Search in sources :

Example 86 with RelOptCluster

use of org.apache.calcite.plan.RelOptCluster in project calcite by apache.

the class ProjectCalcMergeRule method onMatch.

// ~ Methods ----------------------------------------------------------------
public void onMatch(RelOptRuleCall call) {
    final LogicalProject project = call.rel(0);
    final LogicalCalc calc = call.rel(1);
    // Don't merge a project which contains windowed aggregates onto a
    // calc. That would effectively be pushing a windowed aggregate down
    // through a filter. Transform the project into an identical calc,
    // which we'll have chance to merge later, after the over is
    // expanded.
    final RelOptCluster cluster = project.getCluster();
    RexProgram program = RexProgram.create(calc.getRowType(), project.getProjects(), null, project.getRowType(), cluster.getRexBuilder());
    if (RexOver.containsOver(program)) {
        LogicalCalc projectAsCalc = LogicalCalc.create(calc, program);
        call.transformTo(projectAsCalc);
        return;
    }
    // Create a program containing the project node's expressions.
    final RexBuilder rexBuilder = cluster.getRexBuilder();
    final RexProgramBuilder progBuilder = new RexProgramBuilder(calc.getRowType(), rexBuilder);
    for (Pair<RexNode, String> field : project.getNamedProjects()) {
        progBuilder.addProject(field.left, field.right);
    }
    RexProgram topProgram = progBuilder.getProgram();
    RexProgram bottomProgram = calc.getProgram();
    // Merge the programs together.
    RexProgram mergedProgram = RexProgramBuilder.mergePrograms(topProgram, bottomProgram, rexBuilder);
    final LogicalCalc newCalc = LogicalCalc.create(calc.getInput(), mergedProgram);
    call.transformTo(newCalc);
}
Also used : RelOptCluster(org.apache.calcite.plan.RelOptCluster) RexProgram(org.apache.calcite.rex.RexProgram) RexBuilder(org.apache.calcite.rex.RexBuilder) LogicalProject(org.apache.calcite.rel.logical.LogicalProject) LogicalCalc(org.apache.calcite.rel.logical.LogicalCalc) RexProgramBuilder(org.apache.calcite.rex.RexProgramBuilder) RexNode(org.apache.calcite.rex.RexNode)

Example 87 with RelOptCluster

use of org.apache.calcite.plan.RelOptCluster in project calcite by apache.

the class JoinPushThroughJoinRule method onMatchRight.

private void onMatchRight(RelOptRuleCall call) {
    final Join topJoin = call.rel(0);
    final Join bottomJoin = call.rel(1);
    final RelNode relC = call.rel(2);
    final RelNode relA = bottomJoin.getLeft();
    final RelNode relB = bottomJoin.getRight();
    final RelOptCluster cluster = topJoin.getCluster();
    // topJoin
    // /     \
    // bottomJoin  C
    // /    \
    // A      B
    final int aCount = relA.getRowType().getFieldCount();
    final int bCount = relB.getRowType().getFieldCount();
    final int cCount = relC.getRowType().getFieldCount();
    final ImmutableBitSet bBitSet = ImmutableBitSet.range(aCount, aCount + bCount);
    // (Is this too strict?)
    if (topJoin.getJoinType() != JoinRelType.INNER || bottomJoin.getJoinType() != JoinRelType.INNER) {
        return;
    }
    // Split the condition of topJoin into a conjunction. Each of the
    // parts that does not use columns from B can be pushed down.
    final List<RexNode> intersecting = new ArrayList<>();
    final List<RexNode> nonIntersecting = new ArrayList<>();
    split(topJoin.getCondition(), bBitSet, intersecting, nonIntersecting);
    // If there's nothing to push down, it's not worth proceeding.
    if (nonIntersecting.isEmpty()) {
        return;
    }
    // Split the condition of bottomJoin into a conjunction. Each of the
    // parts that use columns from B will need to be pulled up.
    final List<RexNode> bottomIntersecting = new ArrayList<>();
    final List<RexNode> bottomNonIntersecting = new ArrayList<>();
    split(bottomJoin.getCondition(), bBitSet, bottomIntersecting, bottomNonIntersecting);
    // target: | A       | C      |
    // source: | A       | B | C      |
    final Mappings.TargetMapping bottomMapping = Mappings.createShiftMapping(aCount + bCount + cCount, 0, 0, aCount, aCount, aCount + bCount, cCount);
    final List<RexNode> newBottomList = new ArrayList<>();
    new RexPermuteInputsShuttle(bottomMapping, relA, relC).visitList(nonIntersecting, newBottomList);
    new RexPermuteInputsShuttle(bottomMapping, relA, relC).visitList(bottomNonIntersecting, newBottomList);
    final RexBuilder rexBuilder = cluster.getRexBuilder();
    RexNode newBottomCondition = RexUtil.composeConjunction(rexBuilder, newBottomList, false);
    final Join newBottomJoin = bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relA, relC, bottomJoin.getJoinType(), bottomJoin.isSemiJoinDone());
    // target: | A       | C      | B |
    // source: | A       | B | C      |
    final Mappings.TargetMapping topMapping = Mappings.createShiftMapping(aCount + bCount + cCount, 0, 0, aCount, aCount + cCount, aCount, bCount, aCount, aCount + bCount, cCount);
    final List<RexNode> newTopList = new ArrayList<>();
    new RexPermuteInputsShuttle(topMapping, newBottomJoin, relB).visitList(intersecting, newTopList);
    new RexPermuteInputsShuttle(topMapping, newBottomJoin, relB).visitList(bottomIntersecting, newTopList);
    RexNode newTopCondition = RexUtil.composeConjunction(rexBuilder, newTopList, false);
    @SuppressWarnings("SuspiciousNameCombination") final Join newTopJoin = topJoin.copy(topJoin.getTraitSet(), newTopCondition, newBottomJoin, relB, topJoin.getJoinType(), topJoin.isSemiJoinDone());
    assert !Mappings.isIdentity(topMapping);
    final RelBuilder relBuilder = call.builder();
    relBuilder.push(newTopJoin);
    relBuilder.project(relBuilder.fields(topMapping));
    call.transformTo(relBuilder.build());
}
Also used : RelOptCluster(org.apache.calcite.plan.RelOptCluster) RelBuilder(org.apache.calcite.tools.RelBuilder) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) ArrayList(java.util.ArrayList) Join(org.apache.calcite.rel.core.Join) LogicalJoin(org.apache.calcite.rel.logical.LogicalJoin) RelNode(org.apache.calcite.rel.RelNode) Mappings(org.apache.calcite.util.mapping.Mappings) RexBuilder(org.apache.calcite.rex.RexBuilder) RexPermuteInputsShuttle(org.apache.calcite.rex.RexPermuteInputsShuttle) RexNode(org.apache.calcite.rex.RexNode)

