Class MergeNode
- java.lang.Object
-
- All Implemented Interfaces:
Visitable
public final class MergeNode extends DMLModStatementNode
A MergeNode represents a MERGE statement. The statement looks like this...
MERGE INTO targetTable USING sourceTable ON searchCondition matchingClause1 ... matchingClauseN
...where each matching clause looks like this...
WHEN MATCHED [ AND matchingRefinement ] THEN DELETE
...or
WHEN MATCHED [ AND matchingRefinement ] THEN UPDATE SET col1 = expr1, ... colM = exprM
...or
WHEN NOT MATCHED [ AND matchingRefinement ] THEN INSERT columnList VALUES valueList
The Derby compiler essentially rewrites this statement into a driving left join followed by a series of DELETE/UPDATE/INSERT actions. The left join looks like this:
SELECT selectList FROM sourceTable LEFT OUTER JOIN targetTable ON searchCondition
The selectList of the driving left join consists of the following:
- All of the columns mentioned in the searchCondition.
- All of the columns mentioned in the matchingRefinement clauses.
- All of the columns mentioned in the SET clauses and the INSERT columnLists and valueLists.
- All additional columns needed for the triggers and foreign keys fired by the DeleteResultSets and UpdateResultSets constructed for the WHEN MATCHED clauses.
- All additional columns needed to build index rows and evaluate generated columns needed by the UpdateResultSets constructed for the WHEN MATCHED...THEN UPDATE clauses.
- A trailing targetTable.RowLocation column.
The driving left join's selectList then looks like this...
sc1, ..., scN, tc1, ..., tcM, targetTable.RowLocation
Where sc1...scN are the columns we need from the source table (in alphabetical order) and tc1...tcM are the columns we need from the target table (in alphabetical order).
The matchingRefinement expressions are bound and generated against the FromList of the driving left join. Dummy DeleteNode, UpdateNode, and InsertNode statements are independently constructed in order to bind and generate the DELETE/UPDATE/INSERT actions.
At execution time, the targetTable.RowLocation column is used to determine whether a given driving row matches. The row matches iff targetTable.RowLocation is not null. The driving row is then assigned to the first DELETE/UPDATE/INSERT action to which it applies. The relevant columns from the driving row are extracted and buffered in a temporary table (the "then" rows) specific to that DELETE/UPDATE/INSERT action. After the driving left join has been processed, the DELETE/UPDATE/INSERT actions are run in order, each taking its corresponding temporary table as its source ResultSet.
Name resolution was a particularly thorny problem. This is because name resolution behaves differently for SELECTs and UPDATEs. In particular, while processing UPDATEs, the compiler throws away name resolution information; this happens as a consequence of work done on DERBY-1043. In the end, I had to invent more name resolution machinery in order to compensate for the differences in the handling of SELECTs and UPDATEs. If we are to allow subqueries in matching refinement clauses and in the values expressions of INSERT and UPDATE actions, then we probably need to remove this special name resolution machinery. And that, in turn, probably means revisiting DERBY-1043.
The special name resolution machinery involves marking source and target column references in order to make it clear which table they belong to. This is done in associateColumn(). The markers are consulted at code-generation time in order to resolve column references when we generate the expressions needed to populate the rows which go into the temporary tables. That resolution happens in MatchingClauseNode.getSelectListOffset().
-
-
Field Summary
Fields Modifier and Type Field Description private ConstantAction
_constantAction
private HalfOuterJoinNode
_hojn
private CursorNode
_leftJoinCursor
private FromList
_leftJoinFromList
private QueryTreeNodeVector<MatchingClauseNode>
_matchingClauses
private ValueNode
_searchCondition
private ResultColumnList
_selectList
private FromTable
_sourceTable
private FromBaseTable
_targetTable
static int
SOURCE_TABLE_INDEX
private static java.lang.String
TARGET_ROW_LOCATION_NAME
static int
TARGET_TABLE_INDEX
-
Fields inherited from class org.apache.derby.impl.sql.compile.DMLModStatementNode
dependentTables, fkColArrays, fkColDescriptors, fkIndexConglomNumbers, fkInfo, fkRefActions, fkSchemaNames, fkTableNames, indexConglomerateNumbers, indexNames, indicesToMaintain, isDependentTable, lockMode, matchingClause, relevantCdl, relevantTriggers, resultColumnList, synonymTableName, targetTableDescriptor, targetTableName, targetVTI, triggerInfo
-
Fields inherited from class org.apache.derby.impl.sql.compile.DMLStatementNode
resultSet
-
Fields inherited from class org.apache.derby.impl.sql.compile.StatementNode
EMPTY_TD_LIST, NEED_CURSOR_ACTIVATION, NEED_DDL_ACTIVATION, NEED_NOTHING_ACTIVATION, NEED_PARAM_ACTIVATION, NEED_ROW_ACTIVATION
-
Fields inherited from class org.apache.derby.impl.sql.compile.QueryTreeNode
AUTOINCREMENT_CREATE_MODIFY, AUTOINCREMENT_CYCLE, AUTOINCREMENT_INC_INDEX, AUTOINCREMENT_IS_AUTOINCREMENT_INDEX, AUTOINCREMENT_START_INDEX
-
-
Constructor Summary
Constructors Constructor Description MergeNode(FromTable targetTable, FromTable sourceTable, ValueNode searchCondition, QueryTreeNodeVector<MatchingClauseNode> matchingClauses, ContextManager cm)
Constructor for a MergeNode.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description (package private) void
acceptChildren(Visitor v)
Accept the visitor for all visitable children of this node.(package private) void
addColumn(java.util.HashMap<java.lang.String,ColumnReference> map, ColumnReference cr, int mergeTableID)
Add a column to the evolving map of referenced columnsprivate void
addColumnPrivilege(ColumnReference cr)
Add SELECT privilege on the indicated column.private void
addColumns(FromTable fromTable, java.util.HashMap<java.lang.String,ColumnReference> drivingColumnMap, ResultColumnList selectList, int mergeTableID)
Add to an evolving select list the columns from the indicated table.private void
addOnClausePrivileges()
Add the privileges required by the ON clause.private void
addRoutinePrivilege(StaticMethodCallNode routine)
Add EXECUTE privilege on the indicated routine.private void
addTargetRowLocation(ResultColumnList selectList)
Add the target table's row location to the left join's select list(package private) void
associateColumn(FromList fromList, ColumnReference cr, int mergeTableID)
Associate a column with the SOURCE or TARGET table.(package private) void
bindExpression(ValueNode value, FromList fromList)
Boilerplate for binding an expression against a FromListprivate void
bindLeftJoin(DataDictionary dd)
Bind the driving left join select.void
bindStatement()
Perform the binding operation statement.private ResultColumnList
buildSelectList()
Build the select list for the left join(package private) static void
checkNoAggregates(QueryTreeNode clause)
private FromList
cloneFromList(DataDictionary dd, FromBaseTable targetTable)
Create a FromList for binding a WHEN [ NOT ] MATCHED clauseprivate FromTable
cloneFromTable(FromTable fromTable)
Clone a FromTable to avoid binding the originalprivate void
forbidDerivedColumnLists()
Because of name resolution complexities, we do not allow derived column lists on source or target tables.private void
forbidSynonyms()
Neither the source nor the target table may be a synonymprivate void
forbidSynonyms(TableName tableName)
(package private) void
generate(ActivationClassBuilder acb, MethodBuilder mb)
Do the code generation for this node.private java.util.List<CastNode>
getCastNodes(QueryTreeNode expression)
Get a list of CastNodes in an expressionprivate java.util.List<ColumnReference>
getColumnReferences(QueryTreeNode expression)
Get a list of column references in an expressionprivate java.lang.String[]
getColumns(int mergeTableID, java.util.HashMap<java.lang.String,ColumnReference> map)
Get the column names from the table with the given table number, in sorted orderprivate void
getColumnsFromList(java.util.HashMap<java.lang.String,ColumnReference> map, java.util.List<ColumnReference> colRefs, int mergeTableID)
Add a list of columns to the the evolving map(package private) void
getColumnsFromList(java.util.HashMap<java.lang.String,ColumnReference> map, ResultColumnList rcl, int mergeTableID)
Add a list of columns to the the evolving map.(package private) void
getColumnsInExpression(java.util.HashMap<java.lang.String,ColumnReference> map, ValueNode expression, int mergeTableID)
Add the columns in the matchingRefinement clause to the evolving map.private java.lang.String
getExposedName(FromTable ft)
Get the exposed name of a FromTableprivate java.util.List<StaticMethodCallNode>
getRoutineReferences(QueryTreeNode expression)
Get a list of routines in an expression(package private) FromBaseTable
getTargetTable()
Get the target table for the MERGE statementConstantAction
makeConstantAction()
This creates a class that will do the work that's constant across all Executions of a PreparedStatement.private java.lang.String
makeDCMKey(java.lang.String tableName, java.lang.String columnName)
Make a HashMap key for a column in the driving column map of the LEFT JOINprivate void
notBaseTable()
Throw a "not base table" exceptionvoid
optimizeStatement()
Generate an optimized QueryTree from a bound QueryTree.(package private) void
printSubNodes(int depth)
Prints the sub-nodes of this object.boolean
referencesSessionSchema()
Return true if the node references SESSION schema tables (temporary or permanent)private boolean
sourceIsBase_or_VTI()
Return true if the source table is a base table, view, or table function(package private) java.lang.String
statementToString()
private boolean
targetIsBaseTable(FromBaseTable targetTable)
Return true if the target table is a base table-
Methods inherited from class org.apache.derby.impl.sql.compile.DMLModStatementNode
adjustDeferredFlag, bindConstraints, bindRowScopedExpression, generateCheckConstraints, generateCheckConstraints, generateCodeForTemporaryTable, generateGenerationClauses, getAffectedIndexes, getAllRelevantConstraints, getAllRelevantTriggers, getCheckConstraints, getFKInfo, getReadColMap, getResultColumnList, getResultColumnList, getSchemaDescriptor, getTriggerInfo, getXAffectedIndexes, hasCheckConstraints, hasGenerationClauses, inMatchingClause, isAtomic, markAffectedIndexes, normalizeSynonymColumns, parseAndBindGenerationClauses, parseCheckConstraint, parseGenerationClause, requiresDeferredProcessing, setRefActionInfo, setTarget, verifyTargetTable
-
Methods inherited from class org.apache.derby.impl.sql.compile.DMLStatementNode
activationKind, bind, bindExpressions, bindExpressionsWithTables, bindResultSetsWithTables, bindTables, generateParameterValueSet, getPrivType, getResultSetNode, makeResultDescription
-
Methods inherited from class org.apache.derby.impl.sql.compile.StatementNode
executeSchemaName, executeStatementName, generate, getCursorInfo, getSPSName, lockTableForCompilation, needsSavepoint, toString, updateIndexStatisticsFor
-
Methods inherited from class org.apache.derby.impl.sql.compile.QueryTreeNode
accept, addTag, addUDTUsagePriv, addUDTUsagePriv, bindOffsetFetch, bindRowMultiSet, bindUserCatalogType, bindUserType, checkReliability, checkReliability, convertDefaultNode, copyTagsFrom, createTypeDependency, debugFlush, debugPrint, disablePrivilegeCollection, formatNodeString, generateAuthorizeCheck, getBeginOffset, getClassFactory, getCompilerContext, getContext, getContextManager, getDataDictionary, getDependencyManager, getEndOffset, getExecutionFactory, getGenericConstantActionFactory, getIntProperty, getLanguageConnectionContext, getLongProperty, getNullNode, getOffsetOrderedNodes, getOptimizerFactory, getOptimizerTracer, getParameterTypes, getSchemaDescriptor, getSchemaDescriptor, getStatementType, getTableDescriptor, getTypeCompiler, getUDTDesc, isPrivilegeCollectionRequired, isSessionSchema, isSessionSchema, makeTableName, makeTableName, nodeHeader, optimizerTracingIsOn, orReliability, parseSearchCondition, parseStatement, printLabel, resolveTableToSynonym, setBeginOffset, setEndOffset, stackPrint, taggedWith, treePrint, treePrint, verifyClassExist
-
-
-
-
Field Detail
-
SOURCE_TABLE_INDEX
public static final int SOURCE_TABLE_INDEX
- See Also:
- Constant Field Values
-
TARGET_TABLE_INDEX
public static final int TARGET_TABLE_INDEX
- See Also:
- Constant Field Values
-
TARGET_ROW_LOCATION_NAME
private static final java.lang.String TARGET_ROW_LOCATION_NAME
- See Also:
- Constant Field Values
-
_targetTable
private FromBaseTable _targetTable
-
_sourceTable
private FromTable _sourceTable
-
_searchCondition
private ValueNode _searchCondition
-
_matchingClauses
private QueryTreeNodeVector<MatchingClauseNode> _matchingClauses
-
_selectList
private ResultColumnList _selectList
-
_leftJoinFromList
private FromList _leftJoinFromList
-
_hojn
private HalfOuterJoinNode _hojn
-
_constantAction
private ConstantAction _constantAction
-
_leftJoinCursor
private CursorNode _leftJoinCursor
-
-
Constructor Detail
-
MergeNode
public MergeNode(FromTable targetTable, FromTable sourceTable, ValueNode searchCondition, QueryTreeNodeVector<MatchingClauseNode> matchingClauses, ContextManager cm) throws StandardException
Constructor for a MergeNode.
- Throws:
StandardException
-
-
Method Detail
-
getTargetTable
FromBaseTable getTargetTable()
Get the target table for the MERGE statement
-
associateColumn
void associateColumn(FromList fromList, ColumnReference cr, int mergeTableID) throws StandardException
Associate a column with the SOURCE or TARGET table. This is part of the special name resolution machinery which smooths over the differences between name resolution for SELECTs and UPDATEs.
- Throws:
StandardException
-
bindExpression
void bindExpression(ValueNode value, FromList fromList) throws StandardException
Boilerplate for binding an expression against a FromList- Throws:
StandardException
-
getColumnsInExpression
void getColumnsInExpression(java.util.HashMap<java.lang.String,ColumnReference> map, ValueNode expression, int mergeTableID) throws StandardException
Add the columns in the matchingRefinement clause to the evolving map. This is called when we're building the SELECT list for the driving left join.
- Throws:
StandardException
-
getColumnsFromList
void getColumnsFromList(java.util.HashMap<java.lang.String,ColumnReference> map, ResultColumnList rcl, int mergeTableID) throws StandardException
Add a list of columns to the the evolving map. This is called when we're building the SELECT list for the driving left join.
- Throws:
StandardException
-
bindStatement
public void bindStatement() throws StandardException
Description copied from class:StatementNode
Perform the binding operation statement. Binding consists of permissions checking, view resolution, datatype resolution, and creation of a dependency list (for determining whether a tree or plan is still up to date). This bindStatement() method does nothing. Each StatementNode type that can appear at the top of a tree can override this method with its own bindStatement() method that does "something".- Overrides:
bindStatement
in classStatementNode
- Throws:
StandardException
- Thrown on error
-
checkNoAggregates
static void checkNoAggregates(QueryTreeNode clause) throws StandardException
- Throws:
StandardException
-
getExposedName
private java.lang.String getExposedName(FromTable ft) throws StandardException
Get the exposed name of a FromTable- Throws:
StandardException
-
referencesSessionSchema
public boolean referencesSessionSchema() throws StandardException
Description copied from class:QueryTreeNode
Return true if the node references SESSION schema tables (temporary or permanent)- Overrides:
referencesSessionSchema
in classQueryTreeNode
- Returns:
- true if references SESSION schema tables, else false
- Throws:
StandardException
- Thrown on error
-
forbidDerivedColumnLists
private void forbidDerivedColumnLists() throws StandardException
Because of name resolution complexities, we do not allow derived column lists on source or target tables. These lists arise in queries like the following:
merge into t1 r( x ) using t2 on r.x = t2.a when matched then delete; merge into t1 using t2 r( x ) on t1.a = r.x when matched then delete;
- Throws:
StandardException
-
forbidSynonyms
private void forbidSynonyms() throws StandardException
Neither the source nor the target table may be a synonym- Throws:
StandardException
-
forbidSynonyms
private void forbidSynonyms(TableName tableName) throws StandardException
- Throws:
StandardException
-
notBaseTable
private void notBaseTable() throws StandardException
Throw a "not base table" exception- Throws:
StandardException
-
targetIsBaseTable
private boolean targetIsBaseTable(FromBaseTable targetTable) throws StandardException
Return true if the target table is a base table- Throws:
StandardException
-
sourceIsBase_or_VTI
private boolean sourceIsBase_or_VTI() throws StandardException
Return true if the source table is a base table, view, or table function- Throws:
StandardException
-
bindLeftJoin
private void bindLeftJoin(DataDictionary dd) throws StandardException
Bind the driving left join select. Stuffs the left join SelectNode into the resultSet variable.- Throws:
StandardException
-
cloneFromList
private FromList cloneFromList(DataDictionary dd, FromBaseTable targetTable) throws StandardException
Create a FromList for binding a WHEN [ NOT ] MATCHED clause- Throws:
StandardException
-
cloneFromTable
private FromTable cloneFromTable(FromTable fromTable) throws StandardException
Clone a FromTable to avoid binding the original- Throws:
StandardException
-
addOnClausePrivileges
private void addOnClausePrivileges() throws StandardException
Add the privileges required by the ON clause.
- Throws:
StandardException
-
addColumnPrivilege
private void addColumnPrivilege(ColumnReference cr) throws StandardException
Add SELECT privilege on the indicated column.
- Throws:
StandardException
-
addRoutinePrivilege
private void addRoutinePrivilege(StaticMethodCallNode routine) throws StandardException
Add EXECUTE privilege on the indicated routine.
- Throws:
StandardException
-
getCastNodes
private java.util.List<CastNode> getCastNodes(QueryTreeNode expression) throws StandardException
Get a list of CastNodes in an expression- Throws:
StandardException
-
getRoutineReferences
private java.util.List<StaticMethodCallNode> getRoutineReferences(QueryTreeNode expression) throws StandardException
Get a list of routines in an expression- Throws:
StandardException
-
buildSelectList
private ResultColumnList buildSelectList() throws StandardException
Build the select list for the left join- Throws:
StandardException
-
addTargetRowLocation
private void addTargetRowLocation(ResultColumnList selectList) throws StandardException
Add the target table's row location to the left join's select list- Throws:
StandardException
-
addColumns
private void addColumns(FromTable fromTable, java.util.HashMap<java.lang.String,ColumnReference> drivingColumnMap, ResultColumnList selectList, int mergeTableID) throws StandardException
Add to an evolving select list the columns from the indicated table.
- Throws:
StandardException
-
getColumns
private java.lang.String[] getColumns(int mergeTableID, java.util.HashMap<java.lang.String,ColumnReference> map)
Get the column names from the table with the given table number, in sorted order
-
getColumnReferences
private java.util.List<ColumnReference> getColumnReferences(QueryTreeNode expression) throws StandardException
Get a list of column references in an expression- Throws:
StandardException
-
getColumnsFromList
private void getColumnsFromList(java.util.HashMap<java.lang.String,ColumnReference> map, java.util.List<ColumnReference> colRefs, int mergeTableID) throws StandardException
Add a list of columns to the the evolving map- Throws:
StandardException
-
addColumn
void addColumn(java.util.HashMap<java.lang.String,ColumnReference> map, ColumnReference cr, int mergeTableID) throws StandardException
Add a column to the evolving map of referenced columns- Throws:
StandardException
-
makeDCMKey
private java.lang.String makeDCMKey(java.lang.String tableName, java.lang.String columnName)
Make a HashMap key for a column in the driving column map of the LEFT JOIN
-
optimizeStatement
public void optimizeStatement() throws StandardException
Description copied from class:DMLModStatementNode
Generate an optimized QueryTree from a bound QueryTree. Actually, it can annotate the tree in place rather than generate a new tree, but this interface allows the root node of the optimized QueryTree to be different from the root node of the bound QueryTree. For non-optimizable statements, this method is a no-op. Throws an exception if the tree is not bound, or if the binding is out of date.- Overrides:
optimizeStatement
in classDMLModStatementNode
- Throws:
StandardException
- Thrown on failure
-
generate
void generate(ActivationClassBuilder acb, MethodBuilder mb) throws StandardException
Description copied from class:QueryTreeNode
Do the code generation for this node. This is a place-holder method - it should be over-ridden in the sub-classes.- Overrides:
generate
in classQueryTreeNode
- Parameters:
acb
- The ActivationClassBuilder for the class being builtmb
- The method for the generated code to go into- Throws:
StandardException
- Thrown on error
-
makeConstantAction
public ConstantAction makeConstantAction() throws StandardException
Description copied from class:QueryTreeNode
This creates a class that will do the work that's constant across all Executions of a PreparedStatement. It's up to our subclasses to override this method if they need to compile constant actions into PreparedStatements.- Overrides:
makeConstantAction
in classQueryTreeNode
- Throws:
StandardException
- Thrown on failure
-
acceptChildren
void acceptChildren(Visitor v) throws StandardException
Accept the visitor for all visitable children of this node.- Overrides:
acceptChildren
in classDMLModStatementNode
- Parameters:
v
- the visitor- Throws:
StandardException
- on error
-
printSubNodes
void printSubNodes(int depth)
Prints the sub-nodes of this object. See QueryTreeNode.java for how tree printing is supposed to work.- Overrides:
printSubNodes
in classDMLModStatementNode
- Parameters:
depth
- The depth of this node in the tree
-
statementToString
java.lang.String statementToString()
- Overrides:
statementToString
in classDMLModStatementNode
-
-