use of org.eclipse.persistence.internal.expressions.SQLDeleteStatement in project eclipselink by eclipse-ee4j.
the class HistoryPolicy method mappingLogicalDelete.
/**
* INTERNAL:
* Performs a logical delete (update) on the historical schema. Direct
* collections and many to many mappings are maintained through the session
* events.
*/
public void mappingLogicalDelete(ModifyQuery originalQuery, AbstractRecord arguments, AbstractSession session) {
SQLDeleteStatement originalStatement = (SQLDeleteStatement) originalQuery.getSQLStatement();
DataModifyQuery historyQuery = new DataModifyQuery();
SQLUpdateStatement historyStatement = new SQLUpdateStatement();
DatabaseTable histTable = getHistoricalTables().get(0);
historyStatement.setTable(histTable);
Expression whereClause = (Expression) originalStatement.getWhereClause().clone();
DatabaseField endField = getEnd();
whereClause = whereClause.getBuilder().getField(endField).isNull().and(whereClause);
historyStatement.setWhereClause(whereClause);
AbstractRecord modifyRow = new DatabaseRecord();
AbstractRecord translationRow = arguments.clone();
Object time = getCurrentTime(session);
modifyRow.add(getEnd(), time);
translationRow.add(getEnd(), time);
historyStatement.setModifyRow(modifyRow);
historyQuery.setSQLStatement(historyStatement);
historyQuery.setModifyRow(modifyRow);
session.executeQuery(historyQuery, translationRow);
}
use of org.eclipse.persistence.internal.expressions.SQLDeleteStatement in project eclipselink by eclipse-ee4j.
the class DirectCollectionMapping method initializeDeleteQuery.
protected void initializeDeleteQuery(AbstractSession session) {
if (!getDeleteQuery().hasSessionName()) {
getDeleteQuery().setSessionName(session.getName());
}
if (getDeleteQuery().getPartitioningPolicy() == null) {
getDeleteQuery().setPartitioningPolicy(getPartitioningPolicy());
}
if (hasCustomDeleteQuery()) {
return;
}
SQLDeleteStatement statement = new SQLDeleteStatement();
ExpressionBuilder builder = new ExpressionBuilder();
Expression expression = createWhereClauseForDeleteQuery(builder);
statement.setWhereClause(expression);
statement.setTable(getReferenceTable());
getDeleteQuery().setSQLStatement(statement);
}
use of org.eclipse.persistence.internal.expressions.SQLDeleteStatement 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.SQLDeleteStatement in project eclipselink by eclipse-ee4j.
the class ExpressionQueryMechanism method prepareDeleteObject.
/**
* Pre-build the SQL statement from the expression.
*/
@Override
public void prepareDeleteObject() {
ClassDescriptor descriptor = getDescriptor();
if (descriptor.usesFieldLocking() && (getTranslationRow() == null)) {
return;
}
// actual SQL calls are sent they are sent in the reverse of this order.
for (DatabaseTable table : descriptor.getMultipleTableInsertOrder()) {
SQLDeleteStatement deleteStatement = buildDeleteStatement(table);
if (descriptor.getTables().size() > 1) {
getSQLStatements().add(deleteStatement);
} else {
setSQLStatement(deleteStatement);
}
// 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();
if (supportCascadeOnDelete) {
break;
}
}
super.prepareDeleteObject();
}
use of org.eclipse.persistence.internal.expressions.SQLDeleteStatement in project eclipselink by eclipse-ee4j.
the class ExpressionQueryMechanism method buildDeleteStatementForDeleteAllQuery.
/**
* Used by DeleteAllQuery to create DeleteStatement in a simple case
* when selectionCriteria==null.
*/
protected SQLDeleteStatement buildDeleteStatementForDeleteAllQuery(DatabaseTable table, Expression inheritanceExpression) {
SQLDeleteStatement deleteStatement = new SQLDeleteStatement();
if (inheritanceExpression != null) {
deleteStatement.setWhereClause((Expression) inheritanceExpression.clone());
}
deleteStatement.setTable(table);
deleteStatement.setTranslationRow(getTranslationRow());
deleteStatement.setHintString(getQuery().getHintString());
return deleteStatement;
}
Aggregations