Search in sources :

Example 26 with RexCall

use of org.apache.calcite.rex.RexCall 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, List<Integer> filterNulls, 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 instanceof RexCall) {
        RexCall call = (RexCall) condition;
        if (call.getKind() == SqlKind.AND) {
            for (RexNode operand : call.getOperands()) {
                splitJoinCondition(sysFieldList, inputs, operand, joinKeys, filterNulls, rangeOp, nonEquiList);
            }
            return;
        }
        RexNode leftKey = null;
        RexNode rightKey = null;
        int leftInput = 0;
        int rightInput = 0;
        List<RelDataTypeField> leftFields = null;
        List<RelDataTypeField> rightFields = null;
        boolean reverse = false;
        call = collapseExpandedIsNotDistinctFromExpr(call, 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) {
                if (reverse) {
                    kind = kind.reverse();
                }
                rangeOp.add(op(kind, call.getOperator()));
            }
            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) RelDataType(org.apache.calcite.rel.type.RelDataType) SqlKind(org.apache.calcite.sql.SqlKind) 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 27 with RexCall

use of org.apache.calcite.rex.RexCall 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 node, int leftCount, int rightCount, List<RexNode> extraLeftExprs, List<RexNode> extraRightExprs) {
    switch(node.getKind()) {
        case AND:
        case EQUALS:
            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);
                final int left2 = leftCount + extraLeftExprs.size();
                final int right2 = rightCount + extraRightExprs.size();
                final RexNode e = pushDownEqualJoinConditions(operand, leftCount, rightCount, extraLeftExprs, extraRightExprs);
                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:
            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) RexNode(org.apache.calcite.rex.RexNode)

Example 28 with RexCall

use of org.apache.calcite.rex.RexCall in project calcite by apache.

the class RelOptUtil method splitCorrelatedFilterCondition.