Example 88 with RelOptCluster

use of org.apache.calcite.plan.RelOptCluster in project calcite by apache.

the class JoinPushThroughJoinRule method onMatchLeft.

/**
 * Similar to {@link #onMatch}, but swaps the upper sibling with the left
 * of the two lower siblings, rather than the right.
 */
private void onMatchLeft(RelOptRuleCall call) {
    final Join topJoin = call.rel(0);
    final Join bottomJoin = call.rel(1);
    final RelNode relC = call.rel(2);
    final RelNode relA = bottomJoin.getLeft();
    final RelNode relB = bottomJoin.getRight();
    final RelOptCluster cluster = topJoin.getCluster();
    // topJoin
    // /     \
    // bottomJoin  C
    // /    \
    // A      B
    final int aCount = relA.getRowType().getFieldCount();
    final int bCount = relB.getRowType().getFieldCount();
    final int cCount = relC.getRowType().getFieldCount();
    final ImmutableBitSet aBitSet = ImmutableBitSet.range(aCount);
    // (Is this too strict?)
    if (topJoin.getJoinType() != JoinRelType.INNER || bottomJoin.getJoinType() != JoinRelType.INNER) {
        return;
    }
    // Split the condition of topJoin into a conjunction. Each of the
    // parts that does not use columns from A can be pushed down.
    final List<RexNode> intersecting = new ArrayList<>();
    final List<RexNode> nonIntersecting = new ArrayList<>();
    split(topJoin.getCondition(), aBitSet, intersecting, nonIntersecting);
    // If there's nothing to push down, it's not worth proceeding.
    if (nonIntersecting.isEmpty()) {
        return;
    }
    // Split the condition of bottomJoin into a conjunction. Each of the
    // parts that use columns from A will need to be pulled up.
    final List<RexNode> bottomIntersecting = new ArrayList<>();
    final List<RexNode> bottomNonIntersecting = new ArrayList<>();
    split(bottomJoin.getCondition(), aBitSet, bottomIntersecting, bottomNonIntersecting);
    // target: | C      | B |
    // source: | A       | B | C      |
    final Mappings.TargetMapping bottomMapping = Mappings.createShiftMapping(aCount + bCount + cCount, cCount, aCount, bCount, 0, aCount + bCount, cCount);
    final List<RexNode> newBottomList = new ArrayList<>();
    new RexPermuteInputsShuttle(bottomMapping, relC, relB).visitList(nonIntersecting, newBottomList);
    new RexPermuteInputsShuttle(bottomMapping, relC, relB).visitList(bottomNonIntersecting, newBottomList);
    final RexBuilder rexBuilder = cluster.getRexBuilder();
    RexNode newBottomCondition = RexUtil.composeConjunction(rexBuilder, newBottomList, false);
    final Join newBottomJoin = bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relC, relB, bottomJoin.getJoinType(), bottomJoin.isSemiJoinDone());
    // target: | C      | B | A       |
    // source: | A       | B | C      |
    final Mappings.TargetMapping topMapping = Mappings.createShiftMapping(aCount + bCount + cCount, cCount + bCount, 0, aCount, cCount, aCount, bCount, 0, aCount + bCount, cCount);
    final List<RexNode> newTopList = new ArrayList<>();
    new RexPermuteInputsShuttle(topMapping, newBottomJoin, relA).visitList(intersecting, newTopList);
    new RexPermuteInputsShuttle(topMapping, newBottomJoin, relA).visitList(bottomIntersecting, newTopList);
    RexNode newTopCondition = RexUtil.composeConjunction(rexBuilder, newTopList, false);
    @SuppressWarnings("SuspiciousNameCombination") final Join newTopJoin = topJoin.copy(topJoin.getTraitSet(), newTopCondition, newBottomJoin, relA, topJoin.getJoinType(), topJoin.isSemiJoinDone());
    final RelBuilder relBuilder = call.builder();
    relBuilder.push(newTopJoin);
    relBuilder.project(relBuilder.fields(topMapping));
    call.transformTo(relBuilder.build());
}
Also used : RelOptCluster(org.apache.calcite.plan.RelOptCluster) RelBuilder(org.apache.calcite.tools.RelBuilder) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) ArrayList(java.util.ArrayList) Join(org.apache.calcite.rel.core.Join) LogicalJoin(org.apache.calcite.rel.logical.LogicalJoin) RelNode(org.apache.calcite.rel.RelNode) Mappings(org.apache.calcite.util.mapping.Mappings) RexBuilder(org.apache.calcite.rex.RexBuilder) RexPermuteInputsShuttle(org.apache.calcite.rex.RexPermuteInputsShuttle) RexNode(org.apache.calcite.rex.RexNode)

