Search in sources :

Example 41 with RexCall

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

the class DruidJsonFilter method toBoundDruidFilter.

/**
 * @param rexNode    rexNode to translate
 * @param rowType    row type associated to Filter
 * @param druidQuery druid query
 *
 * @return valid Druid Json Bound Filter or null if it can not translate the rexNode.
 */
@Nullable
private static DruidJsonFilter toBoundDruidFilter(RexNode rexNode, RelDataType rowType, DruidQuery druidQuery) {
    final RexCall rexCall = (RexCall) rexNode;
    final RexLiteral rexLiteral;
    if (rexCall.getOperands().size() < 2) {
        return null;
    }
    final RexNode refNode;
    final RexNode lhs = rexCall.getOperands().get(0);
    final RexNode rhs = rexCall.getOperands().get(1);
    final boolean lhsIsRef;
    if (lhs.getKind() == SqlKind.LITERAL && rhs.getKind() != SqlKind.LITERAL) {
        rexLiteral = (RexLiteral) lhs;
        refNode = rhs;
        lhsIsRef = false;
    } else if (rhs.getKind() == SqlKind.LITERAL && lhs.getKind() != SqlKind.LITERAL) {
        rexLiteral = (RexLiteral) rhs;
        refNode = lhs;
        lhsIsRef = true;
    } else {
        // must have at least one literal
        return null;
    }
    if (RexLiteral.isNullLiteral(rexLiteral)) {
        // we are not handling is NULL filter here thus we bail out if Literal is null
        return null;
    }
    final String literalValue = DruidJsonFilter.toDruidLiteral(rexLiteral, rowType, druidQuery);
    if (literalValue == null) {
        // can not translate literal better bail out
        return null;
    }
    final boolean isNumeric = refNode.getType().getFamily() == SqlTypeFamily.NUMERIC || rexLiteral.getType().getFamily() == SqlTypeFamily.NUMERIC;
    final Pair<String, ExtractionFunction> druidColumn = DruidQuery.toDruidColumn(refNode, rowType, druidQuery);
    final String columnName = druidColumn.left;
    final ExtractionFunction extractionFunction = druidColumn.right;
    if (columnName == null) {
        // no column name better bail out.
        return null;
    }
    switch(rexCall.getKind()) {
        case LESS_THAN_OR_EQUAL:
        case LESS_THAN:
            if (lhsIsRef) {
                return new JsonBound(columnName, null, false, literalValue, rexCall.getKind() == SqlKind.LESS_THAN, isNumeric, extractionFunction);
            } else {
                return new JsonBound(columnName, literalValue, rexCall.getKind() == SqlKind.LESS_THAN, null, false, isNumeric, extractionFunction);
            }
        case GREATER_THAN_OR_EQUAL:
        case GREATER_THAN:
            if (!lhsIsRef) {
                return new JsonBound(columnName, null, false, literalValue, rexCall.getKind() == SqlKind.GREATER_THAN, isNumeric, extractionFunction);
            } else {
                return new JsonBound(columnName, literalValue, rexCall.getKind() == SqlKind.GREATER_THAN, null, false, isNumeric, extractionFunction);
            }
        default:
            return null;
    }
}
Also used : RexCall(org.apache.calcite.rex.RexCall) RexLiteral(org.apache.calcite.rex.RexLiteral) TimestampString(org.apache.calcite.util.TimestampString) RexNode(org.apache.calcite.rex.RexNode) Nullable(javax.annotation.Nullable)

Example 42 with RexCall

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

the class DruidJsonFilter method toBetweenDruidFilter.

