/** * INTERNAL: Returns the first field from each of the owned tables, used for fine-grained * pessimistic locking. */ protected Vector getForUpdateOfFields() { Vector allFields = getFields(); int expected = getTableAliases().size(); Vector firstFields = new Vector(expected); DatabaseTable lastTable = null; DatabaseField field = null; int i = 0; // The following loop takes O(n*m) time. n=# of fields. m=#tables. // However, in the m=1 case this will take one pass only. // Also assuming that fields are generally sorted by table, this will // take O(n) time. // An even faster way may be to go getDescriptor().getAdditionalPrimaryKeyFields. while ((i < allFields.size()) && (firstFields.size() < expected)) { field = (DatabaseField) allFields.elementAt(i++); if ((lastTable == null) || !field.getTable().equals(lastTable)) { lastTable = field.getTable(); int j = 0; while (j < firstFields.size()) { if (lastTable.equals(((DatabaseField) firstFields.elementAt(j)).getTable())) { break; } j++; } if (j == firstFields.size()) { firstFields.addElement(field); } } } return firstFields; }
/** INTERNAL: Print SQL onto the stream, using the ExpressionPrinter for context */ public void printSQL(ExpressionSQLPrinter printer) { if (isAttribute()) { printer.printField(getAliasedField()); } // If the mapping is a direct collection then this falls into a gray area. // It must be treated as an attribute at this moment for it has a direct field. // However it is not an attribute in the sense that it also represents a foreign // reference and a mapping criteria has been added. // For bug 2900974 these are now handled as non-attributes during normalize but // as attributes when printing SQL. // if ((!isAttribute()) && (getMapping() != null) && getMapping().isDirectCollectionMapping()) { DirectCollectionMapping directCollectionMapping = (DirectCollectionMapping) getMapping(); // The aliased table comes for free as it was a required part of the join criteria. TableExpression table = (TableExpression) getTable(directCollectionMapping.getReferenceTable()); DatabaseTable aliasedTable = table.aliasForTable(table.getTable()); DatabaseField aliasedField = (DatabaseField) directCollectionMapping.getDirectField().clone(); aliasedField.setTable(aliasedTable); printer.printField(aliasedField); } if ((getMapping() != null) && getMapping().isNestedTableMapping()) { DatabaseTable tableAlias = aliasForTable(new NestedTable(this)); printer.printString(tableAlias.getName()); } }
/** * INTERNAL: This methods clones all the fields and ensures that each collection refers to the * same clones. */ @Override public Object clone() { VariableOneToOneMapping clone = (VariableOneToOneMapping) super.clone(); Map setOfKeys = new HashMap(getSourceToTargetQueryKeyNames().size()); Map sourceToTarget = new HashMap(getSourceToTargetQueryKeyNames().size()); Vector foreignKeys = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance( getForeignKeyFields().size()); if (getTypeField() != null) { clone.setTypeField((DatabaseField) this.getTypeField().clone()); } for (Iterator enumtr = getSourceToTargetQueryKeyNames().keySet().iterator(); enumtr.hasNext(); ) { // Clone the SourceKeyFields DatabaseField field = (DatabaseField) enumtr.next(); DatabaseField clonedField = (DatabaseField) field.clone(); setOfKeys.put(field, clonedField); // on the next line I'm cloning the query key names sourceToTarget.put(clonedField, getSourceToTargetQueryKeyNames().get(field)); } for (Enumeration enumtr = getForeignKeyFields().elements(); enumtr.hasMoreElements(); ) { DatabaseField field = (DatabaseField) enumtr.nextElement(); foreignKeys.addElement(setOfKeys.get(field)); } clone.setSourceToTargetQueryKeyFields(sourceToTarget); clone.setForeignKeyFields(foreignKeys); clone.setTypeIndicatorTranslation(new HashMap(this.getTypeIndicatorTranslation())); return clone; }
/** Append the string containing the SQL insert string for the given table. */ protected SQLCall buildCallWithoutReturning(AbstractSession session) { SQLCall call = new SQLCall(); call.returnNothing(); Writer writer = new CharArrayWriter(200); try { writer.write("INSERT "); if (getHintString() != null) { writer.write(getHintString()); writer.write(" "); } writer.write("INTO "); writer.write(getTable().getQualifiedNameDelimited(session.getPlatform())); writer.write(" ("); Vector fieldsForTable = new Vector(); for (Enumeration fieldsEnum = getModifyRow().keys(); fieldsEnum.hasMoreElements(); ) { DatabaseField field = (DatabaseField) fieldsEnum.nextElement(); if (field.getTable().equals(getTable()) || (!field.hasTableName())) { fieldsForTable.addElement(field); } } if (fieldsForTable.isEmpty()) { throw QueryException.objectToInsertIsEmpty(getTable()); } for (int i = 0; i < fieldsForTable.size(); i++) { writer.write( ((DatabaseField) fieldsForTable.elementAt(i)).getNameDelimited(session.getPlatform())); if ((i + 1) < fieldsForTable.size()) { writer.write(", "); } } writer.write(") VALUES ("); for (int i = 0; i < fieldsForTable.size(); i++) { DatabaseField field = (DatabaseField) fieldsForTable.elementAt(i); call.appendModify(writer, field); if ((i + 1) < fieldsForTable.size()) { writer.write(", "); } } writer.write(")"); call.setSQLString(writer.toString()); } catch (IOException exception) { throw ValidationException.fileError(exception); } return call; }
/** * INTERNAL: Return the classification for the field contained in the mapping. This is used to * convert the row value to a consistent java value. */ @Override public Class getFieldClassification(DatabaseField fieldToClassify) { if ((getTypeField() != null) && (fieldToClassify.equals(getTypeField()))) { return getTypeField().getType(); } String queryKey = (String) getSourceToTargetQueryKeyNames().get(fieldToClassify); if (queryKey == null) { return null; } // Search any of the implementor descriptors for a mapping for the query-key. Iterator iterator = getReferenceDescriptor().getInterfacePolicy().getChildDescriptors().iterator(); if (iterator.hasNext()) { ClassDescriptor firstChild = (ClassDescriptor) iterator.next(); DatabaseMapping mapping = firstChild.getObjectBuilder().getMappingForAttributeName(queryKey); if ((mapping != null) && (mapping.isDirectToFieldMapping())) { return ((AbstractDirectMapping) mapping).getAttributeClassification(); } QueryKey targetQueryKey = firstChild.getQueryKeyNamed(queryKey); if ((targetQueryKey != null) && (targetQueryKey.isDirectQueryKey())) { return firstChild .getObjectBuilder() .getFieldClassification(((DirectQueryKey) targetQueryKey).getField()); } } return null; }
/** INTERNAL: Alias the database field for our current environment */ protected void initializeAliasedField() { DatabaseField tempField = (DatabaseField) getField().clone(); DatabaseTable aliasedTable = getAliasedTable(); // Put in a special check here so that if the aliasing does nothing we don't cache the // result because it's invalid. This saves us from caching premature data if e.g. debugging // causes us to print too early" // if (aliasedTable.equals(getField().getTable())) { // return; // } else { aliasedField = tempField; aliasedField.setTable(aliasedTable); // } }
/** * INTERNAL: Build and return the nested rows from the specified field value. This method allows * the field value to be an ARRAY containing other structures such as arrays or Struct, or direct * values. */ public static Object buildContainerFromArray( Array fieldValue, ObjectRelationalDatabaseField arrayField, AbstractSession session) throws DatabaseException { if (arrayField.getType() == null) { return fieldValue; } Object[] objects = null; try { objects = (Object[]) fieldValue.getArray(); } catch (java.sql.SQLException ex) { throw DatabaseException.sqlException(ex, session, false); } if (objects == null) { return null; } boolean isNestedStructure = false; ObjectRelationalDataTypeDescriptor ord = null; DatabaseField nestedType = null; if (arrayField != null) { nestedType = arrayField.getNestedTypeField(); if ((nestedType != null) && nestedType.getSqlType() == Types.STRUCT) { ClassDescriptor descriptor = session.getDescriptor(nestedType.getType()); if ((descriptor != null) && (descriptor.isObjectRelationalDataTypeDescriptor())) { // this is used to convert non-null objects passed through stored procedures and custom // SQL to structs ord = (ObjectRelationalDataTypeDescriptor) descriptor; } } else if ((nestedType != null) && (nestedType instanceof ObjectRelationalDatabaseField)) { isNestedStructure = true; } } // handle ARRAY conversions ReadObjectQuery query = new ReadObjectQuery(); query.setSession(session); ContainerPolicy cp = ContainerPolicy.buildPolicyFor(arrayField.getType()); Object container = cp.containerInstance(objects.length); for (int i = 0; i < objects.length; i++) { Object arrayValue = objects[i]; if (arrayValue == null) { return null; } if (ord != null) { AbstractRecord nestedRow = ord.buildRowFromStructure((Struct) arrayValue); ClassDescriptor descriptor = ord; if (descriptor.hasInheritance()) { Class newElementClass = descriptor.getInheritancePolicy().classFromRow(nestedRow, session); if (!descriptor.getJavaClass().equals(newElementClass)) { descriptor = session.getDescriptor(newElementClass); if (descriptor == null) { descriptor = ord; } } } arrayValue = descriptor.getObjectBuilder().buildNewInstance(); descriptor .getObjectBuilder() .buildAttributesIntoObject(arrayValue, nestedRow, query, null, false); } else if (isNestedStructure && (arrayValue instanceof Array)) { arrayValue = buildContainerFromArray( (Array) arrayValue, (ObjectRelationalDatabaseField) nestedType, session); } cp.addInto(arrayValue, container, session); } return container; }