Search in sources :

Example 36 with RexBuilder

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexBuilder in project calcite by apache.

the class LoptOptimizeJoinRule method pushDownFactor.

/**
 * Creates a join tree where the new factor is pushed down one of the
 * operands of the current join tree
 *
 * @param multiJoin join factors being optimized
 * @param semiJoinOpt optimal semijoins for each factor
 * @param joinTree current join tree
 * @param factorToAdd new factor to be added
 * @param factorsNeeded factors that must precede the factor to be added
 * @param filtersToAdd filters remaining to be added; filters that are added
 * to the join tree are removed from the list
 * @param selfJoin true if the factor being added is part of a removable
 * self-join
 *
 * @return optimal join tree with the new factor pushed down the current
 * join tree if it is possible to do the pushdown; otherwise, null is
 * returned
 */
private LoptJoinTree pushDownFactor(RelMetadataQuery mq, RelBuilder relBuilder, LoptMultiJoin multiJoin, LoptSemiJoinOptimizer semiJoinOpt, LoptJoinTree joinTree, int factorToAdd, BitSet factorsNeeded, List<RexNode> filtersToAdd, boolean selfJoin) {
    // pushdown option only works if we already have a join tree
    if (!isJoinTree(joinTree.getJoinTree())) {
        return null;
    }
    int childNo = -1;
    LoptJoinTree left = joinTree.getLeft();
    LoptJoinTree right = joinTree.getRight();
    Join joinRel = (Join) joinTree.getJoinTree();
    JoinRelType joinType = joinRel.getJoinType();
    // them, we need to keep the factors together
    if (joinTree.isRemovableSelfJoin()) {
        return null;
    }
    // half of the self-join.
    if (selfJoin) {
        BitSet selfJoinFactor = new BitSet(multiJoin.getNumJoinFactors());
        selfJoinFactor.set(multiJoin.getOtherSelfJoinFactor(factorToAdd));
        if (multiJoin.hasAllFactors(left, selfJoinFactor)) {
            childNo = 0;
        } else {
            assert multiJoin.hasAllFactors(right, selfJoinFactor);
            childNo = 1;
        }
    } else if ((factorsNeeded.cardinality() == 0) && !joinType.generatesNullsOnLeft()) {
        childNo = 0;
    } else {
        // same check for RHS
        if (multiJoin.hasAllFactors(left, factorsNeeded) && !joinType.generatesNullsOnLeft()) {
            childNo = 0;
        } else if (multiJoin.hasAllFactors(right, factorsNeeded) && !joinType.generatesNullsOnRight()) {
            childNo = 1;
        }
    // if it couldn't be pushed down to either side, then it can
    // only be put on top
    }
    if (childNo == -1) {
        return null;
    }
    // remember the original join order before the pushdown so we can
    // appropriately adjust any filters already attached to the join
    // node
    final List<Integer> origJoinOrder = joinTree.getTreeOrder();
    // recursively pushdown the factor
    LoptJoinTree subTree = (childNo == 0) ? left : right;
    subTree = addFactorToTree(mq, relBuilder, multiJoin, semiJoinOpt, subTree, factorToAdd, factorsNeeded, filtersToAdd, selfJoin);
    if (childNo == 0) {
        left = subTree;
    } else {
        right = subTree;
    }
    // adjust the join condition from the original join tree to reflect
    // pushdown of the new factor as well as any swapping that may have
    // been done during the pushdown
    RexNode newCondition = ((Join) joinTree.getJoinTree()).getCondition();
    newCondition = adjustFilter(multiJoin, left, right, newCondition, factorToAdd, origJoinOrder, joinTree.getJoinTree().getRowType().getFieldList());
    // join in createJoinSubtree
    if ((joinType != JoinRelType.LEFT) && (joinType != JoinRelType.RIGHT)) {
        RexNode condition = addFilters(multiJoin, left, -1, right, filtersToAdd, true);
        RexBuilder rexBuilder = multiJoin.getMultiJoinRel().getCluster().getRexBuilder();
        newCondition = RelOptUtil.andJoinFilters(rexBuilder, newCondition, condition);
    }
    // create the new join tree with the factor pushed down
    return createJoinSubtree(mq, relBuilder, multiJoin, left, right, newCondition, joinType, filtersToAdd, false, false);
}
Also used : JoinRelType(org.apache.calcite.rel.core.JoinRelType) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) BitSet(java.util.BitSet) Join(org.apache.calcite.rel.core.Join) SemiJoin(org.apache.calcite.rel.core.SemiJoin) RexBuilder(org.apache.calcite.rex.RexBuilder) RexNode(org.apache.calcite.rex.RexNode)