@Nullable
private static DruidJsonFilter toBetweenDruidFilter(RexNode rexNode, RelDataType rowType, DruidQuery query) {
    if (rexNode.getKind() != SqlKind.BETWEEN) {
        return null;
    }
    final RexCall rexCall = (RexCall) rexNode;
    if (rexCall.getOperands().size() < 4) {
        return null;
    }
    // BETWEEN (ASYMMETRIC, REF, 'lower-bound', 'upper-bound')
    final RexNode refNode = rexCall.getOperands().get(1);
    final RexNode lhs = rexCall.getOperands().get(2);
    final RexNode rhs = rexCall.getOperands().get(3);
    final String lhsLiteralValue = toDruidLiteral(lhs, rowType, query);
    final String rhsLiteralValue = toDruidLiteral(rhs, rowType, query);
    if (lhsLiteralValue == null || rhsLiteralValue == null) {
        return null;
    }
    final boolean isNumeric = lhs.getType().getFamily() == SqlTypeFamily.NUMERIC || lhs.getType().getFamily() == SqlTypeFamily.NUMERIC;
    final Pair<String, ExtractionFunction> druidColumn = DruidQuery.toDruidColumn(refNode, rowType, query);
    final String columnName = druidColumn.left;
    final ExtractionFunction extractionFunction = druidColumn.right;
    if (columnName == null) {
        return null;
    }
    return new JsonBound(columnName, lhsLiteralValue, false, rhsLiteralValue, false, isNumeric, extractionFunction);
}
Also used : RexCall(org.apache.calcite.rex.RexCall) TimestampString(org.apache.calcite.util.TimestampString) RexNode(org.apache.calcite.rex.RexNode) Nullable(javax.annotation.Nullable)

Example 43 with RexCall

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

the class DruidJsonFilter method toEqualityKindDruidFilter.

/**
 * @param rexNode    rexNode to translate to Druid Json Filter
 * @param rowType    rowType associated to rexNode
 * @param druidQuery druid query
 *
 * @return Druid Json filter or null if it can not translate
 */
@Nullable
private static DruidJsonFilter toEqualityKindDruidFilter(RexNode rexNode, RelDataType rowType, DruidQuery druidQuery) {
    if (rexNode.getKind() != SqlKind.EQUALS && rexNode.getKind() != SqlKind.NOT_EQUALS) {
        throw new AssertionError(DruidQuery.format("Expecting EQUALS or NOT_EQUALS but got [%s]", rexNode.getKind()));
    }
    final RexCall rexCall = (RexCall) rexNode;
    if (rexCall.getOperands().size() < 2) {
        return null;
    }
    final RexLiteral rexLiteral;
    final RexNode refNode;
    final RexNode lhs = rexCall.getOperands().get(0);
    final RexNode rhs = rexCall.getOperands().get(1);
    if (lhs.getKind() == SqlKind.LITERAL && rhs.getKind() != SqlKind.LITERAL) {
        rexLiteral = (RexLiteral) lhs;
        refNode = rhs;
    } else if (rhs.getKind() == SqlKind.LITERAL && lhs.getKind() != SqlKind.LITERAL) {
        rexLiteral = (RexLiteral) rhs;
        refNode = lhs;
    } else {
        // must have at least one literal
        return null;
    }
    if (RexLiteral.isNullLiteral(rexLiteral)) {
        // we are not handling is NULL filter here thus we bail out if Literal is null
        return null;
    }
    final String literalValue = toDruidLiteral(rexLiteral, rowType, druidQuery);
    if (literalValue == null) {
        // can not translate literal better bail out
        return null;
    }
    final boolean isNumeric = refNode.getType().getFamily() == SqlTypeFamily.NUMERIC || rexLiteral.getType().getFamily() == SqlTypeFamily.NUMERIC;
    final Pair<String, ExtractionFunction> druidColumn = DruidQuery.toDruidColumn(refNode, rowType, druidQuery);
    final String columnName = druidColumn.left;
    final ExtractionFunction extractionFunction = druidColumn.right;
    if (columnName == null) {
        // no column name better bail out.
        return null;
    }
    final DruidJsonFilter partialFilter;
    if (isNumeric) {
        // need bound filter since it one of operands is numeric
        partialFilter = new JsonBound(columnName, literalValue, false, literalValue, false, true, extractionFunction);
    } else {
        partialFilter = new JsonSelector(columnName, literalValue, extractionFunction);
    }
    if (rexNode.getKind() == SqlKind.EQUALS) {
        return partialFilter;
    }
    return toNotDruidFilter(partialFilter);
}
Also used : RexCall(org.apache.calcite.rex.RexCall) RexLiteral(org.apache.calcite.rex.RexLiteral) TimestampString(org.apache.calcite.util.TimestampString) RexNode(org.apache.calcite.rex.RexNode) Nullable(javax.annotation.Nullable)

