Top Description Fields Constructors Methods
org.apache.derby.impl.sql.compile

public final Class MergeNode

extends DMLModStatementNode
Class Inheritance
Imports
java.util.Arrays, .ArrayList, .HashMap, .HashSet, .List, org.apache.derby.shared.common.error.StandardException, org.apache.derby.shared.common.reference.ClassName, .SQLState, org.apache.derby.iapi.services.classfile.VMOpcode, org.apache.derby.iapi.services.compiler.MethodBuilder, org.apache.derby.iapi.services.context.ContextManager, org.apache.derby.iapi.sql.compile.CompilerContext, .IgnoreFilter, .Visitor, org.apache.derby.iapi.sql.conn.Authorizer, org.apache.derby.iapi.sql.dictionary.ColumnDescriptor, .DataDictionary, .TableDescriptor, org.apache.derby.iapi.sql.execute.ConstantAction, org.apache.derby.iapi.util.IdUtil, org.apache.derby.shared.common.sanity.SanityManager

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().

Field Summary

Modifier and TypeField and Description
private ConstantAction
private HalfOuterJoinNode
private CursorNode
private FromList
private QueryTreeNodeVector<MatchingClauseNode>
private ValueNode
private ResultColumnList
private FromTable
private FromBaseTable
public static final int
private static final String
public static final int
Inherited from org.apache.derby.impl.sql.compile.DMLModStatementNode:
dependentTablesfkColArraysfkColDescriptorsfkIndexConglomNumbersfkInfofkRefActionsfkSchemaNamesfkTableNamesindexConglomerateNumbersindexNamesindicesToMaintainisDependentTablelockModematchingClauserelevantCdlrelevantTriggersresultColumnListsynonymTableNametargetTableDescriptortargetTableNametargetVTItriggerInfo

Constructor Summary

AccessConstructor and Description
public
MergeNode(FromTable targetTable, FromTable sourceTable, ValueNode searchCondition, QueryTreeNodeVector<MatchingClauseNode> matchingClauses, ContextManager cm)

Constructor for a MergeNode.

Method Summary

Modifier and TypeMethod and Description
pack-priv void
acceptChildren(Visitor
the visitor
v
)

Overrides org.apache.derby.impl.sql.compile.DMLModStatementNode.acceptChildren.

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
addColumnPrivilege(ColumnReference cr)

Add SELECT privilege on the indicated column.

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
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

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
bindLeftJoin(DataDictionary dd)

Bind the driving left join select.

public void
bindStatement()

Overrides org.apache.derby.impl.sql.compile.StatementNode.bindStatement.

Perform the binding operation statement.

private ResultColumnList
buildSelectList()

Build the select list for the left join

pack-priv static void
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
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.apache.derby.impl.sql.compile.QueryTreeNode.generate.

Do the code generation for this node.

private List<CastNode>
getCastNodes(QueryTreeNode expression)

Get a list of CastNodes in an expression

private List<ColumnReference>
getColumnReferences(QueryTreeNode expression)

Get a list of column references in an expression

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
getExposedName(FromTable ft)

Get the exposed name of a FromTable

private List<StaticMethodCallNode>
getRoutineReferences(QueryTreeNode expression)

Get a list of routines in an expression

pack-priv FromBaseTable
getTargetTable()

Get the target table for the MERGE statement

public ConstantAction
makeConstantAction()

Overrides org.apache.derby.impl.sql.compile.QueryTreeNode.makeConstantAction.

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
notBaseTable()

Throw a "not base table" exception

public void
optimizeStatement()

Overrides org.apache.derby.impl.sql.compile.DMLModStatementNode.optimizeStatement.

Generate an optimized QueryTree from a bound QueryTree.

pack-priv void
printSubNodes(int
The depth of this node in the tree
depth
)

Overrides org.apache.derby.impl.sql.compile.DMLModStatementNode.printSubNodes.

Prints the sub-nodes of this object.

public boolean
referencesSessionSchema()

Overrides org.apache.derby.impl.sql.compile.QueryTreeNode.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

pack-priv String
private boolean
targetIsBaseTable(FromBaseTable targetTable)

