Search in sources :

Example 81 with ImmutableBitSet

use of org.apache.calcite.util.ImmutableBitSet in project calcite by apache.

the class RelOptUtil method splitJoinCondition.

private static void splitJoinCondition(List<RelDataTypeField> sysFieldList, List<RelNode> inputs, RexNode condition, List<List<RexNode>> joinKeys, @Nullable List<Integer> filterNulls, @Nullable List<SqlOperator> rangeOp, List<RexNode> nonEquiList) {
    final int sysFieldCount = sysFieldList.size();
    final RelOptCluster cluster = inputs.get(0).getCluster();
    final RexBuilder rexBuilder = cluster.getRexBuilder();
    final RelDataTypeFactory typeFactory = cluster.getTypeFactory();
    final ImmutableBitSet[] inputsRange = new ImmutableBitSet[inputs.size()];
    int totalFieldCount = 0;
    for (int i = 0; i < inputs.size(); i++) {
        final int firstField = totalFieldCount + sysFieldCount;
        totalFieldCount = firstField + inputs.get(i).getRowType().getFieldCount();
        inputsRange[i] = ImmutableBitSet.range(firstField, totalFieldCount);
    }
    // adjustment array
    int[] adjustments = new int[totalFieldCount];
    for (int i = 0; i < inputs.size(); i++) {
        final int adjustment = inputsRange[i].nextSetBit(0);
        for (int j = adjustment; j < inputsRange[i].length(); j++) {
            adjustments[j] = -adjustment;
        }
    }
    if (condition.getKind() == SqlKind.AND) {
        for (RexNode operand : ((RexCall) condition).getOperands()) {
            splitJoinCondition(sysFieldList, inputs, operand, joinKeys, filterNulls, rangeOp, nonEquiList);
        }
        return;
    }
    if (condition instanceof RexCall) {
        RexNode leftKey = null;
        RexNode rightKey = null;
        int leftInput = 0;
        int rightInput = 0;
        List<RelDataTypeField> leftFields = null;
        List<RelDataTypeField> rightFields = null;
        boolean reverse = false;
        final RexCall call = collapseExpandedIsNotDistinctFromExpr((RexCall) condition, rexBuilder);
        SqlKind kind = call.getKind();
        // Only consider range operators if we haven't already seen one
        if ((kind == SqlKind.EQUALS) || (filterNulls != null && kind == SqlKind.IS_NOT_DISTINCT_FROM) || (rangeOp != null && rangeOp.isEmpty() && (kind == SqlKind.GREATER_THAN || kind == SqlKind.GREATER_THAN_OR_EQUAL || kind == SqlKind.LESS_THAN || kind == SqlKind.LESS_THAN_OR_EQUAL))) {
            final List<RexNode> operands = call.getOperands();
            RexNode op0 = operands.get(0);
            RexNode op1 = operands.get(1);
            final ImmutableBitSet projRefs0 = InputFinder.bits(op0);
            final ImmutableBitSet projRefs1 = InputFinder.bits(op1);
            boolean foundBothInputs = false;
            for (int i = 0; i < inputs.size() && !foundBothInputs; i++) {
                if (projRefs0.intersects(inputsRange[i]) && projRefs0.union(inputsRange[i]).equals(inputsRange[i])) {
                    if (leftKey == null) {
                        leftKey = op0;
                        leftInput = i;
                        leftFields = inputs.get(leftInput).getRowType().getFieldList();
                    } else {
                        rightKey = op0;
                        rightInput = i;
                        rightFields = inputs.get(rightInput).getRowType().getFieldList();
                        reverse = true;
                        foundBothInputs = true;
                    }
                } else if (projRefs1.intersects(inputsRange[i]) && projRefs1.union(inputsRange[i]).equals(inputsRange[i])) {
                    if (leftKey == null) {
                        leftKey = op1;
                        leftInput = i;
                        leftFields = inputs.get(leftInput).getRowType().getFieldList();
                    } else {
                        rightKey = op1;
                        rightInput = i;
                        rightFields = inputs.get(rightInput).getRowType().getFieldList();
                        foundBothInputs = true;
                    }
                }
            }
            if ((leftKey != null) && (rightKey != null)) {
                // replace right Key input ref
                rightKey = rightKey.accept(new RelOptUtil.RexInputConverter(rexBuilder, rightFields, rightFields, adjustments));
                // left key only needs to be adjusted if there are system
                // fields, but do it for uniformity
                leftKey = leftKey.accept(new RelOptUtil.RexInputConverter(rexBuilder, leftFields, leftFields, adjustments));
                RelDataType leftKeyType = leftKey.getType();
                RelDataType rightKeyType = rightKey.getType();
                if (leftKeyType != rightKeyType) {
                    // perform casting
                    RelDataType targetKeyType = typeFactory.leastRestrictive(ImmutableList.of(leftKeyType, rightKeyType));
                    if (targetKeyType == null) {
                        throw new AssertionError("Cannot find common type for join keys " + leftKey + " (type " + leftKeyType + ") and " + rightKey + " (type " + rightKeyType + ")");
                    }
                    if (leftKeyType != targetKeyType) {
                        leftKey = rexBuilder.makeCast(targetKeyType, leftKey);
                    }
                    if (rightKeyType != targetKeyType) {
                        rightKey = rexBuilder.makeCast(targetKeyType, rightKey);
                    }
                }
            }
        }
        if ((rangeOp == null) && ((leftKey == null) || (rightKey == null))) {
            // no equality join keys found yet:
            // try transforming the condition to
            // equality "join" conditions, e.g.
            // f(LHS) > 0 ===> ( f(LHS) > 0 ) = TRUE,
            // and make the RHS produce TRUE, but only if we're strictly
            // looking for equi-joins
            final ImmutableBitSet projRefs = InputFinder.bits(condition);
            leftKey = null;
            rightKey = null;
            boolean foundInput = false;
            for (int i = 0; i < inputs.size() && !foundInput; i++) {
                if (inputsRange[i].contains(projRefs)) {
                    leftInput = i;
                    leftFields = inputs.get(leftInput).getRowType().getFieldList();
                    leftKey = condition.accept(new RelOptUtil.RexInputConverter(rexBuilder, leftFields, leftFields, adjustments));
                    rightKey = rexBuilder.makeLiteral(true);
                    // effectively performing an equality comparison
                    kind = SqlKind.EQUALS;
                    foundInput = true;
                }
            }
        }
        if ((leftKey != null) && (rightKey != null)) {
            // found suitable join keys
            // add them to key list, ensuring that if there is a
            // non-equi join predicate, it appears at the end of the
            // key list; also mark the null filtering property
            addJoinKey(joinKeys.get(leftInput), leftKey, (rangeOp != null) && !rangeOp.isEmpty());
            addJoinKey(joinKeys.get(rightInput), rightKey, (rangeOp != null) && !rangeOp.isEmpty());
            if (filterNulls != null && kind == SqlKind.EQUALS) {
                // nulls are considered not matching for equality comparison
                // add the position of the most recently inserted key
                filterNulls.add(joinKeys.get(leftInput).size() - 1);
            }
            if (rangeOp != null && kind != SqlKind.EQUALS && kind != SqlKind.IS_DISTINCT_FROM) {
                SqlOperator op = call.getOperator();
                if (reverse) {
                    op = requireNonNull(op.reverse());
                }
                rangeOp.add(op);
            }
            return;
        }
    // else fall through and add this condition as nonEqui condition
    }
    // The operator is not of RexCall type
    // So we fail. Fall through.
    // Add this condition to the list of non-equi-join conditions.
    nonEquiList.add(condition);
}
Also used : ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) SqlOperator(org.apache.calcite.sql.SqlOperator) RelDataType(org.apache.calcite.rel.type.RelDataType) SqlKind(org.apache.calcite.sql.SqlKind) RelHint(org.apache.calcite.rel.hint.RelHint) RexCall(org.apache.calcite.rex.RexCall) RelDataTypeField(org.apache.calcite.rel.type.RelDataTypeField) RelDataTypeFactory(org.apache.calcite.rel.type.RelDataTypeFactory) RexBuilder(org.apache.calcite.rex.RexBuilder) RexNode(org.apache.calcite.rex.RexNode)