Example 89 with RelOptCluster

use of org.apache.calcite.plan.RelOptCluster in project calcite by apache.

the class ReduceExpressionsRule method reduceExpressions.

/**
 * Reduces a list of expressions.
 *
 * <p>The {@code matchNullability} flag comes into play when reducing a
 * expression whose type is nullable. Suppose we are reducing an expression
 * {@code CASE WHEN 'a' = 'a' THEN 1 ELSE NULL END}. Before reduction the
 * type is {@code INTEGER} (nullable), but after reduction the literal 1 has
 * type {@code INTEGER NOT NULL}.
 *
 * <p>In some situations it is more important to preserve types; in this
 * case you should use {@code matchNullability = true} (which used to be
 * the default behavior of this method), and it will cast the literal to
 * {@code INTEGER} (nullable).
 *
 * <p>In other situations, you would rather propagate the new stronger type,
 * because it may allow further optimizations later; pass
 * {@code matchNullability = false} and no cast will be added, but you may
 * need to adjust types elsewhere in the expression tree.
 *
 * @param rel     Relational expression
 * @param expList List of expressions, modified in place
 * @param predicates Constraints known to hold on input expressions
 * @param unknownAsFalse Whether UNKNOWN will be treated as FALSE
 * @param matchNullability Whether Calcite should add a CAST to a literal
 *                         resulting from simplification and expression if the
 *                         expression had nullable type and the literal is
 *                         NOT NULL
 *
 * @return whether reduction found something to change, and succeeded
 */
protected static boolean reduceExpressions(RelNode rel, List<RexNode> expList, RelOptPredicateList predicates, boolean unknownAsFalse, boolean matchNullability) {
    final RelOptCluster cluster = rel.getCluster();
    final RexBuilder rexBuilder = cluster.getRexBuilder();
    final RexExecutor executor = Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR);
    final RexSimplify simplify = new RexSimplify(rexBuilder, predicates, unknownAsFalse, executor);
    // Simplify predicates in place
    boolean reduced = reduceExpressionsInternal(rel, simplify, expList, predicates);
    final ExprSimplifier simplifier = new ExprSimplifier(simplify, matchNullability);
    boolean simplified = false;
    for (int i = 0; i < expList.size(); i++) {
        RexNode expr2 = simplifier.apply(expList.get(i));
        if (!expr2.toString().equals(expList.get(i).toString())) {
            expList.remove(i);
            expList.add(i, expr2);
            simplified = true;
        }
    }
    return reduced || simplified;
}
Also used : RelOptCluster(org.apache.calcite.plan.RelOptCluster) RexSimplify(org.apache.calcite.rex.RexSimplify) RexExecutor(org.apache.calcite.rex.RexExecutor) RexBuilder(org.apache.calcite.rex.RexBuilder) ExprSimplifier(org.apache.calcite.rex.RexUtil.ExprSimplifier) RexNode(org.apache.calcite.rex.RexNode)