Example 37 with RexBuilder

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexBuilder in project calcite by apache.

the class LoptOptimizeJoinRule method createReplacementJoin.

/**
 * Creates a replacement join, projecting either dummy columns or
 * replacement keys from the factor that doesn't actually need to be joined.
 *
 * @param multiJoin join factors being optimized
 * @param semiJoinOpt optimal semijoins for each factor
 * @param currJoinTree current join tree being added to
 * @param leftIdx if &ge; 0, when creating the replacement join, only consider
 * filters that reference leftIdx in currJoinTree; otherwise, consider all
 * filters that reference any factor in currJoinTree
 * @param factorToAdd new factor whose join can be removed
 * @param newKeys join keys that need to be replaced
 * @param replacementKeys the keys that replace the join keys; null if we're
 * removing the null generating factor in an outer join
 * @param filtersToAdd filters remaining to be added; filters added to the
 * new join tree are removed from the list
 *
 * @return created join tree with an appropriate projection for the factor
 * that can be removed
 */
private LoptJoinTree createReplacementJoin(RelBuilder relBuilder, LoptMultiJoin multiJoin, LoptSemiJoinOptimizer semiJoinOpt, LoptJoinTree currJoinTree, int leftIdx, int factorToAdd, ImmutableIntList newKeys, Integer[] replacementKeys, List<RexNode> filtersToAdd) {
    // create a projection, projecting the fields from the join tree
    // containing the current joinRel and the new factor; for fields
    // corresponding to join keys, replace them with the corresponding key
    // from the replacementKeys passed in; for other fields, just create a
    // null expression as a placeholder for the column; this is done so we
    // don't have to adjust the offsets of other expressions that reference
    // the new factor; the placeholder expression values should never be
    // referenced, so that's why it's ok to create these possibly invalid
    // expressions
    RelNode currJoinRel = currJoinTree.getJoinTree();
    List<RelDataTypeField> currFields = currJoinRel.getRowType().getFieldList();
    final int nCurrFields = currFields.size();
    List<RelDataTypeField> newFields = multiJoin.getJoinFactor(factorToAdd).getRowType().getFieldList();
    final int nNewFields = newFields.size();
    List<Pair<RexNode, String>> projects = Lists.newArrayList();
    RexBuilder rexBuilder = currJoinRel.getCluster().getRexBuilder();
    RelDataTypeFactory typeFactory = rexBuilder.getTypeFactory();
    for (int i = 0; i < nCurrFields; i++) {
        projects.add(Pair.of((RexNode) rexBuilder.makeInputRef(currFields.get(i).getType(), i), currFields.get(i).getName()));
    }
    for (int i = 0; i < nNewFields; i++) {
        RexNode projExpr;
        RelDataType newType = newFields.get(i).getType();
        if (!newKeys.contains(i)) {
            if (replacementKeys == null) {
                // null generating factor in an outer join; so make the
                // type nullable
                newType = typeFactory.createTypeWithNullability(newType, true);
            }
            projExpr = rexBuilder.makeCast(newType, rexBuilder.constantNull());
        } else {
            RelDataTypeField mappedField = currFields.get(replacementKeys[i]);
            RexNode mappedInput = rexBuilder.makeInputRef(mappedField.getType(), replacementKeys[i]);
            // if the types aren't the same, create a cast
            if (mappedField.getType() == newType) {
                projExpr = mappedInput;
            } else {
                projExpr = rexBuilder.makeCast(newFields.get(i).getType(), mappedInput);
            }
        }
        projects.add(Pair.of(projExpr, newFields.get(i).getName()));
    }
    relBuilder.push(currJoinRel);
    relBuilder.project(Pair.left(projects), Pair.right(projects));
    // remove the join conditions corresponding to the join we're removing;
    // we don't actually need to use them, but we need to remove them
    // from the list since they're no longer needed
    LoptJoinTree newTree = new LoptJoinTree(semiJoinOpt.getChosenSemiJoin(factorToAdd), factorToAdd);
    addFilters(multiJoin, currJoinTree, leftIdx, newTree, filtersToAdd, false);
    // LogicalFilter placed on top off the projection created above.
    if (leftIdx >= 0) {
        addAdditionalFilters(relBuilder, multiJoin, currJoinTree, newTree, filtersToAdd);
    }
    // from the new factor as we go up in the join tree
    return new LoptJoinTree(relBuilder.build(), currJoinTree.getFactorTree(), newTree.getFactorTree());
}
Also used : RelDataTypeField(org.apache.calcite.rel.type.RelDataTypeField) RelNode(org.apache.calcite.rel.RelNode) RelDataTypeFactory(org.apache.calcite.rel.type.RelDataTypeFactory) RexBuilder(org.apache.calcite.rex.RexBuilder) RelDataType(org.apache.calcite.rel.type.RelDataType) IntPair(org.apache.calcite.util.mapping.IntPair) Pair(org.apache.calcite.util.Pair) RexNode(org.apache.calcite.rex.RexNode)

