Search in sources :

Example 1 with RexCall

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

the class HivePreFilteringRule method extractCommonOperands.

private static List<RexNode> extractCommonOperands(RexBuilder rexBuilder, RexNode condition, int maxCNFNodeCount) {
    assert condition.getKind() == SqlKind.OR;
    Multimap<String, RexNode> reductionCondition = LinkedHashMultimap.create();
    // Data structure to control whether a certain reference is present in every
    // operand
    Set<String> refsInAllOperands = null;
    // 1. We extract the information necessary to create the predicate for the
    // new filter; currently we support comparison functions, in and between
    ImmutableList<RexNode> operands = RexUtil.flattenOr(((RexCall) condition).getOperands());
    for (int i = 0; i < operands.size(); i++) {
        final RexNode operand = operands.get(i);
        final RexNode operandCNF = RexUtil.toCnf(rexBuilder, maxCNFNodeCount, operand);
        final List<RexNode> conjunctions = RelOptUtil.conjunctions(operandCNF);
        Set<String> refsInCurrentOperand = Sets.newHashSet();
        for (RexNode conjunction : conjunctions) {
            // We do not know what it is, we bail out for safety
            if (!(conjunction instanceof RexCall) || !HiveCalciteUtil.isDeterministic(conjunction)) {
                return new ArrayList<>();
            }
            RexCall conjCall = (RexCall) conjunction;
            RexNode ref = null;
            if (COMPARISON.contains(conjCall.getOperator().getKind())) {
                if (conjCall.operands.get(0) instanceof RexInputRef && conjCall.operands.get(1) instanceof RexLiteral) {
                    ref = conjCall.operands.get(0);
                } else if (conjCall.operands.get(1) instanceof RexInputRef && conjCall.operands.get(0) instanceof RexLiteral) {
                    ref = conjCall.operands.get(1);
                } else {
                    // We do not know what it is, we bail out for safety
                    return new ArrayList<>();
                }
            } else if (conjCall.getOperator().getKind().equals(SqlKind.IN)) {
                ref = conjCall.operands.get(0);
            } else if (conjCall.getOperator().getKind().equals(SqlKind.BETWEEN)) {
                ref = conjCall.operands.get(1);
            } else {
                // We do not know what it is, we bail out for safety
                return new ArrayList<>();
            }
            String stringRef = ref.toString();
            reductionCondition.put(stringRef, conjCall);
            refsInCurrentOperand.add(stringRef);
        }
        // Updates the references that are present in every operand up till now
        if (i == 0) {
            refsInAllOperands = refsInCurrentOperand;
        } else {
            refsInAllOperands = Sets.intersection(refsInAllOperands, refsInCurrentOperand);
        }
        // bail out
        if (refsInAllOperands.isEmpty()) {
            return new ArrayList<>();
        }
    }
    // 2. We gather the common factors and return them
    List<RexNode> commonOperands = new ArrayList<>();
    for (String ref : refsInAllOperands) {
        commonOperands.add(RexUtil.composeDisjunction(rexBuilder, reductionCondition.get(ref), false));
    }
    return commonOperands;
}
Also used : RexCall(org.apache.calcite.rex.RexCall) RexLiteral(org.apache.calcite.rex.RexLiteral) ArrayList(java.util.ArrayList) RexInputRef(org.apache.calcite.rex.RexInputRef) RexNode(org.apache.calcite.rex.RexNode)

Example 2 with RexCall

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

the class HiveFilterJoinRule method validateJoinFilters.

/*
   * Any predicates pushed down to joinFilters that aren't equality conditions:
   * put them back as aboveFilters because Hive doesn't support not equi join
   * conditions.
   */
@Override
protected void validateJoinFilters(List<RexNode> aboveFilters, List<RexNode> joinFilters, Join join, JoinRelType joinType) {
    if (joinType.equals(JoinRelType.INNER)) {
        ListIterator<RexNode> filterIter = joinFilters.listIterator();
        while (filterIter.hasNext()) {
            RexNode exp = filterIter.next();
            if (exp instanceof RexCall) {
                RexCall c = (RexCall) exp;
                boolean validHiveJoinFilter = false;
                if ((c.getOperator().getKind() == SqlKind.EQUALS)) {
                    validHiveJoinFilter = true;
                    for (RexNode rn : c.getOperands()) {
                        // (r1.x +r2.x)=(r1.y+r2.y) on join condition.
                        if (filterRefersToBothSidesOfJoin(rn, join)) {
                            validHiveJoinFilter = false;
                            break;
                        }
                    }
                } else if ((c.getOperator().getKind() == SqlKind.LESS_THAN) || (c.getOperator().getKind() == SqlKind.GREATER_THAN) || (c.getOperator().getKind() == SqlKind.LESS_THAN_OR_EQUAL) || (c.getOperator().getKind() == SqlKind.GREATER_THAN_OR_EQUAL)) {
                    validHiveJoinFilter = true;
                    // r2.x) on join condition.
                    if (filterRefersToBothSidesOfJoin(c, join)) {
                        validHiveJoinFilter = false;
                    }
                }
                if (validHiveJoinFilter)
                    continue;
            }
            aboveFilters.add(exp);
            filterIter.remove();
        }
    }
}
Also used : RexCall(org.apache.calcite.rex.RexCall) RexNode(org.apache.calcite.rex.RexNode)