Return true if the target table is a base table

Inherited from org.apache.derby.impl.sql.compile.DMLModStatementNode:
adjustDeferredFlagbindConstraintsbindRowScopedExpressiongenerateCheckConstraintsgenerateCheckConstraintsgenerateCodeForTemporaryTablegenerateGenerationClausesgetAffectedIndexesgetAllRelevantConstraintsgetAllRelevantTriggersgetCheckConstraintsgetFKInfogetReadColMapgetResultColumnListgetResultColumnListgetSchemaDescriptorgetTriggerInfogetXAffectedIndexeshasCheckConstraintshasGenerationClausesinMatchingClauseisAtomicmarkAffectedIndexesnormalizeSynonymColumnsparseAndBindGenerationClausesparseCheckConstraintparseGenerationClauserequiresDeferredProcessingsetRefActionInfosetTargetverifyTargetTable

Field Detail

_constantActionback to summary
private ConstantAction _constantAction
_hojnback to summary
private HalfOuterJoinNode _hojn
_leftJoinCursorback to summary
private CursorNode _leftJoinCursor
_leftJoinFromListback to summary
private FromList _leftJoinFromList
_matchingClausesback to summary
private QueryTreeNodeVector<MatchingClauseNode> _matchingClauses
_searchConditionback to summary
private ValueNode _searchCondition
_selectListback to summary
private ResultColumnList _selectList
_sourceTableback to summary
private FromTable _sourceTable
_targetTableback to summary
private FromBaseTable _targetTable
SOURCE_TABLE_INDEXback to summary
public static final int SOURCE_TABLE_INDEX
TARGET_ROW_LOCATION_NAMEback to summary
private static final String TARGET_ROW_LOCATION_NAME
TARGET_TABLE_INDEXback to summary
public static final int TARGET_TABLE_INDEX

Constructor Detail

MergeNodeback to summary
public MergeNode(FromTable targetTable, FromTable sourceTable, ValueNode searchCondition, QueryTreeNodeVector<MatchingClauseNode> matchingClauses, ContextManager cm) throws StandardException

Constructor for a MergeNode.

Method Detail

acceptChildrenback to summary
pack-priv void acceptChildren(Visitor v) throws StandardException

Overrides org.apache.derby.impl.sql.compile.DMLModStatementNode.acceptChildren.

Accept the visitor for all visitable children of this node.

Parameters
v:Visitor

the visitor

Annotations
@Override
Exceptions
StandardException:
on error
addColumnback 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

addColumnPrivilegeback to summary
private void addColumnPrivilege(ColumnReference cr) throws StandardException

Add SELECT privilege on the indicated column.

addColumnsback 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.

addOnClausePrivilegesback to summary
private void addOnClausePrivileges() throws StandardException

Add the privileges required by the ON clause.

addRoutinePrivilegeback to summary
private void addRoutinePrivilege(StaticMethodCallNode routine) throws StandardException

Add EXECUTE privilege on the indicated routine.

addTargetRowLocationback to summary
private void addTargetRowLocation(ResultColumnList selectList) throws StandardException

Add the target table's row location to the left join's select list

associateColumnback 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.

bindExpressionback to summary
pack-priv void bindExpression(ValueNode value, FromList fromList) throws StandardException

Boilerplate for binding an expression against a FromList

bindLeftJoinback to summary
private void bindLeftJoin(DataDictionary dd) throws StandardException

Bind the driving left join select. Stuffs the left join SelectNode into the resultSet variable.

bindStatementback to summary
public void bindStatement() throws StandardException

Overrides org.apache.derby.impl.sql.compile.StatementNode.bindStatement.

Doc from org.apache.derby.impl.sql.compile.StatementNode.bindStatement.

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".

Annotations
@Override
Exceptions
StandardException:
Thrown on error
buildSelectListback to summary
private ResultColumnList buildSelectList() throws StandardException

Build the select list for the left join

checkNoAggregatesback to summary
pack-priv static void checkNoAggregates(QueryTreeNode clause) throws StandardException
cloneFromListback to summary
private FromList cloneFromList(DataDictionary dd, FromBaseTable targetTable) throws StandardException