Example 38 with RexBuilder

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexBuilder in project calcite by apache.

the class LoptOptimizeJoinRule method createJoinSubtree.

/**
 * Creates a LogicalJoin given left and right operands and a join condition.
 * Swaps the operands if beneficial.
 *
 * @param multiJoin join factors being optimized
 * @param left left operand
 * @param right right operand
 * @param condition join condition
 * @param joinType the join type
 * @param fullAdjust true if the join condition reflects the original join
 * ordering and therefore has not gone through any type of adjustment yet;
 * otherwise, the condition has already been partially adjusted and only
 * needs to be further adjusted if swapping is done
 * @param filtersToAdd additional filters that may be added on top of the
 * resulting LogicalJoin, if the join is a left or right outer join
 * @param selfJoin true if the join being created is a self-join that's
 * removable
 *
 * @return created LogicalJoin
 */
private LoptJoinTree createJoinSubtree(RelMetadataQuery mq, RelBuilder relBuilder, LoptMultiJoin multiJoin, LoptJoinTree left, LoptJoinTree right, RexNode condition, JoinRelType joinType, List<RexNode> filtersToAdd, boolean fullAdjust, boolean selfJoin) {
    RexBuilder rexBuilder = multiJoin.getMultiJoinRel().getCluster().getRexBuilder();
    // swap the inputs if beneficial
    if (swapInputs(mq, multiJoin, left, right, selfJoin)) {
        LoptJoinTree tmp = right;
        right = left;
        left = tmp;
        if (!fullAdjust) {
            condition = swapFilter(rexBuilder, multiJoin, right, left, condition);
        }
        if ((joinType != JoinRelType.INNER) && (joinType != JoinRelType.FULL)) {
            joinType = (joinType == JoinRelType.LEFT) ? JoinRelType.RIGHT : JoinRelType.LEFT;
        }
    }
    if (fullAdjust) {
        int[] adjustments = new int[multiJoin.getNumTotalFields()];
        if (needsAdjustment(multiJoin, adjustments, left, right, selfJoin)) {
            condition = condition.accept(new RelOptUtil.RexInputConverter(rexBuilder, multiJoin.getMultiJoinFields(), left.getJoinTree().getRowType().getFieldList(), right.getJoinTree().getRowType().getFieldList(), adjustments));
        }
    }
    relBuilder.push(left.getJoinTree()).push(right.getJoinTree()).join(joinType, condition);
    // as a filter on top of the outer join result
    if ((joinType == JoinRelType.LEFT) || (joinType == JoinRelType.RIGHT)) {
        assert !selfJoin;
        addAdditionalFilters(relBuilder, multiJoin, left, right, filtersToAdd);
    }
    return new LoptJoinTree(relBuilder.build(), left.getFactorTree(), right.getFactorTree(), selfJoin);
}
Also used : RexBuilder(org.apache.calcite.rex.RexBuilder)

