use of org.apache.calcite.rex.RexLiteral in project calcite by apache.
the class ValuesReduceRule method apply.
// ~ Methods ----------------------------------------------------------------
/**
* Does the work.
*
* @param call Rule call
* @param project Project, may be null
* @param filter Filter, may be null
* @param values Values rel to be reduced
*/
protected void apply(RelOptRuleCall call, LogicalProject project, LogicalFilter filter, LogicalValues values) {
assert values != null;
assert filter != null || project != null;
final RexNode conditionExpr = (filter == null) ? null : filter.getCondition();
final List<RexNode> projectExprs = (project == null) ? null : project.getProjects();
RexBuilder rexBuilder = values.getCluster().getRexBuilder();
// Find reducible expressions.
final List<RexNode> reducibleExps = new ArrayList<>();
final MyRexShuttle shuttle = new MyRexShuttle();
for (final List<RexLiteral> literalList : values.getTuples()) {
shuttle.literalList = literalList;
if (conditionExpr != null) {
RexNode c = conditionExpr.accept(shuttle);
reducibleExps.add(c);
}
if (projectExprs != null) {
int k = -1;
for (RexNode projectExpr : projectExprs) {
++k;
RexNode e = projectExpr.accept(shuttle);
if (RexLiteral.isNullLiteral(e)) {
e = rexBuilder.makeAbstractCast(project.getRowType().getFieldList().get(k).getType(), e);
}
reducibleExps.add(e);
}
}
}
int fieldsPerRow = ((conditionExpr == null) ? 0 : 1) + ((projectExprs == null) ? 0 : projectExprs.size());
assert fieldsPerRow > 0;
assert reducibleExps.size() == (values.getTuples().size() * fieldsPerRow);
// Compute the values they reduce to.
final RelOptPredicateList predicates = RelOptPredicateList.EMPTY;
ReduceExpressionsRule.reduceExpressions(values, reducibleExps, predicates, false, true);
int changeCount = 0;
final ImmutableList.Builder<ImmutableList<RexLiteral>> tuplesBuilder = ImmutableList.builder();
for (int row = 0; row < values.getTuples().size(); ++row) {
int i = 0;
RexNode reducedValue;
if (conditionExpr != null) {
reducedValue = reducibleExps.get((row * fieldsPerRow) + i);
++i;
if (!reducedValue.isAlwaysTrue()) {
++changeCount;
continue;
}
}
ImmutableList<RexLiteral> valuesList;
if (projectExprs != null) {
++changeCount;
final ImmutableList.Builder<RexLiteral> tupleBuilder = ImmutableList.builder();
for (; i < fieldsPerRow; ++i) {
reducedValue = reducibleExps.get((row * fieldsPerRow) + i);
if (reducedValue instanceof RexLiteral) {
tupleBuilder.add((RexLiteral) reducedValue);
} else if (RexUtil.isNullLiteral(reducedValue, true)) {
tupleBuilder.add(rexBuilder.constantNull());
} else {
return;
}
}
valuesList = tupleBuilder.build();
} else {
valuesList = values.getTuples().get(row);
}
tuplesBuilder.add(valuesList);
}
if (changeCount > 0) {
final RelDataType rowType;
if (projectExprs != null) {
rowType = project.getRowType();
} else {
rowType = values.getRowType();
}
final RelNode newRel = LogicalValues.create(values.getCluster(), rowType, tuplesBuilder.build());
call.transformTo(newRel);
} else {
// Filter had no effect, so we can say that Filter(Values) ==
// Values.
call.transformTo(values);
}
// can send the volcano planner into a loop; see dtbug 2070.)
if (filter != null) {
call.getPlanner().setImportance(filter, 0.0);
}
}
use of org.apache.calcite.rex.RexLiteral in project calcite by apache.
the class ExtractOperatorConversion method toDruidExpression.
@Override
public String toDruidExpression(RexNode rexNode, RelDataType rowType, DruidQuery query) {
final RexCall call = (RexCall) rexNode;
final RexLiteral flag = (RexLiteral) call.getOperands().get(0);
final TimeUnitRange calciteUnit = (TimeUnitRange) flag.getValue();
final RexNode arg = call.getOperands().get(1);
final String input = DruidExpressions.toDruidExpression(arg, rowType, query);
if (input == null) {
return null;
}
final String druidUnit = EXTRACT_UNIT_MAP.get(calciteUnit);
if (druidUnit == null) {
return null;
}
return DruidExpressions.applyTimeExtract(input, druidUnit, TimeZone.getTimeZone(query.getConnectionConfig().timeZone()));
}
use of org.apache.calcite.rex.RexLiteral in project drill by axbaretto.
the class DrillReduceAggregatesRule method reduceStddev.
private RexNode reduceStddev(Aggregate oldAggRel, AggregateCall oldCall, boolean biased, boolean sqrt, List<AggregateCall> newCalls, Map<AggregateCall, RexNode> aggCallMapping, List<RexNode> inputExprs) {
// stddev_pop(x) ==>
// power(
// (sum(x * x) - sum(x) * sum(x) / count(x))
// / count(x),
// .5)
//
// stddev_samp(x) ==>
// power(
// (sum(x * x) - sum(x) * sum(x) / count(x))
// / nullif(count(x) - 1, 0),
// .5)
final PlannerSettings plannerSettings = (PlannerSettings) oldAggRel.getCluster().getPlanner().getContext();
final boolean isInferenceEnabled = plannerSettings.isTypeInferenceEnabled();
final int nGroups = oldAggRel.getGroupCount();
RelDataTypeFactory typeFactory = oldAggRel.getCluster().getTypeFactory();
final RexBuilder rexBuilder = oldAggRel.getCluster().getRexBuilder();
assert oldCall.getArgList().size() == 1 : oldCall.getArgList();
final int argOrdinal = oldCall.getArgList().get(0);
final RelDataType argType = getFieldType(oldAggRel.getInput(), argOrdinal);
// final RexNode argRef = inputExprs.get(argOrdinal);
RexNode argRef = rexBuilder.makeCall(CastHighOp, inputExprs.get(argOrdinal));
inputExprs.set(argOrdinal, argRef);
final RexNode argSquared = rexBuilder.makeCall(SqlStdOperatorTable.MULTIPLY, argRef, argRef);
final int argSquaredOrdinal = lookupOrAdd(inputExprs, argSquared);
RelDataType sumType = TypeInferenceUtils.getDrillSqlReturnTypeInference(SqlKind.SUM.name(), ImmutableList.<DrillFuncHolder>of()).inferReturnType(oldCall.createBinding(oldAggRel));
sumType = typeFactory.createTypeWithNullability(sumType, true);
final AggregateCall sumArgSquaredAggCall = AggregateCall.create(new DrillCalciteSqlAggFunctionWrapper(new SqlSumAggFunction(sumType), sumType), oldCall.isDistinct(), oldCall.isApproximate(), ImmutableIntList.of(argSquaredOrdinal), -1, sumType, null);
final RexNode sumArgSquared = rexBuilder.addAggCall(sumArgSquaredAggCall, nGroups, oldAggRel.indicator, newCalls, aggCallMapping, ImmutableList.of(argType));
final AggregateCall sumArgAggCall = AggregateCall.create(new DrillCalciteSqlAggFunctionWrapper(new SqlSumAggFunction(sumType), sumType), oldCall.isDistinct(), oldCall.isApproximate(), ImmutableIntList.of(argOrdinal), -1, sumType, null);
final RexNode sumArg = rexBuilder.addAggCall(sumArgAggCall, nGroups, oldAggRel.indicator, newCalls, aggCallMapping, ImmutableList.of(argType));
final RexNode sumSquaredArg = rexBuilder.makeCall(SqlStdOperatorTable.MULTIPLY, sumArg, sumArg);
final SqlCountAggFunction countAgg = (SqlCountAggFunction) SqlStdOperatorTable.COUNT;
final RelDataType countType = countAgg.getReturnType(typeFactory);
final AggregateCall countArgAggCall = AggregateCall.create(countAgg, oldCall.isDistinct(), oldCall.isApproximate(), oldCall.getArgList(), -1, countType, null);
final RexNode countArg = rexBuilder.addAggCall(countArgAggCall, nGroups, oldAggRel.indicator, newCalls, aggCallMapping, ImmutableList.of(argType));
final RexNode avgSumSquaredArg = rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE, sumSquaredArg, countArg);
final RexNode diff = rexBuilder.makeCall(SqlStdOperatorTable.MINUS, sumArgSquared, avgSumSquaredArg);
final RexNode denominator;
if (biased) {
denominator = countArg;
} else {
final RexLiteral one = rexBuilder.makeExactLiteral(BigDecimal.ONE);
final RexNode nul = rexBuilder.makeNullLiteral(countArg.getType());
final RexNode countMinusOne = rexBuilder.makeCall(SqlStdOperatorTable.MINUS, countArg, one);
final RexNode countEqOne = rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, countArg, one);
denominator = rexBuilder.makeCall(SqlStdOperatorTable.CASE, countEqOne, nul, countMinusOne);
}
final SqlOperator divide;
if (isInferenceEnabled) {
divide = new DrillSqlOperator("divide", 2, true, oldCall.getType(), false);
} else {
divide = SqlStdOperatorTable.DIVIDE;
}
final RexNode div = rexBuilder.makeCall(divide, diff, denominator);
RexNode result = div;
if (sqrt) {
final RexNode half = rexBuilder.makeExactLiteral(new BigDecimal("0.5"));
result = rexBuilder.makeCall(SqlStdOperatorTable.POWER, div, half);
}
if (isInferenceEnabled) {
return result;
} else {
/*
* Currently calcite's strategy to infer the return type of aggregate functions
* is wrong because it uses the first known argument to determine output type. For
* instance if we are performing stddev on an integer column then it interprets the
* output type to be integer which is incorrect as it should be double. So based on
* this if we add cast after rewriting the aggregate we add an additional cast which
* would cause wrong results. So we simply add a cast to ANY.
*/
return rexBuilder.makeCast(typeFactory.createSqlType(SqlTypeName.ANY), result);
}
}
use of org.apache.calcite.rex.RexLiteral in project drill by apache.
the class DrillRexBuilder method makeCast.
/**
* Creates a call to the CAST operator, expanding if possible, and optionally
* also preserving nullability.
*
* <p>Tries to expand the cast, and therefore the result may be something
* other than a {@link org.apache.calcite.rex.RexCall} to the CAST operator, such as a
* {@link RexLiteral} if {@code matchNullability} is false.
*
* @param type Type to cast to
* @param exp Expression being cast
* @param matchNullability Whether to ensure the result has the same
* nullability as {@code type}
* @return Call to CAST operator
*/
@Override
public RexNode makeCast(RelDataType type, RexNode exp, boolean matchNullability) {
if (matchNullability) {
return makeAbstractCast(type, exp);
}
// TODO: remove this code when CALCITE-1468 is fixed
if (type.getSqlTypeName() == SqlTypeName.DECIMAL && exp instanceof RexLiteral) {
int precision = type.getPrecision();
int scale = type.getScale();
validatePrecisionAndScale(precision, scale);
Comparable<?> value = ((RexLiteral) exp).getValueAs(Comparable.class);
if (value instanceof BigDecimal) {
BigDecimal bigDecimal = (BigDecimal) value;
DecimalUtility.checkValueOverflow(bigDecimal, precision, scale);
if (bigDecimal.precision() != precision || bigDecimal.scale() != scale) {
return makeAbstractCast(type, exp);
}
}
}
return super.makeCast(type, exp, false);
}
use of org.apache.calcite.rex.RexLiteral in project drill by apache.
the class JoinUtils method isScalarSubquery.
/**
* Utility method to check if a subquery (represented by its root RelNode) is provably scalar. Currently
* only aggregates with no group-by are considered scalar. In the future, this method should be generalized
* to include more cases and reconciled with Calcite's notion of scalar.
* @param root The root RelNode to be examined
* @return True if the root rel or its descendant is scalar, False otherwise
*/
public static boolean isScalarSubquery(RelNode root) {
DrillAggregateRel agg = null;
RelNode currentrel = root;
while (agg == null && currentrel != null) {
if (currentrel instanceof DrillAggregateRel) {
agg = (DrillAggregateRel) currentrel;
} else if (currentrel instanceof RelSubset) {
currentrel = ((RelSubset) currentrel).getBest();
} else if (currentrel instanceof DrillLimitRel) {
// TODO: Improve this check when DRILL-5691 is fixed.
// The problem is that RelMdMaxRowCount currently cannot be used
// due to CALCITE-1048.
Integer fetchValue = ((RexLiteral) ((DrillLimitRel) currentrel).getFetch()).getValueAs(Integer.class);
return fetchValue != null && fetchValue <= 1;
} else if (currentrel.getInputs().size() == 1) {
// If the rel is not an aggregate or RelSubset, but is a single-input rel (could be Project,
// Filter, Sort etc.), check its input
currentrel = currentrel.getInput(0);
} else {
break;
}
}
if (agg != null) {
if (agg.getGroupSet().isEmpty()) {
return true;
}
// with empty call list and literal from project expression in group set.
if (agg.getAggCallList().isEmpty() && agg.getGroupSet().cardinality() == 1) {
ProjectExpressionsCollector expressionsCollector = new ProjectExpressionsCollector();
agg.accept(expressionsCollector);
List<RexNode> projectedExpressions = expressionsCollector.getProjectedExpressions();
return projectedExpressions.size() == 1 && RexUtil.isLiteral(projectedExpressions.get(agg.getGroupSet().nth(0)), true);
}
}
return false;
}
Aggregations