Example 82 with ImmutableBitSet

use of org.apache.calcite.util.ImmutableBitSet in project calcite by apache.

the class RelOptUtil method classifyFilters.

/**
 * Classifies filters according to where they should be processed. They
 * either stay where they are, are pushed to the join (if they originated
 * from above the join), or are pushed to one of the children. Filters that
 * are pushed are added to list passed in as input parameters.
 *
 * @param joinRel      join node
 * @param filters      filters to be classified
 * @param pushInto     whether filters can be pushed into the join
 * @param pushLeft     true if filters can be pushed to the left
 * @param pushRight    true if filters can be pushed to the right
 * @param joinFilters  list of filters to push to the join
 * @param leftFilters  list of filters to push to the left child
 * @param rightFilters list of filters to push to the right child
 * @return whether at least one filter was pushed
 */
public static boolean classifyFilters(RelNode joinRel, List<RexNode> filters, boolean pushInto, boolean pushLeft, boolean pushRight, List<RexNode> joinFilters, List<RexNode> leftFilters, List<RexNode> rightFilters) {
    RexBuilder rexBuilder = joinRel.getCluster().getRexBuilder();
    List<RelDataTypeField> joinFields = joinRel.getRowType().getFieldList();
    // joinRel.getSystemFieldList().size();
    final int nSysFields = 0;
    final List<RelDataTypeField> leftFields = joinRel.getInputs().get(0).getRowType().getFieldList();
    final int nFieldsLeft = leftFields.size();
    final List<RelDataTypeField> rightFields = joinRel.getInputs().get(1).getRowType().getFieldList();
    final int nFieldsRight = rightFields.size();
    final int nTotalFields = nFieldsLeft + nFieldsRight;
    // set the reference bitmaps for the left and right children
    ImmutableBitSet leftBitmap = ImmutableBitSet.range(nSysFields, nSysFields + nFieldsLeft);
    ImmutableBitSet rightBitmap = ImmutableBitSet.range(nSysFields + nFieldsLeft, nTotalFields);
    final List<RexNode> filtersToRemove = new ArrayList<>();
    for (RexNode filter : filters) {
        final InputFinder inputFinder = InputFinder.analyze(filter);
        final ImmutableBitSet inputBits = inputFinder.build();
        if (pushLeft && leftBitmap.contains(inputBits)) {
            // ignore filters that always evaluate to true
            if (!filter.isAlwaysTrue()) {
                // adjust the field references in the filter to reflect
                // that fields in the left now shift over by the number
                // of system fields
                final RexNode shiftedFilter = shiftFilter(nSysFields, nSysFields + nFieldsLeft, -nSysFields, rexBuilder, joinFields, nTotalFields, leftFields, filter);
                leftFilters.add(shiftedFilter);
            }
            filtersToRemove.add(filter);
        } else if (pushRight && rightBitmap.contains(inputBits)) {
            if (!filter.isAlwaysTrue()) {
                // adjust the field references in the filter to reflect
                // that fields in the right now shift over to the left
                final RexNode shiftedFilter = shiftFilter(nSysFields + nFieldsLeft, nTotalFields, -(nSysFields + nFieldsLeft), rexBuilder, joinFields, nTotalFields, rightFields, filter);
                rightFilters.add(shiftedFilter);
            }
            filtersToRemove.add(filter);
        } else {
            // If the filter can't be pushed to either child, we may push them into the join
            if (pushInto) {
                if (!joinFilters.contains(filter)) {
                    joinFilters.add(filter);
                }
                filtersToRemove.add(filter);
            }
        }
    }
    // Remove filters after the loop, to prevent concurrent modification.
    if (!filtersToRemove.isEmpty()) {
        filters.removeAll(filtersToRemove);
    }
    // Did anything change?
    return !filtersToRemove.isEmpty();
}
Also used : RelDataTypeField(org.apache.calcite.rel.type.RelDataTypeField) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) ArrayList(java.util.ArrayList) RexBuilder(org.apache.calcite.rex.RexBuilder) RelHint(org.apache.calcite.rel.hint.RelHint) RexNode(org.apache.calcite.rex.RexNode)

