use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.sql.SqlKind in project calcite by apache.
the class RexImplicationChecker method checkSupport.
/**
* Looks at the usage of variables in first and second conjunction to decide
* whether this kind of expression is currently supported for proving first
* implies second.
*
* <ol>
* <li>Variables should be used only once in both the conjunction against
* given set of operations only: >, <, ≤, ≥, =; ≠.
*
* <li>All the variables used in second condition should be used even in the
* first.
*
* <li>If operator used for variable in first is op1 and op2 for second, then
* we support these combination for conjunction (op1, op2) then op1, op2
* belongs to one of the following sets:
*
* <ul>
* <li>(<, ≤) X (<, ≤) <i>note: X represents cartesian product</i>
* <li>(> / ≥) X (>, ≥)
* <li>(=) X (>, ≥, <, ≤, =, ≠)
* <li>(≠, =)
* </ul>
*
* <li>We support at most 2 operators to be be used for a variable in first
* and second usages.
*
* </ol>
*
* @return whether input usage pattern is supported
*/
private boolean checkSupport(InputUsageFinder firstUsageFinder, InputUsageFinder secondUsageFinder) {
final Map<RexInputRef, InputRefUsage<SqlOperator, RexNode>> firstUsageMap = firstUsageFinder.usageMap;
final Map<RexInputRef, InputRefUsage<SqlOperator, RexNode>> secondUsageMap = secondUsageFinder.usageMap;
for (Map.Entry<RexInputRef, InputRefUsage<SqlOperator, RexNode>> entry : secondUsageMap.entrySet()) {
final InputRefUsage<SqlOperator, RexNode> secondUsage = entry.getValue();
final List<Pair<SqlOperator, RexNode>> secondUsageList = secondUsage.usageList;
final int secondLen = secondUsageList.size();
if (secondUsage.usageCount != secondLen || secondLen > 2) {
return false;
}
final InputRefUsage<SqlOperator, RexNode> firstUsage = firstUsageMap.get(entry.getKey());
if (firstUsage == null || firstUsage.usageList.size() != firstUsage.usageCount || firstUsage.usageCount > 2) {
return false;
}
final List<Pair<SqlOperator, RexNode>> firstUsageList = firstUsage.usageList;
final int firstLen = firstUsageList.size();
final SqlKind fKind = firstUsageList.get(0).getKey().getKind();
final SqlKind sKind = secondUsageList.get(0).getKey().getKind();
final SqlKind fKind2 = (firstUsageList.size() == 2) ? firstUsageList.get(1).getKey().getKind() : null;
final SqlKind sKind2 = (secondUsageList.size() == 2) ? secondUsageList.get(1).getKey().getKind() : null;
if (firstLen == 2 && secondLen == 2 && !(isEquivalentOp(fKind, sKind) && isEquivalentOp(fKind2, sKind2)) && !(isEquivalentOp(fKind, sKind2) && isEquivalentOp(fKind2, sKind))) {
return false;
} else if (firstLen == 1 && secondLen == 1 && fKind != SqlKind.EQUALS && !isSupportedUnaryOperators(sKind) && !isEquivalentOp(fKind, sKind)) {
return false;
} else if (firstLen == 1 && secondLen == 2 && fKind != SqlKind.EQUALS) {
return false;
} else if (firstLen == 2 && secondLen == 1) {
// x > 30 and x > 40 implies x < 70
if (!isOppositeOp(fKind, fKind2) && !isSupportedUnaryOperators(sKind) && !(isEquivalentOp(fKind, fKind2) && isEquivalentOp(fKind, sKind))) {
return false;
}
}
}
return true;
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.sql.SqlKind in project calcite by apache.
the class AggregateReduceFunctionsRule method reduceAgg.
private RexNode reduceAgg(Aggregate oldAggRel, AggregateCall oldCall, List<AggregateCall> newCalls, Map<AggregateCall, RexNode> aggCallMapping, List<RexNode> inputExprs) {
final SqlKind kind = oldCall.getAggregation().getKind();
if (isReducible(kind)) {
switch(kind) {
case SUM:
// case COUNT(x) when 0 then null else SUM0(x) end
return reduceSum(oldAggRel, oldCall, newCalls, aggCallMapping);
case AVG:
// replace original AVG(x) with SUM(x) / COUNT(x)
return reduceAvg(oldAggRel, oldCall, newCalls, aggCallMapping, inputExprs);
case STDDEV_POP:
// / COUNT(x))
return reduceStddev(oldAggRel, oldCall, true, true, newCalls, aggCallMapping, inputExprs);
case STDDEV_SAMP:
// / CASE COUNT(x) WHEN 1 THEN NULL ELSE COUNT(x) - 1 END)
return reduceStddev(oldAggRel, oldCall, false, true, newCalls, aggCallMapping, inputExprs);
case VAR_POP:
// / COUNT(x)
return reduceStddev(oldAggRel, oldCall, true, false, newCalls, aggCallMapping, inputExprs);
case VAR_SAMP:
// / CASE COUNT(x) WHEN 1 THEN NULL ELSE COUNT(x) - 1 END
return reduceStddev(oldAggRel, oldCall, false, false, newCalls, aggCallMapping, inputExprs);
default:
throw Util.unexpected(kind);
}
} else {
// anything else: preserve original call
RexBuilder rexBuilder = oldAggRel.getCluster().getRexBuilder();
final int nGroups = oldAggRel.getGroupCount();
List<RelDataType> oldArgTypes = SqlTypeUtil.projectTypes(oldAggRel.getInput().getRowType(), oldCall.getArgList());
return rexBuilder.addAggCall(oldCall, nGroups, oldAggRel.indicator, newCalls, aggCallMapping, oldArgTypes);
}
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.sql.SqlKind in project calcite by apache.
the class RexSimplify method simplifyNot.
private RexNode simplifyNot(RexCall call) {
final RexNode a = call.getOperands().get(0);
switch(a.getKind()) {
case NOT:
// NOT NOT x ==> x
return simplify(((RexCall) a).getOperands().get(0));
}
final SqlKind negateKind = a.getKind().negate();
if (a.getKind() != negateKind) {
return simplify(rexBuilder.makeCall(RexUtil.op(negateKind), ImmutableList.of(((RexCall) a).getOperands().get(0))));
}
final SqlKind negateKind2 = a.getKind().negateNullSafe();
if (a.getKind() != negateKind2) {
return simplify(rexBuilder.makeCall(RexUtil.op(negateKind2), ((RexCall) a).getOperands()));
}
if (a.getKind() == SqlKind.AND) {
// NOT distributivity for AND
final List<RexNode> newOperands = new ArrayList<>();
for (RexNode operand : ((RexCall) a).getOperands()) {
newOperands.add(simplify(rexBuilder.makeCall(SqlStdOperatorTable.NOT, operand)));
}
return simplify(rexBuilder.makeCall(SqlStdOperatorTable.OR, newOperands));
}
if (a.getKind() == SqlKind.OR) {
// NOT distributivity for OR
final List<RexNode> newOperands = new ArrayList<>();
for (RexNode operand : ((RexCall) a).getOperands()) {
newOperands.add(simplify(rexBuilder.makeCall(SqlStdOperatorTable.NOT, operand)));
}
return simplify(rexBuilder.makeCall(SqlStdOperatorTable.AND, newOperands));
}
return call;
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.sql.SqlKind in project druid by druid-io.
the class Expressions method toSimpleLeafFilter.
/**
* Translates to a simple leaf filter, i.e. not an "expression" type filter. Note that the filter may still
* reference expression virtual columns, if and only if "virtualColumnRegistry" is defined.
*
* @param plannerContext planner context
* @param rowSignature input row signature
* @param virtualColumnRegistry re-usable virtual column references, may be null if virtual columns aren't allowed
* @param rexNode Calcite row expression
*/
@Nullable
private static DimFilter toSimpleLeafFilter(final PlannerContext plannerContext, final RowSignature rowSignature, @Nullable final VirtualColumnRegistry virtualColumnRegistry, final RexNode rexNode) {
final SqlKind kind = rexNode.getKind();
if (kind == SqlKind.IS_TRUE || kind == SqlKind.IS_NOT_FALSE) {
return toSimpleLeafFilter(plannerContext, rowSignature, virtualColumnRegistry, Iterables.getOnlyElement(((RexCall) rexNode).getOperands()));
} else if (kind == SqlKind.IS_FALSE || kind == SqlKind.IS_NOT_TRUE) {
return new NotDimFilter(toSimpleLeafFilter(plannerContext, rowSignature, virtualColumnRegistry, Iterables.getOnlyElement(((RexCall) rexNode).getOperands())));
} else if (kind == SqlKind.IS_NULL || kind == SqlKind.IS_NOT_NULL) {
final RexNode operand = Iterables.getOnlyElement(((RexCall) rexNode).getOperands());
final DruidExpression druidExpression = toDruidExpression(plannerContext, rowSignature, operand);
if (druidExpression == null) {
return null;
}
final DimFilter equalFilter;
if (druidExpression.isSimpleExtraction()) {
equalFilter = new SelectorDimFilter(druidExpression.getSimpleExtraction().getColumn(), NullHandling.defaultStringValue(), druidExpression.getSimpleExtraction().getExtractionFn());
} else if (virtualColumnRegistry != null) {
final String virtualColumn = virtualColumnRegistry.getOrCreateVirtualColumnForExpression(druidExpression, operand.getType());
equalFilter = new SelectorDimFilter(virtualColumn, NullHandling.defaultStringValue(), null);
} else {
return null;
}
return kind == SqlKind.IS_NOT_NULL ? new NotDimFilter(equalFilter) : equalFilter;
} else if (kind == SqlKind.EQUALS || kind == SqlKind.NOT_EQUALS || kind == SqlKind.GREATER_THAN || kind == SqlKind.GREATER_THAN_OR_EQUAL || kind == SqlKind.LESS_THAN || kind == SqlKind.LESS_THAN_OR_EQUAL) {
final List<RexNode> operands = ((RexCall) rexNode).getOperands();
Preconditions.checkState(operands.size() == 2, "Expected 2 operands, got[%,d]", operands.size());
boolean flip = false;
RexNode lhs = operands.get(0);
RexNode rhs = operands.get(1);
if (lhs.getKind() == SqlKind.LITERAL && rhs.getKind() != SqlKind.LITERAL) {
// swap lhs, rhs
RexNode x = lhs;
lhs = rhs;
rhs = x;
flip = true;
}
// Flip operator, maybe.
final SqlKind flippedKind;
if (flip) {
switch(kind) {
case EQUALS:
case NOT_EQUALS:
flippedKind = kind;
break;
case GREATER_THAN:
flippedKind = SqlKind.LESS_THAN;
break;
case GREATER_THAN_OR_EQUAL:
flippedKind = SqlKind.LESS_THAN_OR_EQUAL;
break;
case LESS_THAN:
flippedKind = SqlKind.GREATER_THAN;
break;
case LESS_THAN_OR_EQUAL:
flippedKind = SqlKind.GREATER_THAN_OR_EQUAL;
break;
default:
throw new ISE("Kind[%s] not expected here", kind);
}
} else {
flippedKind = kind;
}
// rhs must be a literal
if (rhs.getKind() != SqlKind.LITERAL) {
return null;
}
// Translate lhs to a DruidExpression.
final DruidExpression lhsExpression = toDruidExpression(plannerContext, rowSignature, lhs);
if (lhsExpression == null) {
return null;
}
// Special handling for filters on FLOOR(__time TO granularity).
final Granularity queryGranularity = toQueryGranularity(lhsExpression, plannerContext.getExprMacroTable());
if (queryGranularity != null) {
// lhs is FLOOR(__time TO granularity); rhs must be a timestamp
final long rhsMillis = Calcites.calciteDateTimeLiteralToJoda(rhs, plannerContext.getTimeZone()).getMillis();
return buildTimeFloorFilter(ColumnHolder.TIME_COLUMN_NAME, queryGranularity, flippedKind, rhsMillis);
}
final String column;
final ExtractionFn extractionFn;
if (lhsExpression.isSimpleExtraction()) {
column = lhsExpression.getSimpleExtraction().getColumn();
extractionFn = lhsExpression.getSimpleExtraction().getExtractionFn();
} else if (virtualColumnRegistry != null) {
column = virtualColumnRegistry.getOrCreateVirtualColumnForExpression(lhsExpression, lhs.getType());
extractionFn = null;
} else {
return null;
}
if (column.equals(ColumnHolder.TIME_COLUMN_NAME) && extractionFn instanceof TimeFormatExtractionFn) {
// Check if we can strip the extractionFn and convert the filter to a direct filter on __time.
// This allows potential conversion to query-level "intervals" later on, which is ideal for Druid queries.
final Granularity granularity = ExtractionFns.toQueryGranularity(extractionFn);
if (granularity != null) {
// lhs is FLOOR(__time TO granularity); rhs must be a timestamp
final long rhsMillis = Calcites.calciteDateTimeLiteralToJoda(rhs, plannerContext.getTimeZone()).getMillis();
final Interval rhsInterval = granularity.bucket(DateTimes.utc(rhsMillis));
// Is rhs aligned on granularity boundaries?
final boolean rhsAligned = rhsInterval.getStartMillis() == rhsMillis;
// Create a BoundRefKey that strips the extractionFn and compares __time as a number.
final BoundRefKey boundRefKey = new BoundRefKey(column, null, StringComparators.NUMERIC);
return getBoundTimeDimFilter(flippedKind, boundRefKey, rhsInterval, rhsAligned);
}
}
final String val;
final RexLiteral rhsLiteral = (RexLiteral) rhs;
if (SqlTypeName.NUMERIC_TYPES.contains(rhsLiteral.getTypeName())) {
val = String.valueOf(RexLiteral.value(rhsLiteral));
} else if (SqlTypeName.CHAR_TYPES.contains(rhsLiteral.getTypeName())) {
val = String.valueOf(RexLiteral.stringValue(rhsLiteral));
} else if (SqlTypeName.TIMESTAMP == rhsLiteral.getTypeName() || SqlTypeName.DATE == rhsLiteral.getTypeName()) {
val = String.valueOf(Calcites.calciteDateTimeLiteralToJoda(rhsLiteral, plannerContext.getTimeZone()).getMillis());
} else {
// Don't know how to filter on this kind of literal.
return null;
}
// Numeric lhs needs a numeric comparison.
final StringComparator comparator = Calcites.getStringComparatorForRelDataType(lhs.getType());
final BoundRefKey boundRefKey = new BoundRefKey(column, extractionFn, comparator);
final DimFilter filter;
// Always use BoundDimFilters, to simplify filter optimization later (it helps to remember the comparator).
switch(flippedKind) {
case EQUALS:
filter = Bounds.equalTo(boundRefKey, val);
break;
case NOT_EQUALS:
filter = new NotDimFilter(Bounds.equalTo(boundRefKey, val));
break;
case GREATER_THAN:
filter = Bounds.greaterThan(boundRefKey, val);
break;
case GREATER_THAN_OR_EQUAL:
filter = Bounds.greaterThanOrEqualTo(boundRefKey, val);
break;
case LESS_THAN:
filter = Bounds.lessThan(boundRefKey, val);
break;
case LESS_THAN_OR_EQUAL:
filter = Bounds.lessThanOrEqualTo(boundRefKey, val);
break;
default:
throw new IllegalStateException("Shouldn't have got here");
}
return filter;
} else if (rexNode instanceof RexCall) {
final SqlOperator operator = ((RexCall) rexNode).getOperator();
final SqlOperatorConversion conversion = plannerContext.getOperatorTable().lookupOperatorConversion(operator);
if (conversion == null) {
return null;
} else {
return conversion.toDruidFilter(plannerContext, rowSignature, virtualColumnRegistry, rexNode);
}
} else {
return null;
}
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.sql.SqlKind in project flink by apache.
the class OverConvertRule method convert.
@Override
public Optional<RexNode> convert(CallExpression call, ConvertContext context) {
List<Expression> children = call.getChildren();
if (call.getFunctionDefinition() == BuiltInFunctionDefinitions.OVER) {
FlinkTypeFactory typeFactory = context.getTypeFactory();
Expression agg = children.get(0);
FunctionDefinition def = ((CallExpression) agg).getFunctionDefinition();
boolean isDistinct = BuiltInFunctionDefinitions.DISTINCT == def;
SqlAggFunction aggFunc = agg.accept(new SqlAggFunctionVisitor(context.getRelBuilder()));
RelDataType aggResultType = typeFactory.createFieldTypeFromLogicalType(fromDataTypeToLogicalType(((ResolvedExpression) agg).getOutputDataType()));
// assemble exprs by agg children
List<RexNode> aggExprs = agg.getChildren().stream().map(child -> {
if (isDistinct) {
return context.toRexNode(child.getChildren().get(0));
} else {
return context.toRexNode(child);
}
}).collect(Collectors.toList());
// assemble order by key
Expression orderKeyExpr = children.get(1);
Set<SqlKind> kinds = new HashSet<>();
RexNode collationRexNode = createCollation(context.toRexNode(orderKeyExpr), RelFieldCollation.Direction.ASCENDING, null, kinds);
ImmutableList<RexFieldCollation> orderKey = ImmutableList.of(new RexFieldCollation(collationRexNode, kinds));
// assemble partition by keys
List<RexNode> partitionKeys = children.subList(4, children.size()).stream().map(context::toRexNode).collect(Collectors.toList());
// assemble bounds
Expression preceding = children.get(2);
boolean isPhysical = fromDataTypeToLogicalType(((ResolvedExpression) preceding).getOutputDataType()).is(LogicalTypeRoot.BIGINT);
Expression following = children.get(3);
RexWindowBound lowerBound = createBound(context, preceding, SqlKind.PRECEDING);
RexWindowBound upperBound = createBound(context, following, SqlKind.FOLLOWING);
// build RexOver
return Optional.of(context.getRelBuilder().getRexBuilder().makeOver(aggResultType, aggFunc, aggExprs, partitionKeys, orderKey, lowerBound, upperBound, isPhysical, true, false, isDistinct));
}
return Optional.empty();
}
Aggregations