Example 39 with RexBuilder

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexBuilder in project calcite by apache.

the class IntersectToDistinctRule method onMatch.

// ~ Methods ----------------------------------------------------------------
public void onMatch(RelOptRuleCall call) {
    final Intersect intersect = call.rel(0);
    if (intersect.all) {
        // nothing we can do
        return;
    }
    final RelOptCluster cluster = intersect.getCluster();
    final RexBuilder rexBuilder = cluster.getRexBuilder();
    final RelBuilder relBuilder = call.builder();
    // 1st level GB: create a GB (col0, col1, count() as c) for each branch
    for (RelNode input : intersect.getInputs()) {
        relBuilder.push(input);
        relBuilder.aggregate(relBuilder.groupKey(relBuilder.fields()), relBuilder.countStar(null));
    }
    // create a union above all the branches
    final int branchCount = intersect.getInputs().size();
    relBuilder.union(true, branchCount);
    final RelNode union = relBuilder.peek();
    // 2nd level GB: create a GB (col0, col1, count(c)) for each branch
    // the index of c is union.getRowType().getFieldList().size() - 1
    final int fieldCount = union.getRowType().getFieldCount();
    final ImmutableBitSet groupSet = ImmutableBitSet.range(fieldCount - 1);
    relBuilder.aggregate(relBuilder.groupKey(groupSet, null), relBuilder.countStar(null));
    // add a filter count(c) = #branches
    relBuilder.filter(relBuilder.equals(relBuilder.field(fieldCount - 1), rexBuilder.makeBigintLiteral(new BigDecimal(branchCount))));
    // Project all but the last field
    relBuilder.project(Util.skipLast(relBuilder.fields()));
    // the schema for intersect distinct is like this
    // R3 on all attributes + count(c) as cnt
    // finally add a project to project out the last column
    call.transformTo(relBuilder.build());
}
Also used : RelOptCluster(org.apache.calcite.plan.RelOptCluster) LogicalIntersect(org.apache.calcite.rel.logical.LogicalIntersect) Intersect(org.apache.calcite.rel.core.Intersect) RelBuilder(org.apache.calcite.tools.RelBuilder) RelNode(org.apache.calcite.rel.RelNode) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) RexBuilder(org.apache.calcite.rex.RexBuilder) BigDecimal(java.math.BigDecimal)

Example 40 with RexBuilder

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexBuilder in project calcite by apache.

the class JoinAssociateRule method onMatch.

