Class CalcRelSplitter
- java.lang.Object
-
- org.apache.calcite.rel.rules.CalcRelSplitter
-
- Direct Known Subclasses:
ProjectToWindowRule.WindowedAggRelSplitter
public abstract class CalcRelSplitter extends java.lang.Object
CalcRelSplitter operates on aCalc
with multipleRexCall
sub-expressions that cannot all be implemented by a single concreteRelNode
.For example, the Java and Fennel calculator do not implement an identical set of operators. The Calc can be used to split a single Calc with mixed Java- and Fennel-only operators into a tree of Calc object that can each be individually implemented by either Java or Fennel.and splits it into several Calc instances.
Currently the splitter is only capable of handling two "rel types". That is, it can deal with Java vs. Fennel Calcs, but not Java vs. Fennel vs. some other type of Calc.
See
ProjectToWindowRule
for an example of how this class is used.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description private static class
CalcRelSplitter.CannotImplement
Control exception forCalcRelSplitter.ImplementTester
.private static class
CalcRelSplitter.HighestUsageFinder
Builds an array of the highest level which contains an expression which uses each expression as an input.private static class
CalcRelSplitter.ImplementTester
Visitor which returns whether an expression can be implemented in a given type of relational expression.private static class
CalcRelSplitter.InputToCommonExprConverter
Shuttle which converts every reference to an input field in an expression to a reference to a common sub-expression.private static class
CalcRelSplitter.MaxInputFinder
Finds the highest level used by any of the inputs of a given expression.static class
CalcRelSplitter.RelType
Type of relational expression.
-
Field Summary
Fields Modifier and Type Field Description private RelNode
child
private RelOptCluster
cluster
protected RexProgram
program
protected RelBuilder
relBuilder
private CalcRelSplitter.RelType[]
relTypes
private static org.slf4j.Logger
RULE_LOGGER
private RelTraitSet
traits
private RelDataTypeFactory
typeFactory
-
Constructor Summary
Constructors Constructor Description CalcRelSplitter(Calc calc, RelBuilder relBuilder, CalcRelSplitter.RelType[] relTypes)
Constructs a CalcRelSplitter.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description protected boolean
canImplement(LogicalCalc rel, java.lang.String relTypeName)
Returns whether a relational expression can be implemented solely in a givenCalcRelSplitter.RelType
.private int
chooseLevels(RexNode[] exprs, int conditionOrdinal, int[] exprLevels, int[] levelTypeOrdinals)
Figures out which expressions to calculate at which level.private java.util.List<java.lang.Integer>
computeTopologicalOrdering(RexNode[] exprs, java.util.List<java.util.Set<java.lang.Integer>> cohorts)
Computes the order in which to visit expressions, so that we decide the level of an expression only after the levels of lower expressions have been decided.private static int
count(boolean[] booleans)
Returns the number of bits set in an array.private RexProgram
createProgramForLevel(int level, int levelCount, RelDataType inputRowType, RexNode[] allExprs, int[] exprLevels, int[] inputExprOrdinals, int[] projectExprOrdinals, int conditionExprOrdinal, RelDataType outputRowType)
Creates a program containing the expressions for a given level.private java.lang.String
deriveFieldName(RexNode expr, int ordinal)
(package private) RelNode
execute()
private static java.util.Set<java.lang.Integer>
findCohort(java.util.List<java.util.Set<java.lang.Integer>> cohorts, int ordinal)
Finds the cohort that contains the given integer, or returns null.private static int
firstSet(boolean[] booleans)
Returns the index of the first set bit in an array.protected java.util.List<java.util.Set<java.lang.Integer>>
getCohorts()
Returns a list of sets of expressions that should be on the same level.protected RelNode
handle(RelNode rel)
Opportunity to further refine the relational expression created for a given level.private int[]
identityArray(int length)
private static int
indexOf(int value, int[] map)
Searches for a value in a map, and returns the position where it was found, or -1.private void
traceLevelExpressions(RexNode[] exprs, int[] exprLevels, int[] levelTypeOrdinals, int levelCount)
Traces the given array of level expression lists at the finer level.
-
-
-
Field Detail
-
RULE_LOGGER
private static final org.slf4j.Logger RULE_LOGGER
-
program
protected final RexProgram program
-
typeFactory
private final RelDataTypeFactory typeFactory
-
relTypes
private final CalcRelSplitter.RelType[] relTypes
-
cluster
private final RelOptCluster cluster
-
traits
private final RelTraitSet traits
-
child
private final RelNode child
-
relBuilder
protected final RelBuilder relBuilder
-
-
Constructor Detail
-
CalcRelSplitter
CalcRelSplitter(Calc calc, RelBuilder relBuilder, CalcRelSplitter.RelType[] relTypes)
Constructs a CalcRelSplitter.- Parameters:
calc
- Calc to splitrelTypes
- Array of rel types, e.g. {Java, Fennel}. Must be distinct.
-
-
Method Detail
-
execute
RelNode execute()
-
handle
protected RelNode handle(RelNode rel)
Opportunity to further refine the relational expression created for a given level. The default implementation returns the relational expression unchanged.
-
chooseLevels
private int chooseLevels(RexNode[] exprs, int conditionOrdinal, int[] exprLevels, int[] levelTypeOrdinals)
Figures out which expressions to calculate at which level.- Parameters:
exprs
- Array of expressionsconditionOrdinal
- Ordinal of the condition expression, or -1 if no conditionexprLevels
- Level ordinal for each expression (output)levelTypeOrdinals
- The type of each level (output)- Returns:
- Number of levels required
-
computeTopologicalOrdering
private java.util.List<java.lang.Integer> computeTopologicalOrdering(RexNode[] exprs, java.util.List<java.util.Set<java.lang.Integer>> cohorts)
Computes the order in which to visit expressions, so that we decide the level of an expression only after the levels of lower expressions have been decided.First, we need to ensure that an expression is visited after all of its inputs.
Further, if the expression is a member of a cohort, we need to visit it after the inputs of all other expressions in that cohort. With this condition, expressions in the same cohort will very likely end up in the same level.
Note that if there are no cohorts, the expressions from the
RexProgram
are already in a suitable order. We perform the topological sort just to ensure that the code path is well-trodden.- Parameters:
exprs
- Expressionscohorts
- List of cohorts, each of which is a set of expr ordinals- Returns:
- Expression ordinals in topological order
-
findCohort
private static java.util.Set<java.lang.Integer> findCohort(java.util.List<java.util.Set<java.lang.Integer>> cohorts, int ordinal)
Finds the cohort that contains the given integer, or returns null.- Parameters:
cohorts
- List of cohorts, each a set of integersordinal
- Integer to search for- Returns:
- Cohort that contains the integer, or null if not found
-
identityArray
private int[] identityArray(int length)
-
createProgramForLevel
private RexProgram createProgramForLevel(int level, int levelCount, RelDataType inputRowType, RexNode[] allExprs, int[] exprLevels, int[] inputExprOrdinals, int[] projectExprOrdinals, int conditionExprOrdinal, RelDataType outputRowType)
Creates a program containing the expressions for a given level.The expression list of the program will consist of all entries in the expression list
allExprs[i]
for which the corresponding level ordinalexprLevels[i]
is equal tolevel
. Expressions are mapped according toinputExprOrdinals
.- Parameters:
level
- Level ordinallevelCount
- Number of levelsinputRowType
- Input row typeallExprs
- Array of all expressionsexprLevels
- Array of the level ordinal of each expressioninputExprOrdinals
- Ordinals in the expression list of input expressions. Input expressioni
will be found at positioninputExprOrdinals[i]
.projectExprOrdinals
- Ordinals of the expressions to be output this level.conditionExprOrdinal
- Ordinal of the expression to form the condition for this level, or -1 if there is no condition.outputRowType
- Output row type- Returns:
- Relational expression
-
deriveFieldName
private java.lang.String deriveFieldName(RexNode expr, int ordinal)
-
traceLevelExpressions
private void traceLevelExpressions(RexNode[] exprs, int[] exprLevels, int[] levelTypeOrdinals, int levelCount)
Traces the given array of level expression lists at the finer level.- Parameters:
exprs
- Array expressionsexprLevels
- For each expression, the ordinal of its levellevelTypeOrdinals
- For each level, the ordinal of its type in therelTypes
arraylevelCount
- The number of levels
-
count
private static int count(boolean[] booleans)
Returns the number of bits set in an array.
-
firstSet
private static int firstSet(boolean[] booleans)
Returns the index of the first set bit in an array.
-
indexOf
private static int indexOf(int value, int[] map)
Searches for a value in a map, and returns the position where it was found, or -1.- Parameters:
value
- Value to search formap
- Map to search in- Returns:
- Ordinal of value in map, or -1 if not found
-
canImplement
protected boolean canImplement(LogicalCalc rel, java.lang.String relTypeName)
Returns whether a relational expression can be implemented solely in a givenCalcRelSplitter.RelType
.- Parameters:
rel
- Calculation relational expressionrelTypeName
- Name of aCalcRelSplitter.RelType
- Returns:
- Whether relational expression can be implemented
-
getCohorts
protected java.util.List<java.util.Set<java.lang.Integer>> getCohorts()
Returns a list of sets of expressions that should be on the same level.For example, if this method returns { {3, 5}, {4, 7} }, it means that expressions 3 and 5, should be on the same level, and expressions 4 and 7 should be on the same level. The two cohorts do not need to be on the same level.
The list is best effort. If it is not possible to arrange that the expressions in a cohort are on the same level, the
execute()
method will still succeed.The default implementation of this method returns the empty list; expressions will be put on the most suitable level. This is generally the lowest possible level, except for literals, which are placed at the level where they are used.
- Returns:
- List of cohorts, that is sets of expressions, that the splitting algorithm should attempt to place on the same level
-
-