Create a FromList for binding a WHEN [ NOT ] MATCHED clause

cloneFromTableback to summary
private FromTable cloneFromTable(FromTable fromTable) throws StandardException

Clone a FromTable to avoid binding the original

forbidDerivedColumnListsback 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;
forbidSynonymsback to summary
private void forbidSynonyms() throws StandardException

Neither the source nor the target table may be a synonym

forbidSynonymsback to summary
private void forbidSynonyms(TableName tableName) throws StandardException
generateback to summary
pack-priv void generate(ActivationClassBuilder acb, MethodBuilder mb) throws StandardException

Overrides org.apache.derby.impl.sql.compile.QueryTreeNode.generate.

Doc from org.apache.derby.impl.sql.compile.QueryTreeNode.generate.

Do the code generation for this node. This is a place-holder method - it should be over-ridden in the sub-classes.

Parameters
acb:ActivationClassBuilder

The ActivationClassBuilder for the class being built

mb:MethodBuilder

The method for the generated code to go into

Annotations
@Override
Exceptions
StandardException:
Thrown on error
getCastNodesback to summary
private List<CastNode> getCastNodes(QueryTreeNode expression) throws StandardException

Get a list of CastNodes in an expression

getColumnReferencesback to summary
private List<ColumnReference> getColumnReferences(QueryTreeNode expression) throws StandardException

Get a list of column references in an expression

getColumnsback 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

getColumnsFromListback 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.

getColumnsFromListback 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

getColumnsInExpressionback 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.

getExposedNameback to summary
private String getExposedName(FromTable ft) throws StandardException

Get the exposed name of a FromTable

getRoutineReferencesback to summary
private List<StaticMethodCallNode> getRoutineReferences(QueryTreeNode expression) throws StandardException

Get a list of routines in an expression

getTargetTableback to summary
pack-priv FromBaseTable getTargetTable()

Get the target table for the MERGE statement

makeConstantActionback to summary
public ConstantAction makeConstantAction() throws StandardException

Overrides org.apache.derby.impl.sql.compile.QueryTreeNode.makeConstantAction.

Doc from org.apache.derby.impl.sql.compile.QueryTreeNode.makeConstantAction.

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.

Annotations
@Override
Exceptions
StandardException:
Thrown on failure
makeDCMKeyback 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

notBaseTableback to summary
private void notBaseTable() throws StandardException

Throw a "not base table" exception

optimizeStatementback to summary
public void optimizeStatement() throws StandardException

Overrides org.apache.derby.impl.sql.compile.DMLModStatementNode.optimizeStatement.

Doc from org.apache.derby.impl.sql.compile.DMLModStatementNode.optimizeStatement.

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.

Annotations
@Override
Exceptions
StandardException:
Thrown on failure
printSubNodesback to summary
pack-priv void printSubNodes(int depth)

Overrides org.apache.derby.impl.sql.compile.DMLModStatementNode.printSubNodes.

Prints the sub-nodes of this object. See QueryTreeNode.java for how tree printing is supposed to work.

Parameters
depth:int

The depth of this node in the tree

Annotations
@Override
referencesSessionSchemaback to summary
public boolean referencesSessionSchema() throws StandardException

Overrides org.apache.derby.impl.sql.compile.QueryTreeNode.referencesSessionSchema.

Doc from org.apache.derby.impl.sql.compile.QueryTreeNode.referencesSessionSchema.

Return true if the node references SESSION schema tables (temporary or permanent)

Returns:boolean

true if references SESSION schema tables, else false

Annotations
@Override
Exceptions
StandardException:
Thrown on error
sourceIsBase_or_VTIback to summary
private boolean sourceIsBase_or_VTI() throws StandardException

Return true if the source table is a base table, view, or table function

statementToStringback to summary
pack-priv String statementToString()

Overrides org.apache.derby.impl.sql.compile.DMLModStatementNode.statementToString.

Annotations
@Override
targetIsBaseTableback to summary
private boolean targetIsBaseTable(FromBaseTable targetTable) throws StandardException

Return true if the target table is a base table