// ~ Methods ----------------------------------------------------------------
public void onMatch(final RelOptRuleCall call) {
    final Join topJoin = call.rel(0);
    final Join bottomJoin = call.rel(1);
    final RelNode relA = bottomJoin.getLeft();
    final RelNode relB = bottomJoin.getRight();
    final RelSubset relC = call.rel(2);
    final RelOptCluster cluster = topJoin.getCluster();
    final RexBuilder rexBuilder = cluster.getRexBuilder();
    if (relC.getConvention() != relA.getConvention()) {
        // EnumerableConvention, we're only interested in enumerable subsets.
        return;
    }
    // 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(0, aCount);
    final ImmutableBitSet bBitSet = ImmutableBitSet.range(aCount, aCount + bCount);
    if (!topJoin.getSystemFieldList().isEmpty()) {
        // FIXME Enable this rule for joins with system fields
        return;
    }
    // (Is this too strict?)
    if (topJoin.getJoinType() != JoinRelType.INNER || bottomJoin.getJoinType() != JoinRelType.INNER) {
        return;
    }
    // Goal is to transform to
    // 
    // newTopJoin
    // /     \
    // A   newBottomJoin
    // /    \
    // B      C
    // Split the condition of topJoin and bottomJoin into a conjunctions. A
    // condition can be pushed down if it does not use columns from A.
    final List<RexNode> top = Lists.newArrayList();
    final List<RexNode> bottom = Lists.newArrayList();
    JoinPushThroughJoinRule.split(topJoin.getCondition(), aBitSet, top, bottom);
    JoinPushThroughJoinRule.split(bottomJoin.getCondition(), aBitSet, top, bottom);
    // Mapping for moving conditions from topJoin or bottomJoin to
    // newBottomJoin.
    // target: | B | C      |
    // source: | A       | B | C      |
    final Mappings.TargetMapping bottomMapping = Mappings.createShiftMapping(aCount + bCount + cCount, 0, aCount, bCount, bCount, aCount + bCount, cCount);
    final List<RexNode> newBottomList = Lists.newArrayList();
    new RexPermuteInputsShuttle(bottomMapping, relB, relC).visitList(bottom, newBottomList);
    RexNode newBottomCondition = RexUtil.composeConjunction(rexBuilder, newBottomList, false);
    final Join newBottomJoin = bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relB, relC, JoinRelType.INNER, false);
    // Condition for newTopJoin consists of pieces from bottomJoin and topJoin.
    // Field ordinals do not need to be changed.
    RexNode newTopCondition = RexUtil.composeConjunction(rexBuilder, top, false);
    final Join newTopJoin = topJoin.copy(topJoin.getTraitSet(), newTopCondition, relA, newBottomJoin, JoinRelType.INNER, false);
    call.transformTo(newTopJoin);
}
Also used : RelOptCluster(org.apache.calcite.plan.RelOptCluster) RelNode(org.apache.calcite.rel.RelNode) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) Mappings(org.apache.calcite.util.mapping.Mappings) Join(org.apache.calcite.rel.core.Join) RexBuilder(org.apache.calcite.rex.RexBuilder) RexPermuteInputsShuttle(org.apache.calcite.rex.RexPermuteInputsShuttle) RelSubset(org.apache.calcite.plan.volcano.RelSubset) RexNode(org.apache.calcite.rex.RexNode)

Aggregations

RexBuilder (org.apache.calcite.rex.RexBuilder)314 RexNode (org.apache.calcite.rex.RexNode)248 ArrayList (java.util.ArrayList)151 RelNode (org.apache.calcite.rel.RelNode)121 RelDataType (org.apache.calcite.rel.type.RelDataType)121 RelDataTypeField (org.apache.calcite.rel.type.RelDataTypeField)77 ImmutableBitSet (org.apache.calcite.util.ImmutableBitSet)59 RexInputRef (org.apache.calcite.rex.RexInputRef)49 RelBuilder (org.apache.calcite.tools.RelBuilder)49 AggregateCall (org.apache.calcite.rel.core.AggregateCall)48 List (java.util.List)41 RelDataTypeFactory (org.apache.calcite.rel.type.RelDataTypeFactory)41 RelOptCluster (org.apache.calcite.plan.RelOptCluster)36 HashMap (java.util.HashMap)33 RelOptPredicateList (org.apache.calcite.plan.RelOptPredicateList)24 Project (org.apache.calcite.rel.core.Project)24 RexCall (org.apache.calcite.rex.RexCall)24 BigDecimal (java.math.BigDecimal)23 Collectors (java.util.stream.Collectors)23 RelMetadataQuery (org.apache.calcite.rel.metadata.RelMetadataQuery)22