use of org.eclipse.persistence.internal.expressions.DataExpression in project eclipselink by eclipse-ee4j.
the class UpdateAllQueryTestHelper method getQualifiedFieldNameFromKey.
protected static String getQualifiedFieldNameFromKey(Object key, Class<?> referenceClass, ClassDescriptor descriptor, Session session) {
DatabaseField field = null;
if (key instanceof String) {
// attribute name
String name = (String) key;
DatabaseMapping mapping = descriptor.getObjectBuilder().getMappingForAttributeName(name);
if (mapping != null) {
field = mapping.getFields().firstElement();
}
} else if (key instanceof DataExpression) {
DataExpression fieldExpression = (DataExpression) key;
field = descriptor.getObjectBuilder().getFieldForQueryKeyName(fieldExpression.getName());
if (field == null) {
DataExpression fieldExpressionClone = (DataExpression) fieldExpression.clone();
fieldExpressionClone.getBuilder().setQueryClass(referenceClass);
fieldExpressionClone.getBuilder().setSession((org.eclipse.persistence.internal.sessions.AbstractSession) session);
field = fieldExpressionClone.getField();
}
}
if (field != null) {
return field.getQualifiedName();
}
// should never happen
return null;
}
use of org.eclipse.persistence.internal.expressions.DataExpression in project eclipselink by eclipse-ee4j.
the class ExpressionQueryMechanism method getAliasTableName.
protected static String getAliasTableName(SQLSelectStatement selectStatement, DatabaseTable table, DatasourcePlatform platform) {
if (!selectStatement.requiresAliases()) {
return null;
}
HashSet aliasTables = new HashSet();
Iterator<Map.Entry<DatabaseTable, DatabaseTable>> itEntries = selectStatement.getTableAliases().entrySet().iterator();
DatabaseTable aliasTable = null;
while (itEntries.hasNext()) {
Map.Entry<DatabaseTable, DatabaseTable> entry = itEntries.next();
if (table.equals(entry.getValue())) {
aliasTable = entry.getKey();
aliasTables.add(aliasTable);
}
}
if (aliasTables.isEmpty()) {
return null;
} else if (aliasTables.size() == 1) {
return aliasTable.getQualifiedNameDelimited(platform);
}
// The table has several aliases,
// remove the aliases that used by DataExpressions
// with baseExpression NOT the expressionBuilder used by the statement
ExpressionIterator expIterator = new ExpressionIterator() {
@Override
public void iterate(Expression each) {
if (each instanceof DataExpression) {
DataExpression dataExpression = (DataExpression) each;
DatabaseField field = dataExpression.getField();
if (field != null) {
if (dataExpression.getBaseExpression() != getStatement().getBuilder()) {
((Collection) getResult()).remove(dataExpression.getAliasedField().getTable());
}
}
}
}
@Override
public boolean shouldIterateOverSubSelects() {
return true;
}
};
expIterator.setStatement(selectStatement);
expIterator.setResult(aliasTables);
expIterator.iterateOn(selectStatement.getWhereClause());
if (aliasTables.size() == 1) {
aliasTable = (DatabaseTable) aliasTables.iterator().next();
return aliasTable.getQualifiedName();
} else if (aliasTables.isEmpty()) {
// should never happen
return aliasTable.getQualifiedName();
} else {
// should never happen
aliasTable = (DatabaseTable) aliasTables.iterator().next();
return aliasTable.getQualifiedName();
}
}
use of org.eclipse.persistence.internal.expressions.DataExpression in project eclipselink by eclipse-ee4j.
the class ExpressionQueryMechanism method prepareUpdateAll.
/**
* Pre-build the SQL statement from the expressions.
*/
@Override
public void prepareUpdateAll() {
ExpressionBuilder builder = ((UpdateAllQuery) getQuery()).getExpressionBuilder();
HashMap updateClauses = ((UpdateAllQuery) getQuery()).getUpdateClauses();
boolean updateClausesHasBeenCloned = false;
// Add a statement to update the optimistic locking field if their is one.
OptimisticLockingPolicy policy = getDescriptor().getOptimisticLockingPolicy();
if (policy != null) {
if (policy.getWriteLockField() != null) {
Expression writeLock = builder.getField(policy.getWriteLockField());
// already targeted for update.
if (!isFieldInUpdate(writeLock, updateClauses)) {
Expression writeLockUpdateExpression = policy.getWriteLockUpdateExpression(builder, getQuery().getSession());
if (writeLockUpdateExpression != null) {
// clone it to keep user's original data intact
updateClauses = (HashMap) updateClauses.clone();
updateClausesHasBeenCloned = true;
updateClauses.put(writeLock, writeLockUpdateExpression);
}
}
}
}
if (getDescriptor().hasSerializedObjectPolicy()) {
if (!updateClausesHasBeenCloned) {
// clone it to keep user's original data intact
updateClauses = (HashMap) updateClauses.clone();
updateClausesHasBeenCloned = true;
}
Expression sopFieldExpression = builder.getField(getDescriptor().getSerializedObjectPolicy().getField());
updateClauses.put(sopFieldExpression, new ConstantExpression(null, sopFieldExpression));
}
HashMap tables_databaseFieldsToValues = new HashMap();
HashMap<DatabaseTable, List<DatabaseField>> tablesToPrimaryKeyFields = new HashMap();
Iterator it = updateClauses.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
Object fieldObject = entry.getKey();
DataExpression fieldExpression = null;
// QueryKeyExpression or FieldExpression of the field
Expression baseExpression = null;
String attributeName = null;
if (fieldObject instanceof String) {
attributeName = (String) fieldObject;
} else {
// it should be either QueryKeyExpression or FieldExpression
fieldExpression = (DataExpression) fieldObject;
}
DatabaseField field = null;
DatabaseMapping mapping = null;
if (attributeName != null) {
mapping = getDescriptor().getObjectBuilder().getMappingForAttributeName(attributeName);
if (mapping != null && !mapping.getFields().isEmpty()) {
field = mapping.getFields().get(0);
}
if (field == null) {
throw QueryException.updateAllQueryAddUpdateDoesNotDefineField(getDescriptor(), getQuery(), attributeName);
}
baseExpression = ((UpdateAllQuery) getQuery()).getExpressionBuilder().get(attributeName);
} else if (fieldExpression != null) {
// it should be either QueryKeyExpression or ExpressionBuilder
if (fieldExpression.getBaseExpression() instanceof ExpressionBuilder) {
field = getDescriptor().getObjectBuilder().getFieldForQueryKeyName(fieldExpression.getName());
}
if (field == null) {
DataExpression fieldExpressionClone = (DataExpression) fieldExpression.clone();
fieldExpressionClone.getBuilder().setQueryClass(getQuery().getReferenceClass());
fieldExpressionClone.getBuilder().setSession(getSession().getRootSession(null));
field = fieldExpressionClone.getField();
if (field == null) {
throw QueryException.updateAllQueryAddUpdateDoesNotDefineField(getDescriptor(), getQuery(), fieldExpression.toString());
}
}
mapping = getDescriptor().getObjectBuilder().getMappingForField(field);
baseExpression = fieldExpression;
}
Object valueObject = entry.getValue();
Vector fields;
Vector values;
Vector baseExpressions;
if (mapping != null && mapping.isOneToOneMapping()) {
fields = mapping.getFields();
int fieldsSize = fields.size();
values = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(fieldsSize);
baseExpressions = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(fieldsSize);
for (int i = 0; i < fieldsSize; i++) {
if (valueObject instanceof ConstantExpression) {
valueObject = ((ConstantExpression) valueObject).getValue();
}
if (valueObject == null) {
values.add(null);
} else {
DatabaseField targetField = ((OneToOneMapping) mapping).getSourceToTargetKeyFields().get(fields.get(i));
if (valueObject instanceof Expression) {
Expression exp = ((Expression) ((Expression) valueObject).clone()).getField(targetField);
if (exp.isParameterExpression()) {
((ParameterExpression) exp).setType(targetField.getType());
}
values.add(exp);
} else {
values.add(mapping.getReferenceDescriptor().getObjectBuilder().extractValueFromObjectForField(valueObject, targetField, getSession()));
}
}
baseExpressions.add(new FieldExpression((DatabaseField) fields.elementAt(i), ((QueryKeyExpression) baseExpression).getBaseExpression()));
}
} else {
fields = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
fields.add(field);
values = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
values.add(valueObject);
baseExpressions = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
baseExpressions.add(baseExpression);
}
int fieldsSize = fields.size();
for (int i = 0; i < fieldsSize; i++) {
field = (DatabaseField) fields.elementAt(i);
DatabaseTable table = field.getTable();
if (!getDescriptor().getTables().contains(table)) {
if (attributeName != null) {
throw QueryException.updateAllQueryAddUpdateDefinesWrongField(getDescriptor(), getQuery(), attributeName, field.getQualifiedName());
} else {
throw QueryException.updateAllQueryAddUpdateDefinesWrongField(getDescriptor(), getQuery(), fieldExpression.toString(), field.getQualifiedName());
}
}
HashMap databaseFieldsToValues = (HashMap) tables_databaseFieldsToValues.get(table);
if (databaseFieldsToValues == null) {
databaseFieldsToValues = new HashMap();
tables_databaseFieldsToValues.put(table, databaseFieldsToValues);
tablesToPrimaryKeyFields.put(table, getPrimaryKeyFieldsForTable(table));
}
Object value = values.elementAt(i);
Expression valueExpression;
if (valueObject instanceof Expression) {
valueExpression = (Expression) value;
} else {
valueExpression = builder.value(value);
}
// NOTE: If baseExpression is FieldExpression, conversion is not required.
if (valueExpression.isValueExpression()) {
valueExpression.setLocalBase((Expression) baseExpressions.elementAt(i));
}
databaseFieldsToValues.put(field, valueExpression);
}
}
SQLCall selectCallForExist = null;
SQLSelectStatement selectStatementForExist = createSQLSelectStatementForModifyAll(getSelectionCriteria());
// Main Case: Descriptor is mapped to more than one table and/or the query references other tables
boolean isMainCase = selectStatementForExist.requiresAliases();
if (isMainCase) {
if (getExecutionSession().getPlatform().shouldAlwaysUseTempStorageForModifyAll()) {
prepareUpdateAllUsingTempStorage(tables_databaseFieldsToValues, tablesToPrimaryKeyFields);
return;
}
}
selectCallForExist = (SQLCall) selectStatementForExist.buildCall(getSession());
// ExpressionIterator to search for valueExpressions that require select statements.
// Those are expressions that
// either reference other tables:
// Employee-based example: valueExp = builder.get("address").get("city");
// or use DataExpressions with base not ExpressionBuilder:
// Employee-base example: valueExp = builder.get("manager").get("firstName");
// Before iterating the table is set into result,
// if expression requiring select is found, then resul set to null.
ExpressionIterator expRequiresSelectIterator = new ExpressionIterator() {
@Override
public void iterate(Expression each) {
if (getResult() == null) {
return;
}
if (each instanceof DataExpression) {
DataExpression dataExpression = (DataExpression) each;
Expression baseExpression = dataExpression.getBaseExpression();
if (baseExpression != null && !(baseExpression instanceof ExpressionBuilder)) {
boolean stop = true;
if (baseExpression instanceof DataExpression) {
DataExpression baseDataExpression = (DataExpression) baseExpression;
if (baseDataExpression.getMapping() != null && baseDataExpression.getMapping().isAggregateObjectMapping()) {
stop = false;
}
}
if (stop) {
setResult(null);
return;
}
}
// Like ....CONCAT('abcd', column)....
if (baseExpression != null && (baseExpression instanceof ExpressionBuilder) && baseExpression.getSession() == null) {
((ExpressionBuilder) baseExpression).setSession(getSession());
}
DatabaseField field = dataExpression.getField();
if (field != null) {
if (!field.getTable().equals((DatabaseTable) getResult())) {
setResult(null);
return;
}
}
}
}
@Override
public boolean shouldIterateOverSubSelects() {
return true;
}
};
HashMap tables_databaseFieldsToValuesCopy = new HashMap();
it = tables_databaseFieldsToValues.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
DatabaseTable table = (DatabaseTable) entry.getKey();
HashMap databaseFieldsToValues = (HashMap) entry.getValue();
HashMap databaseFieldsToValuesCopy = new HashMap();
tables_databaseFieldsToValuesCopy.put(table, databaseFieldsToValuesCopy);
Iterator itFieldsToValues = databaseFieldsToValues.entrySet().iterator();
while (itFieldsToValues.hasNext()) {
Map.Entry entry2 = (Map.Entry) itFieldsToValues.next();
DatabaseField field = (DatabaseField) entry2.getKey();
Expression value = (Expression) entry2.getValue();
// initialize result with the table
expRequiresSelectIterator.setResult(table);
// To find fields have to have session and ref class
Expression valueClone = (Expression) value.clone();
valueClone.getBuilder().setSession(getSession());
valueClone.getBuilder().setQueryClass(getQuery().getReferenceClass());
expRequiresSelectIterator.iterateOn(valueClone);
if (expRequiresSelectIterator.getResult() == null) {
// The corresponding SelectionStatement should be assigned to value
if (getExecutionSession().getPlatform().shouldAlwaysUseTempStorageForModifyAll()) {
prepareUpdateAllUsingTempStorage(tables_databaseFieldsToValues, tablesToPrimaryKeyFields);
return;
}
SQLSelectStatement selStatement = createSQLSelectStatementForAssignedExpressionForUpdateAll(value);
databaseFieldsToValuesCopy.put(field, selStatement);
} else {
databaseFieldsToValuesCopy.put(field, valueClone);
}
}
}
HashMap tables_databaseFieldsToValuesOriginal = tables_databaseFieldsToValues;
tables_databaseFieldsToValues = tables_databaseFieldsToValuesCopy;
if (tables_databaseFieldsToValues.size() == 1) {
Map.Entry entry = (Map.Entry) tables_databaseFieldsToValues.entrySet().iterator().next();
DatabaseTable table = (DatabaseTable) entry.getKey();
HashMap databaseFieldsToValues = (HashMap) entry.getValue();
Collection<DatabaseField> primaryKeyFields = tablesToPrimaryKeyFields.values().iterator().next();
setSQLStatement(buildUpdateAllStatement(table, databaseFieldsToValues, selectCallForExist, selectStatementForExist, primaryKeyFields));
} else {
// To figure out the order of statements we need to find dependencies
// between updating of tables.
// Here's an example:
// All objects with nameA = "Clob" should be changed so that nameA = "Alex" and nameB = "Bob";
// nameA is mapped to A.name and nameB mapped to B.name:
// UPDATE B SET B.name = "Bob" WHERE A.name = "Clob" and A.id = B.id;
// UPDATE A SET A.name = "Alex" WHERE A.name = "Clob" and A.id = B.id;
// The order can't be altered - or there will be no updating of B.
// To formalize that: for each table we'll gather two Collections:
// leftFields - all the table's fields to receive a new value;
// rightFields - all the fields either in assigned or selecton expression.
// A_leftFields = {A.name}; A_rightFields = {A.name}.
// B_leftFields = {B.name}; B_rightFields = {A.name}.
// There are several comparison outcomes:
// 1. A_leftFields doesn't intersect B_rightFields and
// B_leftFields doesn't intersect A_rightFields
// There is no dependency - doesn't matter which update goes first;
// 2. A_leftFields intersects B_rightFields and
// B_leftFields doesn't intersect A_rightFields
// B should be updated before A (the case in the example).
// 3. A_leftFields intersects B_rightFields and
// B_leftFields intersects A_rightFields
// Ordering conflict that can't be resolved without using transitionary storage.
//
// This ExpressionIterator will be used for collecting fields from
// selection criteria and assigned expressions.
ExpressionIterator expIterator = new ExpressionIterator() {
@Override
public void iterate(Expression each) {
if (each instanceof DataExpression) {
DataExpression dataExpression = (DataExpression) each;
DatabaseField field = dataExpression.getField();
if (field != null) {
((Collection) getResult()).add(field);
}
}
}
@Override
public boolean shouldIterateOverSubSelects() {
return true;
}
};
// This will hold collection of fields from selection criteria expression.
HashSet selectCallForExistFields = new HashSet();
if (selectCallForExist != null) {
expIterator.setResult(selectCallForExistFields);
expIterator.iterateOn(selectStatementForExist.getWhereClause());
}
// Left of the assignment operator that is - the fields acquiring new values
HashMap tablesToLeftFields = new HashMap();
// The fields right of the assignment operator AND the fields from whereClause
HashMap tablesToRightFields = new HashMap();
// before and after vectors work together: n-th member of beforeTable should
// be updated before than n-th member of afterTable
Vector beforeTables = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance();
Vector afterTables = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance();
// Both keys and values are tables.
// An entry indicates a timing conflict between the key and the value:
// both key should be updated before value and value before key.
HashMap simpleConflicts = new HashMap();
it = tables_databaseFieldsToValues.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
// for each table to be updated
DatabaseTable table = (DatabaseTable) entry.getKey();
// here's a Map of left hand fields to right hand expressions
HashMap databaseFieldsToValues = (HashMap) entry.getValue();
// This will contain all the left hand fields
HashSet leftFields = new HashSet(databaseFieldsToValues.size());
// This will contain all the left hand fields plus fields form selection criteria
HashSet rightFields = (HashSet) selectCallForExistFields.clone();
expIterator.setResult(rightFields);
Iterator itDatabaseFieldsToValues = databaseFieldsToValues.entrySet().iterator();
while (itDatabaseFieldsToValues.hasNext()) {
// for each left hand - right hand expression pair
Map.Entry databaseFieldValueEntry = (Map.Entry) itDatabaseFieldsToValues.next();
// here's the left hand database field
DatabaseField field = (DatabaseField) databaseFieldValueEntry.getKey();
leftFields.add(field);
// here's the right hand expression
Object value = databaseFieldValueEntry.getValue();
if (value instanceof Expression) {
Expression valueExpression = (Expression) value;
// use iterator to extract all the fields
expIterator.iterateOn(valueExpression);
} else {
// It should be SQLSelectStatement with a single field
SQLSelectStatement selStatement = (SQLSelectStatement) value;
// first one is the normalized value to be assigned
expIterator.iterateOn((Expression) selStatement.getFields().get(0));
// whereClause - generated during normalization
expIterator.iterateOn(selStatement.getWhereClause());
}
}
// now let's compare the table with the already processed tables
Iterator itProcessedTables = tablesToLeftFields.keySet().iterator();
while (itProcessedTables.hasNext()) {
DatabaseTable processedTable = (DatabaseTable) itProcessedTables.next();
HashSet processedTableLeftFields = (HashSet) tablesToLeftFields.get(processedTable);
HashSet processedTableRightFields = (HashSet) tablesToRightFields.get(processedTable);
boolean tableBeforeProcessedTable = false;
Iterator itProcessedTableLeftField = processedTableLeftFields.iterator();
while (itProcessedTableLeftField.hasNext()) {
if (rightFields.contains(itProcessedTableLeftField.next())) {
tableBeforeProcessedTable = true;
break;
}
}
boolean processedTableBeforeTable = false;
Iterator itLeftField = leftFields.iterator();
while (itLeftField.hasNext()) {
if (processedTableRightFields.contains(itLeftField.next())) {
processedTableBeforeTable = true;
break;
}
}
if (tableBeforeProcessedTable && !processedTableBeforeTable) {
// table should be updated before processedTable
beforeTables.add(table);
afterTables.add(processedTable);
} else if (!tableBeforeProcessedTable && processedTableBeforeTable) {
// processedTable should be updated before table
beforeTables.add(processedTable);
afterTables.add(table);
} else if (tableBeforeProcessedTable && processedTableBeforeTable) {
// there is an order conflict between table and processTable
simpleConflicts.put(processedTable, table);
}
}
tablesToLeftFields.put(table, leftFields);
tablesToRightFields.put(table, rightFields);
}
if (!simpleConflicts.isEmpty()) {
prepareUpdateAllUsingTempStorage(tables_databaseFieldsToValuesOriginal, tablesToPrimaryKeyFields);
return;
}
// This will contain tables in update order
Vector orderedTables = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(tables_databaseFieldsToValues.size());
// first process the tables found in beforeTables / afterTables
while (!beforeTables.isEmpty()) {
// Find firstTable - the one that appears in beforeTables, but not afterTables.
// That means there is no requirement to update it after any other table and we
// can put it first in update order. There could be several such tables -
// it doesn't matter which one will be picked.
DatabaseTable firstTable = null;
for (int i = 0; i < beforeTables.size(); i++) {
DatabaseTable beforeTable = (DatabaseTable) beforeTables.elementAt(i);
if (!afterTables.contains(beforeTable)) {
firstTable = beforeTable;
break;
}
}
if (firstTable == null) {
// There is no firstTable - it's an order conflict between three or more tables
prepareUpdateAllUsingTempStorage(tables_databaseFieldsToValuesOriginal, tablesToPrimaryKeyFields);
return;
} else {
// Also remove the corresponding entries from afterTable.
for (int i = beforeTables.size() - 1; i >= 0; i--) {
if (beforeTables.elementAt(i).equals(firstTable)) {
beforeTables.remove(i);
afterTables.remove(i);
}
}
// Add firstTable to orderedTables
orderedTables.addElement(firstTable);
}
}
// now all the remaining ones - there are no dependencies between them
// so the order is arbitrary.
Iterator itTables = tables_databaseFieldsToValues.keySet().iterator();
while (itTables.hasNext()) {
DatabaseTable table = (DatabaseTable) itTables.next();
if (!orderedTables.contains(table)) {
orderedTables.add(table);
}
}
// finally create statements
for (int i = 0; i < orderedTables.size(); i++) {
DatabaseTable table = (DatabaseTable) orderedTables.elementAt(i);
HashMap databaseFieldsToValues = (HashMap) tables_databaseFieldsToValues.get(table);
Collection<DatabaseField> primaryKeyFields = tablesToPrimaryKeyFields.get(table);
getSQLStatements().addElement(buildUpdateAllStatement(table, databaseFieldsToValues, selectCallForExist, selectStatementForExist, primaryKeyFields));
}
}
((UpdateAllQuery) getQuery()).setIsPreparedUsingTempStorage(false);
super.prepareUpdateAll();
}
use of org.eclipse.persistence.internal.expressions.DataExpression in project eclipselink by eclipse-ee4j.
the class ForeignReferenceQueryKey method getRelationTable.
/**
* PUBLIC:
* Returns the relation table.
* Currently only ManyToMany and OneToOne may have relation table.
* The method is overridden to return null for other subclasses.
* The returned relationTable still could be null.
*/
public DatabaseTable getRelationTable(ClassDescriptor referenceDescriptor) {
ExpressionIterator expIterator = new ExpressionIterator() {
@Override
public void iterate(Expression each) {
if (each.isTableExpression()) {
((Collection) this.getResult()).add(((TableExpression) each).getTable());
} else if (each.isDataExpression()) {
DatabaseField field = ((DataExpression) each).getField();
if (field != null && field.hasTableName()) {
((Collection) this.getResult()).add(field.getTable());
}
} else if (each.isParameterExpression()) {
DatabaseField field = ((ParameterExpression) each).getField();
if (field != null && field.hasTableName()) {
((Collection) this.getResult()).add(field.getTable());
}
}
}
};
expIterator.setResult(new HashSet());
expIterator.iterateOn(this.joinCriteria);
HashSet<DatabaseTable> tables = (HashSet) expIterator.getResult();
DatabaseTable relationTable = null;
Iterator<DatabaseTable> it = tables.iterator();
while (it.hasNext()) {
DatabaseTable table = it.next();
// neither source nor reference descriptor contains table - must be relationTable
if (!descriptor.getTables().contains(table) && !referenceDescriptor.getTables().contains(table)) {
relationTable = table;
break;
}
}
return relationTable;
}
Aggregations