com.lucidera.lcs
Class LcsTableMergeRule

java.lang.Object
  extended by org.eigenbase.relopt.RelOptRule
      extended by com.lucidera.lcs.LcsTableMergeRule

public class LcsTableMergeRule
extends RelOptRule

LcsTableMergeRule is a rule for converting an abstract TableModificationRel into a corresponding LcsTableMergeRel.

Version:
$Id: //open/dev/farrago/src/com/lucidera/lcs/LcsTableMergeRule.java#21 $
Author:
Zelaine Fong

Field Summary
private static double COLUMN_UPDATE_THRESHOLD
          The upper bound on the percentage of columns that must be updated for the replace column optimization to be used
static LcsTableMergeRule instance
           
private static double ROW_UPDATE_THRESHOLD
          The lower bound on the percentage of rows that must be updated for the replace column optimization to be used.
private static Logger tracer
           
 
Fields inherited from class org.eigenbase.relopt.RelOptRule
ANY, description, operands
 
Constructor Summary
private LcsTableMergeRule()
          Creates a LcsTableMergeRule.
 
Method Summary
private  List<FemLocalIndex> checkSingleColClusters(List<String> updateCols, LcsTable table, FarragoRepos repos)
          Determines if each of the columns from a list of columns being updated all belong to clusters containing only a single column.
private  boolean checkUniqueJoinKeys(JoinRel joinRel)
          Determines if the join keys corresponding to the source for the MERGE are unique.
private  RelNode createChangeFilterRel(ProjectRel origProj, RelDataTypeField[] targetFields, List<String> updateList, boolean updateOnly, RexNode ridExpr, RexBuilder rexBuilder, int nInsertFields)
          Creates the filter expression used to detect changed rows.
private  RelNode createInsertSource(ProjectRel origProj, RelDataTypeField[] targetFields, RexNode ridExpr, RexBuilder rexBuilder)
          Creates a RelNode that serves as the source for an insert-only MERGE.
private  void createNullFilter(RexBuilder rexBuilder, RexNode expr, List<RexNode> filterList)
          Creates an is null expression on an expression and adds it to a list of filters
private  RelNode createUpdateSource(ProjectRel origProj, RelDataTypeField[] targetFields, List<String> updateList, boolean updateOnly, boolean replaceColumns, RexNode ridExpr, RexBuilder rexBuilder)
          Creates the source RelNode for a MERGE that contains an UPDATE component.
 CallingConvention getOutConvention()
          Returns the calling convention of the result of firing this rule, null if not known.
 void onMatch(RelOptRuleCall call)
          Receives notification about a rule match.
(package private)  List<FemLocalIndex> shouldReplaceColumns(LcsTable target, JoinRel source, List<String> updateCols, boolean updateOnly)
          Determines whether the merge should be executed by replacing the columns being updated, as opposed to updating individual rows.
 
Methods inherited from class org.eigenbase.relopt.RelOptRule
convert, equals, equals, getOperand, getOperands, getOutTrait, hashCode, matches, mergeTraitsAndConvert, mergeTraitsAndConvert, toString
 
Methods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, wait, wait, wait
 

Field Detail

tracer

private static final Logger tracer

COLUMN_UPDATE_THRESHOLD

private static final double COLUMN_UPDATE_THRESHOLD
The upper bound on the percentage of columns that must be updated for the replace column optimization to be used

See Also:
Constant Field Values

ROW_UPDATE_THRESHOLD

private static final double ROW_UPDATE_THRESHOLD
The lower bound on the percentage of rows that must be updated for the replace column optimization to be used. Note that this percentage will be multiplied by the percentage of columns updated by the statement, so the threshold is lower when fewer columns are updated.

See Also:
Constant Field Values

instance

public static final LcsTableMergeRule instance
Constructor Detail

LcsTableMergeRule

private LcsTableMergeRule()
Creates a LcsTableMergeRule.

Method Detail

getOutConvention

public CallingConvention getOutConvention()
Description copied from class: RelOptRule
Returns the calling convention of the result of firing this rule, null if not known.

Overrides:
getOutConvention in class RelOptRule

onMatch

public void onMatch(RelOptRuleCall call)
Description copied from class: RelOptRule
Receives notification about a rule match. At the time that this method is called, call.rels holds the set of relational expressions which match the operands to the rule; call.rels[0] is the root expression.

Typically a rule would check that the nodes are valid matches, creates a new expression, then calls back RelOptRuleCall.transformTo(org.eigenbase.rel.RelNode) to register the expression.

Specified by:
onMatch in class RelOptRule
Parameters:
call - Rule call
See Also:
RelOptRule.matches(RelOptRuleCall)

shouldReplaceColumns