Example 83 with ImmutableBitSet

use of org.apache.calcite.util.ImmutableBitSet in project calcite by apache.

the class RelOptUtil method pushDownEqualJoinConditions.

/**
 * Pushes down parts of a join condition.
 *
 * <p>For example, given
 * "emp JOIN dept ON emp.deptno + 1 = dept.deptno", adds a project above
 * "emp" that computes the expression
 * "emp.deptno + 1". The resulting join condition is a simple combination
 * of AND, equals, and input fields.
 */
private static RexNode pushDownEqualJoinConditions(RexNode condition, int leftCount, int rightCount, List<RexNode> extraLeftExprs, List<RexNode> extraRightExprs, RexBuilder builder) {
    // Normalize the condition first
    RexNode node = (condition instanceof RexCall) ? collapseExpandedIsNotDistinctFromExpr((RexCall) condition, builder) : condition;
    switch(node.getKind()) {
        case EQUALS:
        case IS_NOT_DISTINCT_FROM:
            final RexCall call0 = (RexCall) node;
            final RexNode leftRex = call0.getOperands().get(0);
            final RexNode rightRex = call0.getOperands().get(1);
            final ImmutableBitSet leftBits = RelOptUtil.InputFinder.bits(leftRex);
            final ImmutableBitSet rightBits = RelOptUtil.InputFinder.bits(rightRex);
            final int pivot = leftCount + extraLeftExprs.size();
            Side lside = Side.of(leftBits, pivot);
            Side rside = Side.of(rightBits, pivot);
            if (!lside.opposite(rside)) {
                return call0;
            }
        // fall through
        case AND:
            final RexCall call = (RexCall) node;
            final List<RexNode> list = new ArrayList<>();
            List<RexNode> operands = Lists.newArrayList(call.getOperands());
            for (int i = 0; i < operands.size(); i++) {
                RexNode operand = operands.get(i);
                if (operand instanceof RexCall) {
                    operand = collapseExpandedIsNotDistinctFromExpr((RexCall) operand, builder);
                }
                if (node.getKind() == SqlKind.AND && operand.getKind() != SqlKind.EQUALS && operand.getKind() != SqlKind.IS_NOT_DISTINCT_FROM) {
                    // one of the join condition is neither EQ nor INDF
                    list.add(operand);
                } else {
                    final int left2 = leftCount + extraLeftExprs.size();
                    final RexNode e = pushDownEqualJoinConditions(operand, leftCount, rightCount, extraLeftExprs, extraRightExprs, builder);
                    if (!e.equals(operand)) {
                        final List<RexNode> remainingOperands = Util.skip(operands, i + 1);
                        final int left3 = leftCount + extraLeftExprs.size();
                        fix(remainingOperands, left2, left3);
                        fix(list, left2, left3);
                    }
                    list.add(e);
                }
            }
            if (!list.equals(call.getOperands())) {
                return call.clone(call.getType(), list);
            }
            return call;
        case OR:
        case INPUT_REF:
        case LITERAL:
        case NOT:
            return node;
        default:
            final ImmutableBitSet bits = RelOptUtil.InputFinder.bits(node);
            final int mid = leftCount + extraLeftExprs.size();
            switch(Side.of(bits, mid)) {
                case LEFT:
                    fix(extraRightExprs, mid, mid + 1);
                    extraLeftExprs.add(node);
                    return new RexInputRef(mid, node.getType());
                case RIGHT:
                    final int index2 = mid + rightCount + extraRightExprs.size();
                    extraRightExprs.add(node);
                    return new RexInputRef(index2, node.getType());
                case BOTH:
                case EMPTY:
                default:
                    return node;
            }
    }
}
Also used : RexCall(org.apache.calcite.rex.RexCall) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) ArrayList(java.util.ArrayList) RexInputRef(org.apache.calcite.rex.RexInputRef) RelHint(org.apache.calcite.rel.hint.RelHint) RexNode(org.apache.calcite.rex.RexNode)