private static void splitCorrelatedFilterCondition(LogicalFilter filter, RexNode condition, List<RexInputRef> joinKeys, List<RexNode> correlatedJoinKeys, List<RexNode> nonEquiList) {
    if (condition instanceof RexCall) {
        RexCall call = (RexCall) condition;
        if (call.getOperator().getKind() == SqlKind.AND) {
            for (RexNode operand : call.getOperands()) {
                splitCorrelatedFilterCondition(filter, operand, joinKeys, correlatedJoinKeys, nonEquiList);
            }
            return;
        }
        if (call.getOperator().getKind() == SqlKind.EQUALS) {
            final List<RexNode> operands = call.getOperands();
            RexNode op0 = operands.get(0);
            RexNode op1 = operands.get(1);
            if (!(RexUtil.containsInputRef(op0)) && (op1 instanceof RexInputRef)) {
                correlatedJoinKeys.add(op0);
                joinKeys.add((RexInputRef) op1);
                return;
            } else if ((op0 instanceof RexInputRef) && !(RexUtil.containsInputRef(op1))) {
                joinKeys.add((RexInputRef) op0);
                correlatedJoinKeys.add(op1);
                return;
            }
        }
    }
    // 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 : RexCall(org.apache.calcite.rex.RexCall) RexInputRef(org.apache.calcite.rex.RexInputRef) RexNode(org.apache.calcite.rex.RexNode)

Example 29 with RexCall

use of org.apache.calcite.rex.RexCall in project calcite by apache.

the class RelOptUtil method decomposeConjunction.

/**
 * Decomposes a predicate into a list of expressions that are AND'ed
 * together, and a list of expressions that are preceded by NOT.
 *
 * <p>For example, {@code a AND NOT b AND NOT (c and d) AND TRUE AND NOT
 * FALSE} returns {@code rexList = [a], notList = [b, c AND d]}.</p>
 *
 * <p>TRUE and NOT FALSE expressions are ignored. FALSE and NOT TRUE
 * expressions are placed on {@code rexList} and {@code notList} as other
 * expressions.</p>
 *
 * <p>For example, {@code a AND TRUE AND NOT TRUE} returns
 * {@code rexList = [a], notList = [TRUE]}.</p>
 *
 * @param rexPredicate predicate to be analyzed
 * @param rexList      list of decomposed RexNodes (except those with NOT)
 * @param notList      list of decomposed RexNodes that were prefixed NOT
 */
public static void decomposeConjunction(RexNode rexPredicate, List<RexNode> rexList, List<RexNode> notList) {
    if (rexPredicate == null || rexPredicate.isAlwaysTrue()) {
        return;
    }
    switch(rexPredicate.getKind()) {
        case AND:
            for (RexNode operand : ((RexCall) rexPredicate).getOperands()) {
                decomposeConjunction(operand, rexList, notList);
            }
            break;
        case NOT:
            final RexNode e = ((RexCall) rexPredicate).getOperands().get(0);
            if (e.isAlwaysFalse()) {
                return;
            }
            switch(e.getKind()) {
                case OR:
                    final List<RexNode> ors = new ArrayList<>();
                    decomposeDisjunction(e, ors);
                    for (RexNode or : ors) {
                        switch(or.getKind()) {
                            case NOT:
                                rexList.add(((RexCall) or).operands.get(0));
                                break;
                            default:
                                notList.add(or);
                        }
                    }
                    break;
                default:
                    notList.add(e);
            }
            break;
        case LITERAL:
            if (!RexLiteral.isNullLiteral(rexPredicate) && RexLiteral.booleanValue(rexPredicate)) {
                // ignore TRUE
                return;
            }
        // fall through
        default:
            rexList.add(rexPredicate);
            break;
    }
}
Also used : RexCall(org.apache.calcite.rex.RexCall) ArrayList(java.util.ArrayList) RexNode(org.apache.calcite.rex.RexNode)

Example 30 with RexCall

use of org.apache.calcite.rex.RexCall in project calcite by apache.

the class RelOptUtil method splitCorrelatedFilterCondition.

private static void splitCorrelatedFilterCondition(LogicalFilter filter, RexNode condition, List<RexNode> joinKeys, List<RexNode> correlatedJoinKeys, List<RexNode> nonEquiList, boolean extractCorrelatedFieldAccess) {
    if (condition instanceof RexCall) {
        RexCall call = (RexCall) condition;
        if (call.getOperator().getKind() == SqlKind.AND) {
            for (RexNode operand : call.getOperands()) {
                splitCorrelatedFilterCondition(filter, operand, joinKeys, correlatedJoinKeys, nonEquiList, extractCorrelatedFieldAccess);
            }
            return;
        }
        if (call.getOperator().getKind() == SqlKind.EQUALS) {
            final List<RexNode> operands = call.getOperands();
            RexNode op0 = operands.get(0);
            RexNode op1 = operands.get(1);
            if (extractCorrelatedFieldAccess) {
                if (!RexUtil.containsFieldAccess(op0) && (op1 instanceof RexFieldAccess)) {
                    joinKeys.add(op0);
                    correlatedJoinKeys.add(op1);
                    return;
                } else if ((op0 instanceof RexFieldAccess) && !RexUtil.containsFieldAccess(op1)) {
                    correlatedJoinKeys.add(op0);
                    joinKeys.add(op1);
                    return;
                }
            } else {
                if (!(RexUtil.containsInputRef(op0)) && (op1 instanceof RexInputRef)) {
                    correlatedJoinKeys.add(op0);
                    joinKeys.add(op1);
                    return;
                } else if ((op0 instanceof RexInputRef) && !(RexUtil.containsInputRef(op1))) {
                    joinKeys.add(op0);
                    correlatedJoinKeys.add(op1);
                    return;
                }
            }
        }
    }
    // 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 : RexCall(org.apache.calcite.rex.RexCall) RexInputRef(org.apache.calcite.rex.RexInputRef) RexFieldAccess(org.apache.calcite.rex.RexFieldAccess) RexNode(org.apache.calcite.rex.RexNode)

Aggregations

RexCall (org.apache.calcite.rex.RexCall)213 RexNode (org.apache.calcite.rex.RexNode)172 RexInputRef (org.apache.calcite.rex.RexInputRef)61 ArrayList (java.util.ArrayList)59 RexLiteral (org.apache.calcite.rex.RexLiteral)44 Nullable (javax.annotation.Nullable)35 RelNode (org.apache.calcite.rel.RelNode)26 RelDataType (org.apache.calcite.rel.type.RelDataType)24 SqlOperator (org.apache.calcite.sql.SqlOperator)23 List (java.util.List)22 RexBuilder (org.apache.calcite.rex.RexBuilder)22 DruidExpression (org.apache.druid.sql.calcite.expression.DruidExpression)19 SqlKind (org.apache.calcite.sql.SqlKind)14 ImmutableBitSet (org.apache.calcite.util.ImmutableBitSet)14 RelOptUtil (org.apache.calcite.plan.RelOptUtil)11 PostAggregator (org.apache.druid.query.aggregation.PostAggregator)11 RexCall (org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexCall)10 RexTableInputRef (org.apache.calcite.rex.RexTableInputRef)10 TimeUnitRange (org.apache.calcite.avatica.util.TimeUnitRange)9 RelDataTypeField (org.apache.calcite.rel.type.RelDataTypeField)9