use of org.eclipse.persistence.internal.expressions.SQLSelectStatement in project eclipselink by eclipse-ee4j.
the class ExpressionQueryMechanism method prepareDeleteAll.
/**
* Pre-build the SQL statement from the expression.
*
* NOTE: A similar pattern also used in method buildDeleteAllStatementsForTempTable():
* if you are updating this method consider applying a similar update to that method as well.
*/
protected void prepareDeleteAll(List<DatabaseTable> tablesToIgnore, boolean isWhereClauseRequired) {
List<DatabaseTable> tablesInInsertOrder;
ClassDescriptor descriptor = getDescriptor();
if (tablesToIgnore == null) {
// It's original (not a nested) method call.
tablesInInsertOrder = descriptor.getMultipleTableInsertOrder();
} else {
// It's a nested method call: tableInInsertOrder filled with descriptor's tables (in insert order),
// the tables found in tablesToIgnore are thrown away -
// they have already been taken care of by the caller.
// In Employee example, query with reference class Project gets here
// to handle LPROJECT table; tablesToIgnore contains PROJECT table.
tablesInInsertOrder = new ArrayList(descriptor.getMultipleTableInsertOrder().size());
for (DatabaseTable table : descriptor.getMultipleTableInsertOrder()) {
if (!tablesToIgnore.contains(table)) {
tablesInInsertOrder.add(table);
}
}
}
// cache the flag - used many times
boolean hasInheritance = descriptor.hasInheritance();
if (!tablesInInsertOrder.isEmpty()) {
Expression whereClause = getSelectionCriteria();
if (tablesToIgnore == null) {
// It's original (not a nested) method call.
// Ignore the passed dummy value of isWhereClauseRequired and calculate it here.
// This value will be passed to all other tables.
isWhereClauseRequired = whereClause != null;
if (!isWhereClauseRequired) {
Expression additionalExpression = descriptor.getQueryManager().getAdditionalJoinExpression();
if (additionalExpression != null) {
if (!additionalExpression.equals(descriptor.getQueryManager().getMultipleTableJoinExpression())) {
isWhereClauseRequired = true;
}
}
}
}
SQLCall selectCallForExist = null;
// Most databases support delete cascade constraints by specifying a ON DELETE CASCADE option when defining foreign key constraints.
// However some databases which don't support foreign key constraints cannot use delete cascade constraints.
// Therefore each delete operation should be executed in such a database platform instead of delegating delete cascade constraints.
boolean supportForeignKeyConstraints = getSession().getPlatform().supportsForeignKeyConstraints();
boolean supportCascadeOnDelete = supportForeignKeyConstraints && descriptor.isCascadeOnDeleteSetOnDatabaseOnSecondaryTables();
boolean isSelectCallForNotExistRequired = (tablesToIgnore == null) && (tablesInInsertOrder.size() > 1) && (!supportCascadeOnDelete);
SQLSelectStatement selectStatementForNotExist = null;
SQLCall selectCallForNotExist = null;
// inheritanceExpression is always null in a nested method call.
Expression inheritanceExpression = null;
if (tablesToIgnore == null) {
// It's original (not a nested) method call.
if (hasInheritance) {
if (descriptor.getInheritancePolicy().shouldReadSubclasses()) {
inheritanceExpression = descriptor.getInheritancePolicy().getWithAllSubclassesExpression();
} else {
inheritanceExpression = descriptor.getInheritancePolicy().getOnlyInstancesExpression();
}
}
}
SQLSelectStatement selectStatementForExist = createSQLSelectStatementForModifyAll(whereClause);
// Main Case: Descriptor is mapped to more than one table and/or the query references other tables
boolean isMainCase = selectStatementForExist.requiresAliases();
if (isMainCase) {
if (isWhereClauseRequired) {
if (getExecutionSession().getPlatform().shouldAlwaysUseTempStorageForModifyAll() && tablesToIgnore == null) {
// currently DeleteAll using Oracle anonymous block is not implemented
if (!getExecutionSession().getPlatform().isOracle()) {
prepareDeleteAllUsingTempStorage();
return;
}
}
if (isSelectCallForNotExistRequired) {
selectStatementForNotExist = createSQLSelectStatementForModifyAll(null, null, descriptor, true, false);
selectCallForNotExist = (SQLCall) selectStatementForNotExist.buildCall(getSession());
}
} else {
// whereClause = null
if (getExecutionSession().getPlatform().shouldAlwaysUseTempStorageForModifyAll() && tablesToIgnore == null) {
// currently DeleteAll using Oracle anonymous block is not implemented
if (!getExecutionSession().getPlatform().isOracle()) {
// in this case all generated delete calls will have no where clauses.
if (hasInheritance && !(inheritanceExpression == null && descriptor.getInheritancePolicy().isRootParentDescriptor())) {
prepareDeleteAllUsingTempStorage();
return;
}
}
}
}
} else {
// simple case: Descriptor is mapped to a single table and the query references no other tables.
if (isWhereClauseRequired) {
if (getExecutionSession().getPlatform().shouldAlwaysUseTempStorageForModifyAll() && tablesToIgnore == null) {
// currently DeleteAll using Oracle anonymous block is not implemented
if (!getExecutionSession().getPlatform().isOracle()) {
// if there are derived classes with additional tables - use temporary storage
if (hasInheritance && descriptor.getInheritancePolicy().hasMultipleTableChild()) {
prepareDeleteAllUsingTempStorage();
return;
}
}
}
}
}
// a simpler sql will be created if possible.
if (isWhereClauseRequired) {
selectCallForExist = (SQLCall) selectStatementForExist.buildCall(getSession());
}
if (isMainCase) {
// actual SQL calls are sent they are sent in the reverse of this order.
for (DatabaseTable table : tablesInInsertOrder) {
Collection<DatabaseField> primaryKeyFields = getPrimaryKeyFieldsForTable(table);
SQLDeleteStatement deleteStatement;
// both "EXISTS" and "NOT EXISTS" used for the "intermediate" (not first and not last) tables.
if (!isSelectCallForNotExistRequired) {
// isSelectCallForNotExistRequired == false:
// either tablesToIgnore != null: it's a nested method call.
// Example:
// In Employee example, query with reference class
// Project will get here to handle LPROJECT table
// or tablesInInsertOrder.size() == 1: there is only one table,
// but there is joining to at least one other table (otherwise would've been isMainCase==false).
//
// Note that buildDeleteAllStatement ignores inheritanceExpression if selectCallForExist!=null.
deleteStatement = buildDeleteAllStatement(table, inheritanceExpression, selectCallForExist, selectStatementForExist, null, null, primaryKeyFields);
} else {
// isSelectCallForNotExistRequired==true: original call, multiple tables.
// indicates whether the table is the last in insertion order
boolean isLastTable = table.equals(tablesInInsertOrder.get(tablesInInsertOrder.size() - 1));
if (inheritanceExpression == null) {
if (isLastTable) {
// In Employee example, query with reference class Employee calls this for SALARY table;
deleteStatement = buildDeleteAllStatement(table, null, selectCallForExist, selectStatementForExist, null, null, primaryKeyFields);
} else {
// In Employee example, query with reference class Employee calls this for EMPLOYEE table
deleteStatement = buildDeleteAllStatement(table, null, null, null, selectCallForNotExist, selectStatementForNotExist, primaryKeyFields);
}
} else {
// there is inheritance
if (table.equals(descriptor.getMultipleTableInsertOrder().get(0))) {
// This is the highest table in inheritance hierarchy - the one that contains conditions
// (usually class indicator fields) that defines the class identity.
// inheritanceExpression is for this table (it doesn't reference any other tables).
// In Employee example, query with reference class LargeProject calls this for PROJECT table
deleteStatement = buildDeleteAllStatement(table, inheritanceExpression, null, null, selectCallForNotExist, selectStatementForNotExist, primaryKeyFields);
} else {
ClassDescriptor desc = getHighestDescriptorMappingTable(table);
if (desc == descriptor) {
if (isLastTable) {
// In Employee example, query with reference class LargeProject calls this for LPROJECT table;
deleteStatement = buildDeleteAllStatement(table, null, selectCallForExist, selectStatementForExist, null, null, primaryKeyFields);
} else {
// Class has multiple tables that are not inherited.
// In extended Employee example:
// Employee2 class inherits from Employee and
// mapped to two additional tables: EMPLOYEE2 and SALARY2.
// Query with reference class Employee2 calls this for EMPLOYEE2 table.
deleteStatement = buildDeleteAllStatement(table, null, null, null, selectCallForNotExist, selectStatementForNotExist, primaryKeyFields);
}
} else {
// and be deleted if the inheritance info isn't included.
if (isLastTable && selectCallForExist != null) {
// In extended Employee example:
// Query with reference class VeryVeryLargeProject calls this for VLPROJECT table.
deleteStatement = buildDeleteAllStatement(table, null, selectCallForExist, selectStatementForExist, null, null, primaryKeyFields);
} else {
// In extended Employee example:
// Query with reference class VeryLargeProject calls this for LPROJECT table.
// Note that both EXISTS and NOT EXISTS clauses created.
SQLSelectStatement inheritanceSelectStatementForExist = createSQLSelectStatementForModifyAll(null, inheritanceExpression, desc, true, true);
SQLCall inheritanceSelectCallForExist = (SQLCall) inheritanceSelectStatementForExist.buildCall(getSession());
deleteStatement = buildDeleteAllStatement(table, null, inheritanceSelectCallForExist, inheritanceSelectStatementForExist, selectCallForNotExist, selectStatementForNotExist, primaryKeyFields);
}
}
}
}
}
if (descriptor.getTables().size() > 1) {
getSQLStatements().add(deleteStatement);
} else {
setSQLStatement(deleteStatement);
}
// Only delete from first table if delete is cascaded on the database.
if (supportCascadeOnDelete) {
break;
}
}
} else {
// A simple case:
// there is only one table mapped to the descriptor, and
// selection criteria doesn't reference any other tables
// A simple sql call with no subselect should be built.
// In Employee example, query with reference class:
// Project will build a simple sql call for PROJECT(and will make nested method calls for LargeProject and SmallProject);
// SmallProject will build a simple sql call for PROJECT
setSQLStatement(buildDeleteAllStatement(descriptor.getDefaultTable(), inheritanceExpression, selectCallForExist, selectStatementForExist, null, null, null));
}
if (selectCallForExist == null) {
// To handle the mappings selectCallForExist may be required in this case, too.
if (hasInheritance && (tablesToIgnore != null || inheritanceExpression != null)) {
// The only case NOT to create the call for no whereClause is either no inheritance,
// or it's an original (not a nested) method call and there is no inheritance expression.
// In Employee example:
// query with reference class Project and no where clause for m-to-m mapping generates:
// DELETE FROM EMP_PROJ;
// as opposed to query with reference class SmallProject:
// DELETE FROM EMP_PROJ WHERE EXISTS(SELECT PROJ_ID FROM PROJECT WHERE (PROJ_TYPE = ?) AND PROJ_ID = EMP_PROJ.PROJ_ID).
//
selectCallForExist = (SQLCall) selectStatementForExist.buildCall(getSession());
}
}
// Add statements for ManyToMany and DirectCollection mappings
List<SQLStatement> deleteStatementsForMappings = buildDeleteAllStatementsForMappings(selectCallForExist, selectStatementForExist, tablesToIgnore == null);
if (!deleteStatementsForMappings.isEmpty()) {
if (getSQLStatement() != null) {
getSQLStatements().add(getSQLStatement());
setSQLStatement(null);
}
getSQLStatements().addAll(deleteStatementsForMappings);
}
}
// Indicates whether the descriptor has children using extra tables.
boolean hasChildrenWithExtraTables = hasInheritance && descriptor.getInheritancePolicy().hasChildren() && descriptor.getInheritancePolicy().hasMultipleTableChild();
// TBD: should we ignore subclasses in case descriptor doesn't want us to read them in?
// ** Currently in this code we do ignore.
// ** If it will be decided that we need to handle children in all cases
// ** the following statement should be changed to: boolean shouldHandleChildren = hasChildrenWithExtraTables;
boolean shouldHandleChildren = hasChildrenWithExtraTables && descriptor.getInheritancePolicy().shouldReadSubclasses();
// Perform a nested method call for each child
if (shouldHandleChildren) {
// In Employee example: query for Project will make nested calls to
// LargeProject and SmallProject and ask them to ignore PROJECT table
List<DatabaseTable> tablesToIgnoreForChildren = new ArrayList();
// The tables this descriptor has ignored, its children also should ignore.
if (tablesToIgnore != null) {
tablesToIgnoreForChildren.addAll(tablesToIgnore);
}
// subclasses to process its tables for the second time.
if (descriptor.getInheritancePolicy().shouldReadSubclasses()) {
tablesToIgnoreForChildren.addAll(tablesInInsertOrder);
}
Iterator<ClassDescriptor> it = descriptor.getInheritancePolicy().getChildDescriptors().iterator();
while (it.hasNext()) {
// Define the same query for the child
ClassDescriptor childDescriptor = it.next();
// Most databases support delete cascade constraints by specifying a ON DELETE CASCADE option when defining foreign key constraints.
// However some databases which don't support foreign key constraints cannot use delete cascade constraints.
// Therefore each delete operation should be executed in such a database platform instead of delegating delete cascade constraints.
boolean supportForeignKeyConstraints = getSession().getPlatform().supportsForeignKeyConstraints();
boolean supportCascadeOnDelete = supportForeignKeyConstraints && childDescriptor.isCascadeOnDeleteSetOnDatabaseOnSecondaryTables();
// Need to process only "multiple tables" child descriptors
if (((!supportCascadeOnDelete) && childDescriptor.getTables().size() > descriptor.getTables().size()) || (childDescriptor.getInheritancePolicy().hasMultipleTableChild())) {
DeleteAllQuery childQuery = new DeleteAllQuery();
childQuery.setReferenceClass(childDescriptor.getJavaClass());
childQuery.setSelectionCriteria(getSelectionCriteria());
childQuery.setDescriptor(childDescriptor);
childQuery.setSession(getSession());
ExpressionQueryMechanism childMechanism = (ExpressionQueryMechanism) childQuery.getQueryMechanism();
// nested call
childMechanism.prepareDeleteAll(tablesToIgnoreForChildren, isWhereClauseRequired);
// Copy the statements from child query mechanism.
// In Employee example query for Project will pick up a statement for
// LPROJECT table from LargeProject and nothing from SmallProject.
List<SQLStatement> childStatements = new ArrayList();
if (childMechanism.getCall() != null) {
childStatements.add(childMechanism.getSQLStatement());
} else if (childMechanism.getSQLStatements() != null) {
childStatements.addAll(childMechanism.getSQLStatements());
}
if (!childStatements.isEmpty()) {
if (getSQLStatement() != null) {
getSQLStatements().add(getSQLStatement());
setSQLStatement(null);
}
getSQLStatements().addAll(childStatements);
}
}
}
}
// Nested method call doesn't need to call this.
if (tablesToIgnore == null) {
((DeleteAllQuery) getQuery()).setIsPreparedUsingTempStorage(false);
super.prepareDeleteAll();
}
}
use of org.eclipse.persistence.internal.expressions.SQLSelectStatement in project eclipselink by eclipse-ee4j.
the class ExpressionQueryMechanism method buildNormalSelectStatement.
/**
* Return the appropriate select statement containing the fields in the table.
*/
protected SQLSelectStatement buildNormalSelectStatement() {
// From bug 2612185 Remember the identity hashtable used in cloning the selection criteria even in the normal case
// for performance, in case subqueries need it, or for order by expressions.
// 2612538 - the default size of Map (32) is appropriate
Map clonedExpressions = new IdentityHashMap();
SQLSelectStatement selectStatement = buildBaseSelectStatement(false, clonedExpressions);
ObjectLevelReadQuery query = ((ObjectLevelReadQuery) getQuery());
// Case, normal read for branch inheritance class that reads subclasses all in its own table(s).
boolean includeAllSubclassesFields = true;
if (getDescriptor().hasInheritance()) {
getDescriptor().getInheritancePolicy().appendWithAllSubclassesExpression(selectStatement);
if ((!query.isReportQuery()) && query.shouldOuterJoinSubclasses()) {
selectStatement.getExpressionBuilder().setShouldUseOuterJoinForMultitableInheritance(true);
}
// Bug 380929 - Find whether to include all subclass fields or not.
includeAllSubclassesFields = shouldIncludeAllSubclassFields(selectStatement);
}
selectStatement.setFields(getSelectionFields(selectStatement, includeAllSubclassesFields));
selectStatement.normalize(getSession(), getDescriptor(), clonedExpressions);
// Allow for joining indexes to be computed to ensure distinct rows.
if (((ObjectLevelReadQuery) getQuery()).hasJoining()) {
((ObjectLevelReadQuery) getQuery()).getJoinedAttributeManager().computeJoiningMappingIndexes(true, getSession(), 0);
}
return selectStatement;
}
use of org.eclipse.persistence.internal.expressions.SQLSelectStatement in project eclipselink by eclipse-ee4j.
the class ExpressionQueryMechanism method buildReportQuerySelectStatement.
/**
* Customary inheritance expression is required for DeleteAllQuery and UpdateAllQuery preparation.
* Ability to switch off AdditionalJoinExpression is required for DeleteAllQuery.
*/
protected SQLSelectStatement buildReportQuerySelectStatement(boolean isSubSelect, boolean useCustomaryInheritanceExpression, Expression inheritanceExpression, boolean shouldUseAdditionalJoinExpression) {
ReportQuery reportQuery = (ReportQuery) getQuery();
// For bug 2612185: Need to know which original bases were mapped to which cloned bases.
// For sub-seclets the expressions have already been clones, and identity must be maintained with the outer expression.
Map clonedExpressions = isSubSelect ? null : new IdentityHashMap();
SQLSelectStatement selectStatement = buildBaseSelectStatement(isSubSelect, clonedExpressions, shouldUseAdditionalJoinExpression);
if (reportQuery.hasGroupByExpressions()) {
selectStatement.setGroupByExpressions(cloneExpressions(reportQuery.getGroupByExpressions(), clonedExpressions));
}
if (reportQuery.getHavingExpression() != null) {
selectStatement.setHavingExpression(reportQuery.getHavingExpression().copiedVersionFrom(clonedExpressions));
}
if (getDescriptor().hasInheritance()) {
if (useCustomaryInheritanceExpression) {
if (inheritanceExpression != null) {
if (selectStatement.getWhereClause() == null) {
selectStatement.setWhereClause((Expression) inheritanceExpression.clone());
} else {
selectStatement.setWhereClause(selectStatement.getWhereClause().and(inheritanceExpression));
}
}
} else {
getDescriptor().getInheritancePolicy().appendWithAllSubclassesExpression(selectStatement);
if (reportQuery.shouldOuterJoinSubclasses()) {
selectStatement.getExpressionBuilder().setShouldUseOuterJoinForMultitableInheritance(true);
}
}
}
Vector fieldExpressions = reportQuery.getQueryExpressions();
int itemOffset = fieldExpressions.size();
List<ReportItem> items = reportQuery.getItems();
computeFieldExpressions(items, clonedExpressions, selectStatement, fieldExpressions);
selectStatement.setFields(fieldExpressions);
if (reportQuery.hasNonFetchJoinedAttributeExpressions()) {
selectStatement.setNonSelectFields(cloneExpressions(reportQuery.getNonFetchJoinAttributeExpressions(), clonedExpressions));
}
// Subselects must be normalized in the context of the parent statement.
if (!isSubSelect) {
selectStatement.normalize(getSession(), getDescriptor(), clonedExpressions);
}
items = reportQuery.getItems();
computeAndSetItemOffset(reportQuery, items, itemOffset);
return selectStatement;
}
use of org.eclipse.persistence.internal.expressions.SQLSelectStatement in project eclipselink by eclipse-ee4j.
the class ExpressionQueryMechanism method createSQLSelectStatementForUpdateAllForOracleAnonymousBlock.
protected SQLSelectStatement createSQLSelectStatementForUpdateAllForOracleAnonymousBlock(HashMap tables_databaseFieldsToValues) {
ExpressionBuilder builder = ((UpdateAllQuery) getQuery()).getExpressionBuilder();
Expression whereClause = getSelectionCriteria();
ReportQuery reportQuery = new ReportQuery(getDescriptor().getJavaClass(), builder);
reportQuery.setDescriptor(getDescriptor());
reportQuery.setSelectionCriteria(whereClause);
reportQuery.setSession(getSession());
reportQuery.setShouldRetrievePrimaryKeys(true);
Iterator itDatabaseFieldsToValues = tables_databaseFieldsToValues.values().iterator();
while (itDatabaseFieldsToValues.hasNext()) {
HashMap databaseFieldsToValues = (HashMap) itDatabaseFieldsToValues.next();
Iterator itValues = databaseFieldsToValues.values().iterator();
while (itValues.hasNext()) {
reportQuery.addAttribute("", (Expression) itValues.next());
}
}
SQLSelectStatement selectStatement = ((ExpressionQueryMechanism) reportQuery.getQueryMechanism()).buildReportQuerySelectStatement(false);
reportQuery.setSession(null);
return selectStatement;
}
use of org.eclipse.persistence.internal.expressions.SQLSelectStatement in project eclipselink by eclipse-ee4j.
the class ExpressionQueryMechanism method createSQLSelectStatementForAssignedExpressionForUpdateAll.
protected SQLSelectStatement createSQLSelectStatementForAssignedExpressionForUpdateAll(Expression value) {
ReportQuery reportQuery = new ReportQuery(getQuery().getReferenceClass(), value.getBuilder());
reportQuery.setDescriptor(getQuery().getDescriptor());
reportQuery.setSession(getSession());
reportQuery.addAttribute("", value);
SQLSelectStatement selectStatement = ((ExpressionQueryMechanism) reportQuery.getQueryMechanism()).buildReportQuerySelectStatement(false);
reportQuery.setSession(null);
return selectStatement;
}
Aggregations