Example 84 with ImmutableBitSet

use of org.apache.calcite.util.ImmutableBitSet in project calcite by apache.

the class RelOptUtil method simplifyJoin.

/**
 * Simplifies outer joins if filter above would reject nulls.
 *
 * @param joinRel Join
 * @param aboveFilters Filters from above
 * @param joinType Join type, can not be inner join
 */
public static JoinRelType simplifyJoin(RelNode joinRel, ImmutableList<RexNode> aboveFilters, JoinRelType joinType) {
    // No need to simplify if the join only outputs left side.
    if (!joinType.projectsRight()) {
        return joinType;
    }
    final int nTotalFields = joinRel.getRowType().getFieldCount();
    final int nSysFields = 0;
    final int nFieldsLeft = joinRel.getInputs().get(0).getRowType().getFieldCount();
    final int nFieldsRight = joinRel.getInputs().get(1).getRowType().getFieldCount();
    assert nTotalFields == nSysFields + nFieldsLeft + nFieldsRight;
    // set the reference bitmaps for the left and right children
    ImmutableBitSet leftBitmap = ImmutableBitSet.range(nSysFields, nSysFields + nFieldsLeft);
    ImmutableBitSet rightBitmap = ImmutableBitSet.range(nSysFields + nFieldsLeft, nTotalFields);
    for (RexNode filter : aboveFilters) {
        if (joinType.generatesNullsOnLeft() && Strong.isNotTrue(filter, leftBitmap)) {
            joinType = joinType.cancelNullsOnLeft();
        }
        if (joinType.generatesNullsOnRight() && Strong.isNotTrue(filter, rightBitmap)) {
            joinType = joinType.cancelNullsOnRight();
        }
        if (!joinType.isOuterJoin()) {
            break;
        }
    }
    return joinType;
}
Also used : ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) RelHint(org.apache.calcite.rel.hint.RelHint) RexNode(org.apache.calcite.rex.RexNode)

