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:
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().
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 |
dependentTables, fkColArrays, fkColDescriptors, fkIndexConglomNumbers, fkInfo, fkRefActions, fkSchemaNames, fkTableNames, indexConglomerateNumbers, indexNames, indicesToMaintain, isDependentTable, lockMode, matchingClause, relevantCdl, relevantTriggers, resultColumnList, synonymTableName, targetTableDescriptor, targetTableName, targetVTI, triggerInfo
resultSet
AUTOINCREMENT_CREATE_MODIFY, AUTOINCREMENT_CYCLE, AUTOINCREMENT_INC_INDEX, AUTOINCREMENT_IS_AUTOINCREMENT_INDEX, AUTOINCREMENT_START_INDEX
EMPTY_TD_LIST, NEED_CURSOR_ACTIVATION, NEED_DDL_ACTIVATION, NEED_NOTHING_ACTIVATION, NEED_PARAM_ACTIVATION, NEED_ROW_ACTIVATION
Constructor | Description |
---|---|
MergeNode(FromTable targetTable,
FromTable sourceTable,
ValueNode searchCondition,
QueryTreeNodeVector<MatchingClauseNode> matchingClauses,
ContextManager cm) |
Constructor for a MergeNode.
|
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 columns
|
private 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 FromList
|
private 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 clause
|
private FromTable |
cloneFromTable(FromTable fromTable) |
Clone a FromTable to avoid binding the original
|
private 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 synonym
|
private 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 expression
|
private java.util.List<ColumnReference> |
getColumnReferences(QueryTreeNode expression) |
Get a list of column references in an expression
|
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
|
private 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 FromTable
|
private 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 statement
|
ConstantAction |
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 JOIN
|
private void |
notBaseTable() |
Throw a "not base table" exception
|
void |
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
|
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
activationKind, bind, bindExpressions, bindExpressionsWithTables, bindResultSetsWithTables, bindTables, generateParameterValueSet, getPrivType, getResultSetNode, makeResultDescription
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
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
executeSchemaName, executeStatementName, generate, getCursorInfo, getSPSName, lockTableForCompilation, needsSavepoint, toString, updateIndexStatisticsFor
public static final int SOURCE_TABLE_INDEX
public static final int TARGET_TABLE_INDEX
private static final java.lang.String TARGET_ROW_LOCATION_NAME
private FromBaseTable _targetTable
private FromTable _sourceTable
private ValueNode _searchCondition
private QueryTreeNodeVector<MatchingClauseNode> _matchingClauses
private ResultColumnList _selectList
private FromList _leftJoinFromList
private HalfOuterJoinNode _hojn
private ConstantAction _constantAction
private CursorNode _leftJoinCursor
public MergeNode(FromTable targetTable, FromTable sourceTable, ValueNode searchCondition, QueryTreeNodeVector<MatchingClauseNode> matchingClauses, ContextManager cm) throws StandardException
Constructor for a MergeNode.
StandardException
FromBaseTable getTargetTable()
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.
StandardException
void bindExpression(ValueNode value, FromList fromList) throws StandardException
StandardException
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.
StandardException
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.
StandardException
public void bindStatement() throws StandardException
StatementNode
bindStatement
in class StatementNode
StandardException
- Thrown on errorstatic void checkNoAggregates(QueryTreeNode clause) throws StandardException
StandardException
private java.lang.String getExposedName(FromTable ft) throws StandardException
StandardException
public boolean referencesSessionSchema() throws StandardException
QueryTreeNode
referencesSessionSchema
in class QueryTreeNode
StandardException
- Thrown on errorprivate 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;
StandardException
private void forbidSynonyms() throws StandardException
StandardException
private void forbidSynonyms(TableName tableName) throws StandardException
StandardException
private void notBaseTable() throws StandardException
StandardException
private boolean targetIsBaseTable(FromBaseTable targetTable) throws StandardException
StandardException
private boolean sourceIsBase_or_VTI() throws StandardException
StandardException
private void bindLeftJoin(DataDictionary dd) throws StandardException
StandardException
private FromList cloneFromList(DataDictionary dd, FromBaseTable targetTable) throws StandardException
StandardException
private FromTable cloneFromTable(FromTable fromTable) throws StandardException
StandardException
private void addOnClausePrivileges() throws StandardException
Add the privileges required by the ON clause.
StandardException
private void addColumnPrivilege(ColumnReference cr) throws StandardException
Add SELECT privilege on the indicated column.
StandardException
private void addRoutinePrivilege(StaticMethodCallNode routine) throws StandardException
Add EXECUTE privilege on the indicated routine.
StandardException
private java.util.List<CastNode> getCastNodes(QueryTreeNode expression) throws StandardException
StandardException
private java.util.List<StaticMethodCallNode> getRoutineReferences(QueryTreeNode expression) throws StandardException
StandardException
private ResultColumnList buildSelectList() throws StandardException
StandardException
private void addTargetRowLocation(ResultColumnList selectList) throws StandardException
StandardException
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.
StandardException
private java.lang.String[] getColumns(int mergeTableID, java.util.HashMap<java.lang.String,ColumnReference> map)
private java.util.List<ColumnReference> getColumnReferences(QueryTreeNode expression) throws StandardException
StandardException
private void getColumnsFromList(java.util.HashMap<java.lang.String,ColumnReference> map, java.util.List<ColumnReference> colRefs, int mergeTableID) throws StandardException
StandardException
void addColumn(java.util.HashMap<java.lang.String,ColumnReference> map, ColumnReference cr, int mergeTableID) throws StandardException
StandardException
private java.lang.String makeDCMKey(java.lang.String tableName, java.lang.String columnName)
public void optimizeStatement() throws StandardException
DMLModStatementNode
optimizeStatement
in class DMLModStatementNode
StandardException
- Thrown on failurevoid generate(ActivationClassBuilder acb, MethodBuilder mb) throws StandardException
QueryTreeNode
generate
in class QueryTreeNode
acb
- The ActivationClassBuilder for the class being builtmb
- The method for the generated code to go intoStandardException
- Thrown on errorpublic ConstantAction makeConstantAction() throws StandardException
QueryTreeNode
makeConstantAction
in class QueryTreeNode
StandardException
- Thrown on failurevoid acceptChildren(Visitor v) throws StandardException
acceptChildren
in class DMLModStatementNode
v
- the visitorStandardException
- on errorvoid printSubNodes(int depth)
printSubNodes
in class DMLModStatementNode
depth
- The depth of this node in the treejava.lang.String statementToString()
statementToString
in class DMLModStatementNode
Apache Derby V10.14 Internals - Copyright © 2004,2018 The Apache Software Foundation. All Rights Reserved.