Example 44 with RexCall

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

the class DruidJsonFilter method toDruidFilters.

/**
 * @param rexNode    rexNode to translate to Druid Filter
 * @param rowType    rowType of filter input
 * @param druidQuery Druid query
 *
 * @return Druid Json Filters or null when can not translate to valid Druid Filters.
 */
@Nullable
static DruidJsonFilter toDruidFilters(final RexNode rexNode, RelDataType rowType, DruidQuery druidQuery) {
    if (rexNode.isAlwaysTrue()) {
        return JsonExpressionFilter.alwaysTrue();
    }
    if (rexNode.isAlwaysFalse()) {
        return JsonExpressionFilter.alwaysFalse();
    }
    switch(rexNode.getKind()) {
        case IS_TRUE:
        case IS_NOT_FALSE:
            return toDruidFilters(Iterables.getOnlyElement(((RexCall) rexNode).getOperands()), rowType, druidQuery);
        case IS_NOT_TRUE:
        case IS_FALSE:
            final DruidJsonFilter simpleFilter = toDruidFilters(Iterables.getOnlyElement(((RexCall) rexNode).getOperands()), rowType, druidQuery);
            return simpleFilter != null ? new JsonCompositeFilter(Type.NOT, simpleFilter) : simpleFilter;
        case AND:
        case OR:
        case NOT:
            final RexCall call = (RexCall) rexNode;
            final List<DruidJsonFilter> jsonFilters = Lists.newArrayList();
            for (final RexNode e : call.getOperands()) {
                final DruidJsonFilter druidFilter = toDruidFilters(e, rowType, druidQuery);
                if (druidFilter == null) {
                    return null;
                }
                jsonFilters.add(druidFilter);
            }
            return new JsonCompositeFilter(Type.valueOf(rexNode.getKind().name()), jsonFilters);
    }
    final DruidJsonFilter simpleLeafFilter = toSimpleDruidFilter(rexNode, rowType, druidQuery);
    return simpleLeafFilter == null ? toDruidExpressionFilter(rexNode, rowType, druidQuery) : simpleLeafFilter;
}
Also used : RexCall(org.apache.calcite.rex.RexCall) RexNode(org.apache.calcite.rex.RexNode) Nullable(javax.annotation.Nullable)

Example 45 with RexCall

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

the class ProjectWindowTransposeRule method onMatch.