List<FemLocalIndex> shouldReplaceColumns(LcsTable target,
                                         JoinRel source,
                                         List<String> updateCols,
                                         boolean updateOnly)
Determines whether the merge should be executed by replacing the columns being updated, as opposed to updating individual rows. This is only feasible if:
  1. The underlying personality supports snapshots.
  2. The merge statement only contains an update substatement.
  3. The columns being updated all correspond to single column clusters.
  4. The keys in the ON condition are unique.
  5. The number of columns being updated is less than some threshold.
  6. The percentage of rows being updated is greater than a threshold that also depends on the percentage of columns updated.

Parameters:
target - the target table
source - the source for the merge
updateCols - list of columns being updated
updateOnly - true if the statement only contains an update substatement
Returns:
list of clusters corresponding to the columns being updated if the criteria are met; otherwise, null

checkUniqueJoinKeys

private boolean checkUniqueJoinKeys(JoinRel joinRel)
Determines if the join keys corresponding to the source for the MERGE are unique. Rid expressions are considered to be unique keys.

Parameters:
joinRel - the join
Returns:
true if the join keys are unique

checkSingleColClusters

private List<FemLocalIndex> checkSingleColClusters(List<String> updateCols,
                                                   LcsTable table,
                                                   FarragoRepos repos)
Determines if each of the columns from a list of columns being updated all belong to clusters containing only a single column.

Parameters:
updateCols - the list of columns being updated
table - the target table
repos - repository
Returns:
the clusters corresponding to the columns being updated in an order matching the update columns, provided the columns are all part of single-column clusters; otherwise, null is returned

createInsertSource

private RelNode createInsertSource(ProjectRel origProj,
                                   RelDataTypeField[] targetFields,
                                   RexNode ridExpr,
                                   RexBuilder rexBuilder)
Creates a RelNode that serves as the source for an insert-only MERGE. A FilterRel is inserted underneath the current ProjectRel. The filter removes rids that are non-null.

Parameters:
origProj - original projection
targetFields - fields from the target table
ridExpr - expression representing the target rid column
rexBuilder - rex builder
Returns:
RelNode corresponding to the source for the insert-only MERGE

createUpdateSource

private RelNode createUpdateSource(ProjectRel origProj,
                                   RelDataTypeField[] targetFields,
                                   List<String> updateList,
                                   boolean updateOnly,
                                   boolean replaceColumns,
                                   RexNode ridExpr,
                                   RexBuilder rexBuilder)
Creates the source RelNode for a MERGE that contains an UPDATE component. The current ProjectRel is replaced by a FilterRel underneath a new ProjectRel. The filter removes rows where the columns are not actually updated.

The new projection projects the target rid followed by a set of expressions representing new insert rows, or in the case where columns are being replaced, the replaced column values.

Parameters:
origProj - the original projection being replaced
targetFields - fields from the target table
updateList - list of names corresponding to the update columns
updateOnly - if true, MERGE statement contains no INSERT
replaceColumns - true if the MERGE will be executed by replacing entire columns
ridExpr - expression representing the target rid column
rexBuilder - rex builder
Returns:
source RelNode for a MERGE that contains an UPDATE

createChangeFilterRel

private RelNode createChangeFilterRel(ProjectRel origProj,
                                      RelDataTypeField[] targetFields,
                                      List<String> updateList,
                                      boolean updateOnly,
                                      RexNode ridExpr,
                                      RexBuilder rexBuilder,
                                      int nInsertFields)
Creates the filter expression used to detect changed rows. The expression looks like (ROW(O1, O2, ...) IS DISTINCT FROM ROW(N1, N2, ...)) where the O references are the old values and the N references are the new values. We rely on a custom implementation of the row-wise IS DISTINCT FROM operator in the Java calc to evaluate this efficiently and without exceeding the Java calc limit on method bytecode size. (As opposed to RelOptUtil.isDistinctFrom(org.eigenbase.rex.RexBuilder, org.eigenbase.rex.RexNode, org.eigenbase.rex.RexNode, boolean), which generates a deeply nested tree.)

Parameters:
origProj - the original projection being replaced
targetFields - fields from the target table
updateList - list of names corresponding to the update columns
updateOnly - if true, MERGE statement contains no INSERT
ridExpr - expression representing the target rid column
rexBuilder - rex builder
nInsertFields - number of fields in INSERT portion of UPSERT
Returns:
filter rel

createNullFilter

private void createNullFilter(RexBuilder rexBuilder,
                              RexNode expr,
                              List<RexNode> filterList)
Creates an is null expression on an expression and adds it to a list of filters

Parameters:
rexBuilder - rex builder
expr - expression to create the is null expression on
filterList - list of filters