Example 3 with RexCall

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

the class FlinkAggregateJoinTransposeRule method populateEquivalences.

private static void populateEquivalences(Map<Integer, BitSet> equivalence, RexNode predicate) {
    switch(predicate.getKind()) {
        case EQUALS:
            RexCall call = (RexCall) predicate;
            final List<RexNode> operands = call.getOperands();
            if (operands.get(0) instanceof RexInputRef) {
                final RexInputRef ref0 = (RexInputRef) operands.get(0);
                if (operands.get(1) instanceof RexInputRef) {
                    final RexInputRef ref1 = (RexInputRef) operands.get(1);
                    populateEquivalence(equivalence, ref0.getIndex(), ref1.getIndex());
                    populateEquivalence(equivalence, ref1.getIndex(), ref0.getIndex());
                }
            }
    }
}
Also used : RexCall(org.apache.calcite.rex.RexCall) RexInputRef(org.apache.calcite.rex.RexInputRef) RexNode(org.apache.calcite.rex.RexNode)

Example 4 with RexCall

use of org.apache.calcite.rex.RexCall in project druid by druid-io.

the class GroupByRules method translateAggregateCall.

/**
   * Translate an AggregateCall to Druid equivalents.
   *
   * @return translated aggregation, or null if translation failed.
   */