@Override
public void onMatch(RelOptRuleCall call) {
    final LogicalProject project = call.rel(0);
    final LogicalWindow window = call.rel(1);
    final RelOptCluster cluster = window.getCluster();
    final List<RelDataTypeField> rowTypeWindowInput = window.getInput().getRowType().getFieldList();
    final int windowInputColumn = rowTypeWindowInput.size();
    // Record the window input columns which are actually referred
    // either in the LogicalProject above LogicalWindow or LogicalWindow itself
    // (Note that the constants used in LogicalWindow are not considered here)
    final ImmutableBitSet beReferred = findReference(project, window);
    // it is impossible to trim anyone of them out
    if (beReferred.cardinality() == windowInputColumn) {
        return;
    }
    // Put a DrillProjectRel below LogicalWindow
    final List<RexNode> exps = new ArrayList<>();
    final RelDataTypeFactory.Builder builder = cluster.getTypeFactory().builder();
    // Keep only the fields which are referred
    for (int index : BitSets.toIter(beReferred)) {
        final RelDataTypeField relDataTypeField = rowTypeWindowInput.get(index);
        exps.add(new RexInputRef(index, relDataTypeField.getType()));
        builder.add(relDataTypeField);
    }
    final LogicalProject projectBelowWindow = new LogicalProject(cluster, window.getTraitSet(), window.getInput(), exps, builder.build());
    // Create a new LogicalWindow with necessary inputs only
    final List<Window.Group> groups = new ArrayList<>();
    // As the un-referred columns are trimmed by the LogicalProject,
    // the indices specified in LogicalWindow would need to be adjusted
    final RexShuttle indexAdjustment = new RexShuttle() {

        @Override
        public RexNode visitInputRef(RexInputRef inputRef) {
            final int newIndex = getAdjustedIndex(inputRef.getIndex(), beReferred, windowInputColumn);
            return new RexInputRef(newIndex, inputRef.getType());
        }

        @Override
        public RexNode visitCall(final RexCall call) {
            if (call instanceof Window.RexWinAggCall) {
                boolean[] update = { false };
                final List<RexNode> clonedOperands = visitList(call.operands, update);
                if (update[0]) {
                    return new Window.RexWinAggCall((SqlAggFunction) call.getOperator(), call.getType(), clonedOperands, ((Window.RexWinAggCall) call).ordinal, ((Window.RexWinAggCall) call).distinct);
                } else {
                    return call;
                }
            } else {
                return super.visitCall(call);
            }
        }
    };
    int aggCallIndex = windowInputColumn;
    final RelDataTypeFactory.Builder outputBuilder = cluster.getTypeFactory().builder();
    outputBuilder.addAll(projectBelowWindow.getRowType().getFieldList());
    for (Window.Group group : window.groups) {
        final ImmutableBitSet.Builder keys = ImmutableBitSet.builder();
        final List<RelFieldCollation> orderKeys = new ArrayList<>();
        final List<Window.RexWinAggCall> aggCalls = new ArrayList<>();
        // Adjust keys
        for (int index : group.keys) {
            keys.set(getAdjustedIndex(index, beReferred, windowInputColumn));
        }
        // Adjust orderKeys
        for (RelFieldCollation relFieldCollation : group.orderKeys.getFieldCollations()) {
            final int index = relFieldCollation.getFieldIndex();
            orderKeys.add(relFieldCollation.copy(getAdjustedIndex(index, beReferred, windowInputColumn)));
        }
        // Adjust Window Functions
        for (Window.RexWinAggCall rexWinAggCall : group.aggCalls) {
            aggCalls.add((Window.RexWinAggCall) rexWinAggCall.accept(indexAdjustment));
            final RelDataTypeField relDataTypeField = window.getRowType().getFieldList().get(aggCallIndex);
            outputBuilder.add(relDataTypeField);
            ++aggCallIndex;
        }
        groups.add(new Window.Group(keys.build(), group.isRows, group.lowerBound, group.upperBound, RelCollations.of(orderKeys), aggCalls));
    }
    final LogicalWindow newLogicalWindow = LogicalWindow.create(window.getTraitSet(), projectBelowWindow, window.constants, outputBuilder.build(), groups);
    // Modify the top LogicalProject
    final List<RexNode> topProjExps = new ArrayList<>();
    for (RexNode rexNode : project.getChildExps()) {
        topProjExps.add(rexNode.accept(indexAdjustment));
    }
    final LogicalProject newTopProj = project.copy(newLogicalWindow.getTraitSet(), newLogicalWindow, topProjExps, project.getRowType());
    if (ProjectRemoveRule.isTrivial(newTopProj)) {
        call.transformTo(newLogicalWindow);
    } else {
        call.transformTo(newTopProj);
    }
}
Also used : RelOptCluster(org.apache.calcite.plan.RelOptCluster) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) ArrayList(java.util.ArrayList) RexCall(org.apache.calcite.rex.RexCall) LogicalWindow(org.apache.calcite.rel.logical.LogicalWindow) RelDataTypeFactory(org.apache.calcite.rel.type.RelDataTypeFactory) Window(org.apache.calcite.rel.core.Window) LogicalWindow(org.apache.calcite.rel.logical.LogicalWindow) RexShuttle(org.apache.calcite.rex.RexShuttle) RelDataTypeField(org.apache.calcite.rel.type.RelDataTypeField) RelFieldCollation(org.apache.calcite.rel.RelFieldCollation) RexInputRef(org.apache.calcite.rex.RexInputRef) LogicalProject(org.apache.calcite.rel.logical.LogicalProject) 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