Example 85 with ImmutableBitSet

use of org.apache.calcite.util.ImmutableBitSet in project calcite by apache.

the class RelOptUtil method correlationColumns.

/**
 * Finds which columns of a correlation variable are used within a
 * relational expression.
 */
public static ImmutableBitSet correlationColumns(CorrelationId id, RelNode rel) {
    final CorrelationCollector collector = new CorrelationCollector();
    rel.accept(collector);
    final ImmutableBitSet.Builder builder = ImmutableBitSet.builder();
    for (int field : collector.vuv.variableFields.get(id)) {
        if (field >= 0) {
            builder.set(field);
        }
    }
    return builder.build();
}
Also used : ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) RelHint(org.apache.calcite.rel.hint.RelHint)

Aggregations

ImmutableBitSet (org.apache.calcite.util.ImmutableBitSet)365 RexNode (org.apache.calcite.rex.RexNode)196 RelNode (org.apache.calcite.rel.RelNode)183 ArrayList (java.util.ArrayList)179 AggregateCall (org.apache.calcite.rel.core.AggregateCall)116 RelDataTypeField (org.apache.calcite.rel.type.RelDataTypeField)98 RexBuilder (org.apache.calcite.rex.RexBuilder)92 RelDataType (org.apache.calcite.rel.type.RelDataType)89 RexInputRef (org.apache.calcite.rex.RexInputRef)79 HashMap (java.util.HashMap)68 Aggregate (org.apache.calcite.rel.core.Aggregate)62 RelBuilder (org.apache.calcite.tools.RelBuilder)59 Pair (org.apache.calcite.util.Pair)57 List (java.util.List)49 ImmutableList (com.google.common.collect.ImmutableList)48 HashSet (java.util.HashSet)45 LinkedHashSet (java.util.LinkedHashSet)45 Join (org.apache.calcite.rel.core.Join)45 RelMetadataQuery (org.apache.calcite.rel.metadata.RelMetadataQuery)45 Nullable (org.checkerframework.checker.nullness.qual.Nullable)43