private static Aggregation translateAggregateCall(final PlannerContext plannerContext, final RowSignature sourceRowSignature, final Project project, final AggregateCall call, final DruidOperatorTable operatorTable, final List<Aggregation> existingAggregations, final int aggNumber, final boolean approximateCountDistinct) {
    final List<DimFilter> filters = Lists.newArrayList();
    final List<String> rowOrder = sourceRowSignature.getRowOrder();
    final String name = aggOutputName(aggNumber);
    final SqlKind kind = call.getAggregation().getKind();
    final SqlTypeName outputType = call.getType().getSqlTypeName();
    if (call.filterArg >= 0) {
        // AGG(xxx) FILTER(WHERE yyy)
        if (project == null) {
            // We need some kind of projection to support filtered aggregations.
            return null;
        }
        final RexNode expression = project.getChildExps().get(call.filterArg);
        final DimFilter filter = Expressions.toFilter(operatorTable, plannerContext, sourceRowSignature, expression);
        if (filter == null) {
            return null;
        }
        filters.add(filter);
    }
    if (kind == SqlKind.COUNT && call.getArgList().isEmpty()) {
        // COUNT(*)
        return Aggregation.create(new CountAggregatorFactory(name)).filter(makeFilter(filters, sourceRowSignature));
    } else if (kind == SqlKind.COUNT && call.isDistinct()) {
        // COUNT(DISTINCT x)
        return approximateCountDistinct ? APPROX_COUNT_DISTINCT.toDruidAggregation(name, sourceRowSignature, operatorTable, plannerContext, existingAggregations, project, call, makeFilter(filters, sourceRowSignature)) : null;
    } else if (kind == SqlKind.COUNT || kind == SqlKind.SUM || kind == SqlKind.SUM0 || kind == SqlKind.MIN || kind == SqlKind.MAX || kind == SqlKind.AVG) {
        // Built-in agg, not distinct, not COUNT(*)
        boolean forceCount = false;
        final FieldOrExpression input;
        final int inputField = Iterables.getOnlyElement(call.getArgList());
        final RexNode rexNode = Expressions.fromFieldAccess(sourceRowSignature, project, inputField);
        final FieldOrExpression foe = FieldOrExpression.fromRexNode(operatorTable, plannerContext, rowOrder, rexNode);
        if (foe != null) {
            input = foe;
        } else if (rexNode.getKind() == SqlKind.CASE && ((RexCall) rexNode).getOperands().size() == 3) {
            // Possibly a CASE-style filtered aggregation. Styles supported:
            // A: SUM(CASE WHEN x = 'foo' THEN cnt END) => operands (x = 'foo', cnt, null)
            // B: SUM(CASE WHEN x = 'foo' THEN 1 ELSE 0 END) => operands (x = 'foo', 1, 0)
            // C: COUNT(CASE WHEN x = 'foo' THEN 'dummy' END) => operands (x = 'foo', 'dummy', null)
            // If the null and non-null args are switched, "flip" is set, which negates the filter.
            final RexCall caseCall = (RexCall) rexNode;
            final boolean flip = RexLiteral.isNullLiteral(caseCall.getOperands().get(1)) && !RexLiteral.isNullLiteral(caseCall.getOperands().get(2));
            final RexNode arg1 = caseCall.getOperands().get(flip ? 2 : 1);
            final RexNode arg2 = caseCall.getOperands().get(flip ? 1 : 2);
            // Operand 1: Filter
            final DimFilter filter = Expressions.toFilter(operatorTable, plannerContext, sourceRowSignature, caseCall.getOperands().get(0));
            if (filter == null) {
                return null;
            } else {
                filters.add(flip ? new NotDimFilter(filter) : filter);
            }
            if (call.getAggregation().getKind() == SqlKind.COUNT && arg1 instanceof RexLiteral && !RexLiteral.isNullLiteral(arg1) && RexLiteral.isNullLiteral(arg2)) {
                // Case C
                forceCount = true;
                input = null;
            } else if (call.getAggregation().getKind() == SqlKind.SUM && arg1 instanceof RexLiteral && ((Number) RexLiteral.value(arg1)).intValue() == 1 && arg2 instanceof RexLiteral && ((Number) RexLiteral.value(arg2)).intValue() == 0) {
                // Case B
                forceCount = true;
                input = null;
            } else if (RexLiteral.isNullLiteral(arg2)) {
                // Maybe case A
                input = FieldOrExpression.fromRexNode(operatorTable, plannerContext, rowOrder, arg1);
                if (input == null) {
                    return null;
                }
            } else {
                // Can't translate CASE into a filter.
                return null;
            }
        } else {
            // Can't translate operand.
            return null;
        }
        if (!forceCount) {
            Preconditions.checkNotNull(input, "WTF?! input was null for non-COUNT aggregation");
        }
        if (forceCount || kind == SqlKind.COUNT) {
            // COUNT(x)
            return Aggregation.create(new CountAggregatorFactory(name)).filter(makeFilter(filters, sourceRowSignature));
        } else {
            // Built-in aggregator that is not COUNT.
            final Aggregation retVal;
            final String fieldName = input.getFieldName();
            final String expression = input.getExpression();
            final boolean isLong = SqlTypeName.INT_TYPES.contains(outputType) || SqlTypeName.TIMESTAMP == outputType || SqlTypeName.DATE == outputType;
            if (kind == SqlKind.SUM || kind == SqlKind.SUM0) {
                retVal = isLong ? Aggregation.create(new LongSumAggregatorFactory(name, fieldName, expression)) : Aggregation.create(new DoubleSumAggregatorFactory(name, fieldName, expression));
            } else if (kind == SqlKind.MIN) {
                retVal = isLong ? Aggregation.create(new LongMinAggregatorFactory(name, fieldName, expression)) : Aggregation.create(new DoubleMinAggregatorFactory(name, fieldName, expression));
            } else if (kind == SqlKind.MAX) {
                retVal = isLong ? Aggregation.create(new LongMaxAggregatorFactory(name, fieldName, expression)) : Aggregation.create(new DoubleMaxAggregatorFactory(name, fieldName, expression));
            } else if (kind == SqlKind.AVG) {
                final String sumName = aggInternalName(aggNumber, "sum");
                final String countName = aggInternalName(aggNumber, "count");
                final AggregatorFactory sum = isLong ? new LongSumAggregatorFactory(sumName, fieldName, expression) : new DoubleSumAggregatorFactory(sumName, fieldName, expression);
                final AggregatorFactory count = new CountAggregatorFactory(countName);
                retVal = Aggregation.create(ImmutableList.of(sum, count), new ArithmeticPostAggregator(name, "quotient", ImmutableList.<PostAggregator>of(new FieldAccessPostAggregator(null, sumName), new FieldAccessPostAggregator(null, countName))));
            } else {
                // Not reached.
                throw new ISE("WTF?! Kind[%s] got into the built-in aggregator path somehow?!", kind);
            }
            return retVal.filter(makeFilter(filters, sourceRowSignature));
        }
    } else {
        // Not a built-in aggregator, check operator table.
        final SqlAggregator sqlAggregator = operatorTable.lookupAggregator(call.getAggregation().getName());
        return sqlAggregator != null ? sqlAggregator.toDruidAggregation(name, sourceRowSignature, operatorTable, plannerContext, existingAggregations, project, call, makeFilter(filters, sourceRowSignature)) : null;
    }
}
Also used : RexLiteral(org.apache.calcite.rex.RexLiteral) ArithmeticPostAggregator(io.druid.query.aggregation.post.ArithmeticPostAggregator) DoubleMaxAggregatorFactory(io.druid.query.aggregation.DoubleMaxAggregatorFactory) SqlTypeName(org.apache.calcite.sql.type.SqlTypeName) LongSumAggregatorFactory(io.druid.query.aggregation.LongSumAggregatorFactory) DoubleMinAggregatorFactory(io.druid.query.aggregation.DoubleMinAggregatorFactory) LongMinAggregatorFactory(io.druid.query.aggregation.LongMinAggregatorFactory) RexCall(org.apache.calcite.rex.RexCall) Aggregation(io.druid.sql.calcite.aggregation.Aggregation) ISE(io.druid.java.util.common.ISE) LongMaxAggregatorFactory(io.druid.query.aggregation.LongMaxAggregatorFactory) NotDimFilter(io.druid.query.filter.NotDimFilter) FieldAccessPostAggregator(io.druid.query.aggregation.post.FieldAccessPostAggregator) DoubleSumAggregatorFactory(io.druid.query.aggregation.DoubleSumAggregatorFactory) PostAggregator(io.druid.query.aggregation.PostAggregator) FieldAccessPostAggregator(io.druid.query.aggregation.post.FieldAccessPostAggregator) ArithmeticPostAggregator(io.druid.query.aggregation.post.ArithmeticPostAggregator) SqlKind(org.apache.calcite.sql.SqlKind) CountAggregatorFactory(io.druid.query.aggregation.CountAggregatorFactory) DoubleMaxAggregatorFactory(io.druid.query.aggregation.DoubleMaxAggregatorFactory) LongMaxAggregatorFactory(io.druid.query.aggregation.LongMaxAggregatorFactory) DoubleSumAggregatorFactory(io.druid.query.aggregation.DoubleSumAggregatorFactory) AggregatorFactory(io.druid.query.aggregation.AggregatorFactory) LongMinAggregatorFactory(io.druid.query.aggregation.LongMinAggregatorFactory) PostAggregatorFactory(io.druid.sql.calcite.aggregation.PostAggregatorFactory) DoubleMinAggregatorFactory(io.druid.query.aggregation.DoubleMinAggregatorFactory) LongSumAggregatorFactory(io.druid.query.aggregation.LongSumAggregatorFactory) CountAggregatorFactory(io.druid.query.aggregation.CountAggregatorFactory) SqlAggregator(io.druid.sql.calcite.aggregation.SqlAggregator) ApproxCountDistinctSqlAggregator(io.druid.sql.calcite.aggregation.ApproxCountDistinctSqlAggregator) DimFilter(io.druid.query.filter.DimFilter) NotDimFilter(io.druid.query.filter.NotDimFilter) AndDimFilter(io.druid.query.filter.AndDimFilter) RexNode(org.apache.calcite.rex.RexNode)