Example 90 with RelOptCluster

use of org.apache.calcite.plan.RelOptCluster in project calcite by apache.

the class FilterTableFunctionTransposeRule method onMatch.

// ~ Methods ----------------------------------------------------------------
// implement RelOptRule
public void onMatch(RelOptRuleCall call) {
    LogicalFilter filter = call.rel(0);
    LogicalTableFunctionScan funcRel = call.rel(1);
    Set<RelColumnMapping> columnMappings = funcRel.getColumnMappings();
    if (columnMappings == null || columnMappings.isEmpty()) {
        // possible.
        return;
    }
    List<RelNode> funcInputs = funcRel.getInputs();
    if (funcInputs.size() != 1) {
        // offsetting field indices, similar to join
        return;
    }
    // TODO:  support mappings other than 1-to-1
    if (funcRel.getRowType().getFieldCount() != funcInputs.get(0).getRowType().getFieldCount()) {
        return;
    }
    for (RelColumnMapping mapping : columnMappings) {
        if (mapping.iInputColumn != mapping.iOutputColumn) {
            return;
        }
        if (mapping.derived) {
            return;
        }
    }
    final List<RelNode> newFuncInputs = new ArrayList<RelNode>();
    final RelOptCluster cluster = funcRel.getCluster();
    final RexNode condition = filter.getCondition();
    // create filters on top of each func input, modifying the filter
    // condition to reference the child instead
    RexBuilder rexBuilder = filter.getCluster().getRexBuilder();
    List<RelDataTypeField> origFields = funcRel.getRowType().getFieldList();
    // TODO:  these need to be non-zero once we
    // support arbitrary mappings
    int[] adjustments = new int[origFields.size()];
    for (RelNode funcInput : funcInputs) {
        RexNode newCondition = condition.accept(new RelOptUtil.RexInputConverter(rexBuilder, origFields, funcInput.getRowType().getFieldList(), adjustments));
        newFuncInputs.add(LogicalFilter.create(funcInput, newCondition));
    }
    // create a new UDX whose children are the filters created above
    LogicalTableFunctionScan newFuncRel = LogicalTableFunctionScan.create(cluster, newFuncInputs, funcRel.getCall(), funcRel.getElementType(), funcRel.getRowType(), columnMappings);
    call.transformTo(newFuncRel);
}
Also used : RelOptCluster(org.apache.calcite.plan.RelOptCluster) LogicalFilter(org.apache.calcite.rel.logical.LogicalFilter) RelOptUtil(org.apache.calcite.plan.RelOptUtil) ArrayList(java.util.ArrayList) LogicalTableFunctionScan(org.apache.calcite.rel.logical.LogicalTableFunctionScan) RelDataTypeField(org.apache.calcite.rel.type.RelDataTypeField) RelNode(org.apache.calcite.rel.RelNode) RexBuilder(org.apache.calcite.rex.RexBuilder) RelColumnMapping(org.apache.calcite.rel.metadata.RelColumnMapping) RexNode(org.apache.calcite.rex.RexNode)

Aggregations

RelOptCluster (org.apache.calcite.plan.RelOptCluster)117 RelNode (org.apache.calcite.rel.RelNode)63 RelTraitSet (org.apache.calcite.plan.RelTraitSet)36 RexBuilder (org.apache.calcite.rex.RexBuilder)35 RexNode (org.apache.calcite.rex.RexNode)31 ArrayList (java.util.ArrayList)25 RelDataType (org.apache.calcite.rel.type.RelDataType)23 Test (org.junit.Test)21 ImmutableBitSet (org.apache.calcite.util.ImmutableBitSet)15 List (java.util.List)13 RelDataTypeField (org.apache.calcite.rel.type.RelDataTypeField)13 RelBuilder (org.apache.calcite.tools.RelBuilder)13 RelCollation (org.apache.calcite.rel.RelCollation)12 RelMetadataQuery (org.apache.calcite.rel.metadata.RelMetadataQuery)11 RelOptTable (org.apache.calcite.plan.RelOptTable)10 ImmutableList (com.google.common.collect.ImmutableList)9 HashMap (java.util.HashMap)9 RelOptPlanner (org.apache.calcite.plan.RelOptPlanner)9 Join (org.apache.calcite.rel.core.Join)9 LogicalJoin (org.apache.calcite.rel.logical.LogicalJoin)9