Class MergeNode
- java.lang.Object
-
- org.apache.derby.impl.sql.compile.QueryTreeNode
-
- org.apache.derby.impl.sql.compile.StatementNode
-
- org.apache.derby.impl.sql.compile.MergeNode
-
- All Implemented Interfaces:
- Visitable
public final class MergeNode extends StatementNode
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 and Description long[]indexConglomerateNumbersjava.lang.String[]indexNamesIndexRowGenerator[]indicesToMaintainstatic intSOURCE_TABLE_INDEXstatic intTARGET_TABLE_INDEX
-
Constructor Summary
Constructors Constructor and Description MergeNode(org.apache.derby.impl.sql.compile.FromTable targetTable, org.apache.derby.impl.sql.compile.FromTable sourceTable, ValueNode searchCondition, org.apache.derby.impl.sql.compile.QueryTreeNodeVector<MatchingClauseNode> matchingClauses, ContextManager cm)Constructor for a MergeNode.
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method and Description voidbindStatement()Perform the binding operation statement.MethodBuildergenerateCheckConstraints(ValueNode checkConstraints, org.apache.derby.impl.sql.compile.ExpressionClassBuilder ecb)Generate a method to evaluate a tree of CHECK CONSTRAINTS.voidgenerateCheckConstraints(ValueNode checkConstraints, org.apache.derby.impl.sql.compile.ExpressionClassBuilder ecb, MethodBuilder mb)Generate the code to evaluate a tree of CHECK CONSTRAINTS.voidgenerateGenerationClauses(org.apache.derby.impl.sql.compile.ResultColumnList rcl, int resultSetNumber, boolean isUpdate, org.apache.derby.impl.sql.compile.ExpressionClassBuilder ecb, MethodBuilder mb)Generate the code to evaluate all of the generation clauses.booleaninMatchingClause()Returns true if this DMLModStatement a [ NOT ] MATCHED action of a MERGE statementbooleanisAtomic()INSERT/UPDATE/DELETE are always atomic.ConstantActionmakeConstantAction()This creates a class that will do the work that's constant across all Executions of a PreparedStatement.ResultDescriptionmakeResultDescription()Make a ResultDescription for use in a PreparedStatement.voidoptimizeStatement()Generate an optimized QueryTree from a bound QueryTree.ValueNodeparseCheckConstraint(java.lang.String checkConstraintText, TableDescriptor td)Parse a check constraint and turn it into a query tree.ValueNodeparseGenerationClause(java.lang.String clauseText, TableDescriptor td)Parse the generation clause for a column.booleanreferencesSessionSchema()Return true if the node references SESSION schema tables (temporary or permanent)-
Methods inherited from class org.apache.derby.impl.sql.compile.StatementNode
executeSchemaName, executeStatementName, generate, getCursorInfo, getSPSName, needsSavepoint, toString, updateIndexStatisticsFor
-
Methods inherited from class org.apache.derby.impl.sql.compile.QueryTreeNode
accept, addTag, bindOffsetFetch, bindRowMultiSet, bindUserCatalogType, bindUserType, checkReliability, checkReliability, createTypeDependency, getBeginOffset, getDataDictionary, getEndOffset, getExecutionFactory, getGenericConstantActionFactory, getOffsetOrderedNodes, getOptimizerFactory, getOptimizerTracer, getParameterTypes, getUDTDesc, makeTableName, makeTableName, optimizerTracingIsOn, orReliability, setBeginOffset, setEndOffset, taggedWith, treePrint
-
-
-
-
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
-
indicesToMaintain
public IndexRowGenerator[] indicesToMaintain
-
indexConglomerateNumbers
public long[] indexConglomerateNumbers
-
indexNames
public java.lang.String[] indexNames
-
-
Constructor Detail
-
MergeNode
public MergeNode(org.apache.derby.impl.sql.compile.FromTable targetTable, org.apache.derby.impl.sql.compile.FromTable sourceTable, ValueNode searchCondition, org.apache.derby.impl.sql.compile.QueryTreeNodeVector<MatchingClauseNode> matchingClauses, ContextManager cm) throws StandardExceptionConstructor for a MergeNode.
- Throws:
StandardException
-
-
Method Detail
-
bindStatement
public void bindStatement() throws StandardExceptionDescription copied from class:StatementNodePerform 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:
bindStatementin classStatementNode- Throws:
StandardException- Thrown on error
-
referencesSessionSchema
public boolean referencesSessionSchema() throws StandardExceptionDescription copied from class:QueryTreeNodeReturn true if the node references SESSION schema tables (temporary or permanent)- Overrides:
referencesSessionSchemain classQueryTreeNode- Returns:
- true if references SESSION schema tables, else false
- Throws:
StandardException- Thrown on error
-
optimizeStatement
public void optimizeStatement() throws StandardExceptionGenerate 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.- Throws:
StandardException- Thrown on failure
-
makeConstantAction
public ConstantAction makeConstantAction() throws StandardException
Description copied from class:QueryTreeNodeThis 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:
makeConstantActionin classQueryTreeNode- Throws:
StandardException- Thrown on failure
-
inMatchingClause
public boolean inMatchingClause()
Returns true if this DMLModStatement a [ NOT ] MATCHED action of a MERGE statement
-
isAtomic
public boolean isAtomic()
INSERT/UPDATE/DELETE are always atomic.- Returns:
- true
-
parseGenerationClause
public ValueNode parseGenerationClause(java.lang.String clauseText, TableDescriptor td) throws StandardException
Parse the generation clause for a column.- Parameters:
clauseText- Text of the generation clause- Returns:
- The parsed expression as a query tree.
- Throws:
StandardException- Thrown on failure
-
parseCheckConstraint
public ValueNode parseCheckConstraint(java.lang.String checkConstraintText, TableDescriptor td) throws StandardException
Parse a check constraint and turn it into a query tree.- Parameters:
checkConstraintText- Text of CHECK CONSTRAINT.td- The TableDescriptor for the table the the constraint is on.- Returns:
- The parsed check constraint as a query tree.
- Throws:
StandardException- Thrown on failure
-
generateCheckConstraints
public void generateCheckConstraints(ValueNode checkConstraints, org.apache.derby.impl.sql.compile.ExpressionClassBuilder ecb, MethodBuilder mb) throws StandardException
Generate the code to evaluate a tree of CHECK CONSTRAINTS.- Parameters:
checkConstraints- Bound query tree of ANDed check constraints.ecb- Expression Class Builder- Throws:
StandardException- Thrown on error
-
generateCheckConstraints
public MethodBuilder generateCheckConstraints(ValueNode checkConstraints, org.apache.derby.impl.sql.compile.ExpressionClassBuilder ecb) throws StandardException
Generate a method to evaluate a tree of CHECK CONSTRAINTS.- Parameters:
checkConstraints- Bound query tree of ANDed check constraints.ecb- Expression Class Builder- Throws:
StandardException- Thrown on error
-
generateGenerationClauses
public void generateGenerationClauses(org.apache.derby.impl.sql.compile.ResultColumnList rcl, int resultSetNumber, boolean isUpdate, org.apache.derby.impl.sql.compile.ExpressionClassBuilder ecb, MethodBuilder mb) throws StandardExceptionGenerate the code to evaluate all of the generation clauses. If there are generation clauses, this routine builds an Activation method which evaluates the generation clauses and fills in the computed columns.- Parameters:
rcl- describes the row of expressions to be put into the bas tableresultSetNumber- index of base table into array of ResultSetsisUpdate- true if this is for an UPDATE statementecb- code generation state variablemb- the method being generated- Throws:
StandardException- Thrown on error
-
makeResultDescription
public ResultDescription makeResultDescription()
Make a ResultDescription for use in a PreparedStatement. ResultDescriptions are visible to JDBC only for cursor statements. For other types of statements, they are only used internally to get descriptions of the base tables being affected. For example, for an INSERT statement, the ResultDescription describes the rows in the table being inserted into, which is useful when the values being inserted are of a different type or length than the columns in the base table.- Overrides:
makeResultDescriptionin classStatementNode- Returns:
- A ResultDescription for this DML statement
-
-
DataMelt 3.0 © DataMelt by jWork.ORG