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;
}
}
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);
}
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);
}
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;
}
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);
}
}
Aggregations