Example 5 with RexCall

use of org.apache.calcite.rex.RexCall in project druid by druid-io.

the class Expressions method toFilter.

/**
   * Translates "condition" to a Druid filter, or returns null if we cannot translate the condition.
   *
   * @param plannerContext planner context
   * @param rowSignature   row signature of the dataSource to be filtered
   * @param expression     Calcite row expression
   */
public static DimFilter toFilter(final DruidOperatorTable operatorTable, final PlannerContext plannerContext, final RowSignature rowSignature, final RexNode expression) {
    if (expression.getKind() == SqlKind.AND || expression.getKind() == SqlKind.OR || expression.getKind() == SqlKind.NOT) {
        final List<DimFilter> filters = Lists.newArrayList();
        for (final RexNode rexNode : ((RexCall) expression).getOperands()) {
            final DimFilter nextFilter = toFilter(operatorTable, plannerContext, rowSignature, rexNode);
            if (nextFilter == null) {
                return null;
            }
            filters.add(nextFilter);
        }
        if (expression.getKind() == SqlKind.AND) {
            return new AndDimFilter(filters);
        } else if (expression.getKind() == SqlKind.OR) {
            return new OrDimFilter(filters);
        } else {
            assert expression.getKind() == SqlKind.NOT;
            return new NotDimFilter(Iterables.getOnlyElement(filters));
        }
    } else {
        // Handle filter conditions on everything else.
        return toLeafFilter(operatorTable, plannerContext, rowSignature, expression);
    }
}
Also used : RexCall(org.apache.calcite.rex.RexCall) NotDimFilter(io.druid.query.filter.NotDimFilter) AndDimFilter(io.druid.query.filter.AndDimFilter) OrDimFilter(io.druid.query.filter.OrDimFilter) LikeDimFilter(io.druid.query.filter.LikeDimFilter) OrDimFilter(io.druid.query.filter.OrDimFilter) DimFilter(io.druid.query.filter.DimFilter) NotDimFilter(io.druid.query.filter.NotDimFilter) AndDimFilter(io.druid.query.filter.AndDimFilter) 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