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 and Description |
|---|---|
| private ConstantAction | |
| private HalfOuterJoinNode | |
| private CursorNode | |
| private FromList | |
| private QueryTreeNodeVector | |
| private ValueNode | |
| private ResultColumnList | |
| private FromTable | |
| private FromBaseTable | |
| public static final int | |
| private static final String | |
| public static final int |
| Access | Constructor and Description |
|---|---|
| public | MergeNode(FromTable targetTable, FromTable sourceTable, ValueNode searchCondition, QueryTreeNodeVector<MatchingClauseNode> matchingClauses, ContextManager cm)
Constructor for a MergeNode. |
| Modifier and Type | Method and Description |
|---|---|
| pack-priv void | acceptChildren(Visitor
the visitor v)Overrides org. Accept the visitor for all visitable children of this node. |
| pack-priv void | addColumn(HashMap<String, ColumnReference> map, ColumnReference cr, int mergeTableID)
Add a column to the evolving map of referenced columns |
| private void | |
| private void | addColumns(FromTable fromTable, HashMap<String, ColumnReference> drivingColumnMap, ResultColumnList selectList, int mergeTableID)
Add to an evolving select list the columns from the indicated table. |
| private void | |
| private void | |
| private void | addTargetRowLocation(ResultColumnList selectList)
Add the target table's row location to the left join's select list |
| pack-priv void | associateColumn(FromList fromList, ColumnReference cr, int mergeTableID)
Associate a column with the SOURCE or TARGET table. |
| pack-priv void | bindExpression(ValueNode value, FromList fromList)
Boilerplate for binding an expression against a FromList |
| private void | |
| public void | bindStatement()
Overrides org. Perform the binding operation statement. |
| private ResultColumnList | |
| pack-priv static void | |
| private FromList | cloneFromList(DataDictionary dd, FromBaseTable targetTable)
Create a FromList for binding a WHEN [ NOT ] MATCHED clause |
| private FromTable | |
| private void | forbidDerivedColumnLists()
Because of name resolution complexities, we do not allow derived column lists on source or target tables. |
| private void | |
| private void | |
| pack-priv void | generate(ActivationClassBuilder
The ActivationClassBuilder for the class being built acb, MethodBuilder The method for the generated code to go into mb)Overrides org. Do the code generation for this node. |
| private List | |
| private List | |
| private String[] | getColumns(int mergeTableID, HashMap<String, ColumnReference> map)
Get the column names from the table with the given table number, in sorted order |
| pack-priv void | getColumnsFromList(HashMap<String, ColumnReference> map, ResultColumnList rcl, int mergeTableID)
Add a list of columns to the the evolving map. |
| private void | getColumnsFromList(HashMap<String, ColumnReference> map, List<ColumnReference> colRefs, int mergeTableID)
Add a list of columns to the the evolving map |
| pack-priv void | getColumnsInExpression(HashMap<String, ColumnReference> map, ValueNode expression, int mergeTableID)
Add the columns in the matchingRefinement clause to the evolving map. |
| private String | |
| private List | |
| pack-priv FromBaseTable | |
| public ConstantAction | makeConstantAction()
Overrides org. This creates a class that will do the work that's constant across all Executions of a PreparedStatement. |
| private String | makeDCMKey(String tableName, String columnName)
Make a HashMap key for a column in the driving column map of the LEFT JOIN |
| private void | |
| public void | optimizeStatement()
Overrides org. Generate an optimized QueryTree from a bound QueryTree. |
| pack-priv void | printSubNodes(int
The depth of this node in the tree depth)Overrides org. Prints the sub-nodes of this object. |
| public boolean | referencesSessionSchema()
Overrides org. Return true if the node references SESSION schema tables (temporary or permanent) |
| private boolean | |
| pack-priv String | |
| private boolean |
| _constantAction | back to summary |
|---|---|
| private ConstantAction _constantAction | |
| _hojn | back to summary |
|---|---|
| private HalfOuterJoinNode _hojn | |
| _leftJoinCursor | back to summary |
|---|---|
| private CursorNode _leftJoinCursor | |
| _leftJoinFromList | back to summary |
|---|---|
| private FromList _leftJoinFromList | |
| _matchingClauses | back to summary |
|---|---|
| private QueryTreeNodeVector<MatchingClauseNode> _matchingClauses | |
| _searchCondition | back to summary |
|---|---|
| private ValueNode _searchCondition | |
| _selectList | back to summary |
|---|---|
| private ResultColumnList _selectList | |
| _sourceTable | back to summary |
|---|---|
| private FromTable _sourceTable | |
| _targetTable | back to summary |
|---|---|
| private FromBaseTable _targetTable | |
| SOURCE_TABLE_INDEX | back to summary |
|---|---|
| public static final int SOURCE_TABLE_INDEX | |
| TARGET_ROW_LOCATION_NAME | back to summary |
|---|---|
| private static final String TARGET_ROW_LOCATION_NAME | |
| TARGET_TABLE_INDEX | back to summary |
|---|---|
| public static final int TARGET_TABLE_INDEX | |
| MergeNode | back to summary |
|---|---|
| public MergeNode(FromTable targetTable, FromTable sourceTable, ValueNode searchCondition, QueryTreeNodeVector<MatchingClauseNode> matchingClauses, ContextManager cm) throws StandardException Constructor for a MergeNode. | |
| acceptChildren | back to summary |
|---|---|
| pack-priv void acceptChildren(Visitor v) throws StandardException Overrides org. Accept the visitor for all visitable children of this node.
| |
| addColumn | back to summary |
|---|---|
| pack-priv void addColumn(HashMap<String, ColumnReference> map, ColumnReference cr, int mergeTableID) throws StandardException Add a column to the evolving map of referenced columns | |
| addColumnPrivilege | back to summary |
|---|---|
| private void addColumnPrivilege(ColumnReference cr) throws StandardException Add SELECT privilege on the indicated column. | |
| addColumns | back to summary |
|---|---|
| private void addColumns(FromTable fromTable, HashMap<String, ColumnReference> drivingColumnMap, ResultColumnList selectList, int mergeTableID) throws StandardException Add to an evolving select list the columns from the indicated table. | |
| addOnClausePrivileges | back to summary |
|---|---|
| private void addOnClausePrivileges() throws StandardException Add the privileges required by the ON clause. | |
| addRoutinePrivilege | back to summary |
|---|---|
| private void addRoutinePrivilege(StaticMethodCallNode routine) throws StandardException Add EXECUTE privilege on the indicated routine. | |
| addTargetRowLocation | back to summary |
|---|---|
| private void addTargetRowLocation(ResultColumnList selectList) throws StandardException Add the target table's row location to the left join's select list | |
| associateColumn | back to summary |
|---|---|
| pack-priv 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. | |
| bindExpression | back to summary |
|---|---|
| pack-priv void bindExpression(ValueNode value, FromList fromList) throws StandardException Boilerplate for binding an expression against a FromList | |
| bindLeftJoin | back to summary |
|---|---|
| private void bindLeftJoin(DataDictionary dd) throws StandardException Bind the driving left join select. Stuffs the left join SelectNode into the resultSet variable. | |
| bindStatement | back to summary |
|---|---|
| public void bindStatement() throws StandardException Overrides org. Doc from org. 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".
| |
| buildSelectList | back to summary |
|---|---|
| private ResultColumnList buildSelectList() throws StandardException Build the select list for the left join | |
| checkNoAggregates | back to summary |
|---|---|
| pack-priv static void checkNoAggregates(QueryTreeNode clause) throws StandardException | |
| cloneFromList | back to summary |
|---|---|
| private FromList cloneFromList(DataDictionary dd, FromBaseTable targetTable) throws StandardException Create a FromList for binding a WHEN [ NOT ] MATCHED clause | |
| cloneFromTable | back to summary |
|---|---|
| private FromTable cloneFromTable(FromTable fromTable) throws StandardException Clone a FromTable to avoid binding the original | |
| forbidDerivedColumnLists | back to summary |
|---|---|
| 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; | |
| forbidSynonyms | back to summary |
|---|---|
| private void forbidSynonyms() throws StandardException Neither the source nor the target table may be a synonym | |
| forbidSynonyms | back to summary |
|---|---|
| private void forbidSynonyms(TableName tableName) throws StandardException | |
| generate | back to summary |
|---|---|
| pack-priv void generate(ActivationClassBuilder acb, MethodBuilder mb) throws StandardException Overrides org. Doc from org. Do the code generation for this node. This is a place-holder method - it should be over-ridden in the sub-classes.
| |
| getCastNodes | back to summary |
|---|---|
| private List Get a list of CastNodes in an expression | |
| getColumnReferences | back to summary |
|---|---|
| private List Get a list of column references in an expression | |
| getColumns | back to summary |
|---|---|
| private String[] getColumns(int mergeTableID, HashMap<String, ColumnReference> map) Get the column names from the table with the given table number, in sorted order | |
| getColumnsFromList | back to summary |
|---|---|
| pack-priv void getColumnsFromList(HashMap<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. | |
| getColumnsFromList | back to summary |
|---|---|
| private void getColumnsFromList(HashMap<String, ColumnReference> map, List<ColumnReference> colRefs, int mergeTableID) throws StandardException Add a list of columns to the the evolving map | |
| getColumnsInExpression | back to summary |
|---|---|
| pack-priv void getColumnsInExpression(HashMap<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. | |
| getExposedName | back to summary |
|---|---|
| private String getExposedName(FromTable ft) throws StandardException Get the exposed name of a FromTable | |
| getRoutineReferences | back to summary |
|---|---|
| private List Get a list of routines in an expression | |
| getTargetTable | back to summary |
|---|---|
| pack-priv FromBaseTable getTargetTable() Get the target table for the MERGE statement | |
| makeConstantAction | back to summary |
|---|---|
| public ConstantAction makeConstantAction() throws StandardException Overrides org. Doc from org. 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.
| |
| makeDCMKey | back to summary |
|---|---|
| private String makeDCMKey(String tableName, String columnName) Make a HashMap key for a column in the driving column map of the LEFT JOIN | |
| notBaseTable | back to summary |
|---|---|
| private void notBaseTable() throws StandardException Throw a "not base table" exception | |
| optimizeStatement | back to summary |
|---|---|
| public void optimizeStatement() throws StandardException Overrides org. Doc from org. 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.
| |
| printSubNodes | back to summary |
|---|---|
| pack-priv void printSubNodes(int depth) Overrides org. Prints the sub-nodes of this object. See QueryTreeNode.java for how tree printing is supposed to work.
| |
| referencesSessionSchema | back to summary |
|---|---|
| public boolean referencesSessionSchema() throws StandardException Overrides org. Doc from org. Return true if the node references SESSION schema tables (temporary or permanent)
| |
| sourceIsBase_or_VTI | back to summary |
|---|---|
| private boolean sourceIsBase_or_VTI() throws StandardException Return true if the source table is a base table, view, or table function | |
| statementToString | back to summary |
|---|---|
| pack-priv String statementToString() Overrides org.
| |
| targetIsBaseTable | back to summary |
|---|---|
| private boolean targetIsBaseTable(FromBaseTable targetTable) throws StandardException Return true if the target table is a base table | |