use of org.apache.calcite.sql.SqlAggFunction in project calcite by apache.
the class AggregateStarTableRule method rollUp.
private static AggregateCall rollUp(int groupCount, RelBuilder relBuilder, AggregateCall aggregateCall, TileKey tileKey) {
if (aggregateCall.isDistinct()) {
return null;
}
final SqlAggFunction aggregation = aggregateCall.getAggregation();
final Pair<SqlAggFunction, List<Integer>> seek = Pair.of(aggregation, aggregateCall.getArgList());
final int offset = tileKey.dimensions.cardinality();
final ImmutableList<Lattice.Measure> measures = tileKey.measures;
// First, try to satisfy the aggregation by rolling up an aggregate in the
// materialization.
final int i = find(measures, seek);
tryRoll: if (i >= 0) {
final SqlAggFunction roll = SubstitutionVisitor.getRollup(aggregation);
if (roll == null) {
break tryRoll;
}
return AggregateCall.create(roll, false, aggregateCall.isApproximate(), ImmutableList.of(offset + i), -1, groupCount, relBuilder.peek(), null, aggregateCall.name);
}
// Second, try to satisfy the aggregation based on group set columns.
tryGroup: {
List<Integer> newArgs = Lists.newArrayList();
for (Integer arg : aggregateCall.getArgList()) {
int z = tileKey.dimensions.indexOf(arg);
if (z < 0) {
break tryGroup;
}
newArgs.add(z);
}
return AggregateCall.create(aggregation, false, aggregateCall.isApproximate(), newArgs, -1, groupCount, relBuilder.peek(), null, aggregateCall.name);
}
// No roll up possible.
return null;
}
use of org.apache.calcite.sql.SqlAggFunction in project calcite by apache.
the class AggregateUnionTransposeRule method transformAggCalls.
private List<AggregateCall> transformAggCalls(RelNode input, int groupCount, List<AggregateCall> origCalls) {
final List<AggregateCall> newCalls = Lists.newArrayList();
for (Ord<AggregateCall> ord : Ord.zip(origCalls)) {
final AggregateCall origCall = ord.e;
if (origCall.isDistinct() || !SUPPORTED_AGGREGATES.containsKey(origCall.getAggregation().getClass())) {
return null;
}
final SqlAggFunction aggFun;
final RelDataType aggType;
if (origCall.getAggregation() == SqlStdOperatorTable.COUNT) {
aggFun = SqlStdOperatorTable.SUM0;
// count(any) is always not null, however nullability of sum might
// depend on the number of columns in GROUP BY.
// Here we use SUM0 since we are sure we will not face nullable
// inputs nor we'll face empty set.
aggType = null;
} else {
aggFun = origCall.getAggregation();
aggType = origCall.getType();
}
AggregateCall newCall = AggregateCall.create(aggFun, origCall.isDistinct(), origCall.isApproximate(), ImmutableList.of(groupCount + ord.i), -1, groupCount, input, aggType, origCall.getName());
newCalls.add(newCall);
}
return newCalls;
}
use of org.apache.calcite.sql.SqlAggFunction in project calcite by apache.
the class AggregateExpandDistinctAggregatesRule method rewriteUsingGroupingSets.
private void rewriteUsingGroupingSets(RelOptRuleCall call, Aggregate aggregate) {
final Set<ImmutableBitSet> groupSetTreeSet = new TreeSet<>(ImmutableBitSet.ORDERING);
for (AggregateCall aggCall : aggregate.getAggCallList()) {
if (!aggCall.isDistinct()) {
groupSetTreeSet.add(aggregate.getGroupSet());
} else {
groupSetTreeSet.add(ImmutableBitSet.of(aggCall.getArgList()).setIf(aggCall.filterArg, aggCall.filterArg >= 0).union(aggregate.getGroupSet()));
}
}
final ImmutableList<ImmutableBitSet> groupSets = ImmutableList.copyOf(groupSetTreeSet);
final ImmutableBitSet fullGroupSet = ImmutableBitSet.union(groupSets);
final List<AggregateCall> distinctAggCalls = new ArrayList<>();
for (Pair<AggregateCall, String> aggCall : aggregate.getNamedAggCalls()) {
if (!aggCall.left.isDistinct()) {
AggregateCall newAggCall = aggCall.left.adaptTo(aggregate.getInput(), aggCall.left.getArgList(), aggCall.left.filterArg, aggregate.getGroupCount(), fullGroupSet.cardinality());
distinctAggCalls.add(newAggCall.rename(aggCall.right));
}
}
final RelBuilder relBuilder = call.builder();
relBuilder.push(aggregate.getInput());
final int groupCount = fullGroupSet.cardinality();
final Map<ImmutableBitSet, Integer> filters = new LinkedHashMap<>();
final int z = groupCount + distinctAggCalls.size();
distinctAggCalls.add(AggregateCall.create(SqlStdOperatorTable.GROUPING, false, false, ImmutableIntList.copyOf(fullGroupSet), -1, groupSets.size(), relBuilder.peek(), null, "$g"));
for (Ord<ImmutableBitSet> groupSet : Ord.zip(groupSets)) {
filters.put(groupSet.e, z + groupSet.i);
}
relBuilder.aggregate(relBuilder.groupKey(fullGroupSet, groupSets), distinctAggCalls);
final RelNode distinct = relBuilder.peek();
// values to BOOLEAN.
if (!filters.isEmpty()) {
final List<RexNode> nodes = new ArrayList<>(relBuilder.fields());
final RexNode nodeZ = nodes.remove(nodes.size() - 1);
for (Map.Entry<ImmutableBitSet, Integer> entry : filters.entrySet()) {
final long v = groupValue(fullGroupSet, entry.getKey());
nodes.add(relBuilder.alias(relBuilder.equals(nodeZ, relBuilder.literal(v)), "$g_" + v));
}
relBuilder.project(nodes);
}
int x = groupCount;
final List<AggregateCall> newCalls = new ArrayList<>();
for (AggregateCall aggCall : aggregate.getAggCallList()) {
final int newFilterArg;
final List<Integer> newArgList;
final SqlAggFunction aggregation;
if (!aggCall.isDistinct()) {
aggregation = SqlStdOperatorTable.MIN;
newArgList = ImmutableIntList.of(x++);
newFilterArg = filters.get(aggregate.getGroupSet());
} else {
aggregation = aggCall.getAggregation();
newArgList = remap(fullGroupSet, aggCall.getArgList());
newFilterArg = filters.get(ImmutableBitSet.of(aggCall.getArgList()).setIf(aggCall.filterArg, aggCall.filterArg >= 0).union(aggregate.getGroupSet()));
}
final AggregateCall newCall = AggregateCall.create(aggregation, false, aggCall.isApproximate(), newArgList, newFilterArg, aggregate.getGroupCount(), distinct, null, aggCall.name);
newCalls.add(newCall);
}
relBuilder.aggregate(relBuilder.groupKey(remap(fullGroupSet, aggregate.getGroupSet()), remap(fullGroupSet, aggregate.getGroupSets())), newCalls);
relBuilder.convert(aggregate.getRowType(), true);
call.transformTo(relBuilder.build());
}
use of org.apache.calcite.sql.SqlAggFunction in project calcite by apache.
the class AggregateFilterTransposeRule method onMatch.
public void onMatch(RelOptRuleCall call) {
final Aggregate aggregate = call.rel(0);
final Filter filter = call.rel(1);
// Do the columns used by the filter appear in the output of the aggregate?
final ImmutableBitSet filterColumns = RelOptUtil.InputFinder.bits(filter.getCondition());
final ImmutableBitSet newGroupSet = aggregate.getGroupSet().union(filterColumns);
final RelNode input = filter.getInput();
final RelMetadataQuery mq = call.getMetadataQuery();
final Boolean unique = mq.areColumnsUnique(input, newGroupSet);
if (unique != null && unique) {
// the rule fires forever: A-F => A-F-A => A-A-F-A => A-A-A-F-A => ...
return;
}
boolean allColumnsInAggregate = aggregate.getGroupSet().contains(filterColumns);
final Aggregate newAggregate = aggregate.copy(aggregate.getTraitSet(), input, false, newGroupSet, null, aggregate.getAggCallList());
final Mappings.TargetMapping mapping = Mappings.target(new Function<Integer, Integer>() {
public Integer apply(Integer a0) {
return newGroupSet.indexOf(a0);
}
}, input.getRowType().getFieldCount(), newGroupSet.cardinality());
final RexNode newCondition = RexUtil.apply(mapping, filter.getCondition());
final Filter newFilter = filter.copy(filter.getTraitSet(), newAggregate, newCondition);
if (allColumnsInAggregate && aggregate.getGroupType() == Group.SIMPLE) {
// Everything needed by the filter is returned by the aggregate.
assert newGroupSet.equals(aggregate.getGroupSet());
call.transformTo(newFilter);
} else {
// If aggregate uses grouping sets, we always need to split it.
// Otherwise, it means that grouping sets are not used, but the
// filter needs at least one extra column, and now aggregate it away.
final ImmutableBitSet.Builder topGroupSet = ImmutableBitSet.builder();
for (int c : aggregate.getGroupSet()) {
topGroupSet.set(newGroupSet.indexOf(c));
}
ImmutableList<ImmutableBitSet> newGroupingSets = null;
if (aggregate.getGroupType() != Group.SIMPLE) {
ImmutableList.Builder<ImmutableBitSet> newGroupingSetsBuilder = ImmutableList.builder();
for (ImmutableBitSet groupingSet : aggregate.getGroupSets()) {
final ImmutableBitSet.Builder newGroupingSet = ImmutableBitSet.builder();
for (int c : groupingSet) {
newGroupingSet.set(newGroupSet.indexOf(c));
}
newGroupingSetsBuilder.add(newGroupingSet.build());
}
newGroupingSets = newGroupingSetsBuilder.build();
}
final List<AggregateCall> topAggCallList = Lists.newArrayList();
int i = newGroupSet.cardinality();
for (AggregateCall aggregateCall : aggregate.getAggCallList()) {
final SqlAggFunction rollup = SubstitutionVisitor.getRollup(aggregateCall.getAggregation());
if (rollup == null) {
// This aggregate cannot be rolled up.
return;
}
if (aggregateCall.isDistinct()) {
// Cannot roll up distinct.
return;
}
topAggCallList.add(AggregateCall.create(rollup, aggregateCall.isDistinct(), aggregateCall.isApproximate(), ImmutableList.of(i++), -1, aggregateCall.type, aggregateCall.name));
}
final Aggregate topAggregate = aggregate.copy(aggregate.getTraitSet(), newFilter, aggregate.indicator, topGroupSet.build(), newGroupingSets, topAggCallList);
call.transformTo(topAggregate);
}
}
use of org.apache.calcite.sql.SqlAggFunction in project drill by apache.
the class DrillReduceAggregatesRule method reduceAvg.
private RexNode reduceAvg(Aggregate oldAggRel, AggregateCall oldCall, List<AggregateCall> newCalls, Map<AggregateCall, RexNode> aggCallMapping) {
final PlannerSettings plannerSettings = (PlannerSettings) oldAggRel.getCluster().getPlanner().getContext();
final boolean isInferenceEnabled = plannerSettings.isTypeInferenceEnabled();
final int nGroups = oldAggRel.getGroupCount();
RelDataTypeFactory typeFactory = oldAggRel.getCluster().getTypeFactory();
RexBuilder rexBuilder = oldAggRel.getCluster().getRexBuilder();
int iAvgInput = oldCall.getArgList().get(0);
RelDataType avgInputType = getFieldType(oldAggRel.getInput(), iAvgInput);
RelDataType sumType = TypeInferenceUtils.getDrillSqlReturnTypeInference(SqlKind.SUM.name(), ImmutableList.of()).inferReturnType(oldCall.createBinding(oldAggRel));
sumType = typeFactory.createTypeWithNullability(sumType, sumType.isNullable() || nGroups == 0);
SqlAggFunction sumAgg = new DrillCalciteSqlAggFunctionWrapper(new SqlSumEmptyIsZeroAggFunction(), sumType);
AggregateCall sumCall = AggregateCall.create(sumAgg, oldCall.isDistinct(), oldCall.isApproximate(), oldCall.getArgList(), -1, sumType, null);
final SqlCountAggFunction countAgg = (SqlCountAggFunction) SqlStdOperatorTable.COUNT;
final RelDataType countType = countAgg.getReturnType(typeFactory);
AggregateCall countCall = AggregateCall.create(countAgg, oldCall.isDistinct(), oldCall.isApproximate(), oldCall.getArgList(), -1, countType, null);
RexNode tmpsumRef = rexBuilder.addAggCall(sumCall, nGroups, newCalls, aggCallMapping, ImmutableList.of(avgInputType));
RexNode tmpcountRef = rexBuilder.addAggCall(countCall, nGroups, newCalls, aggCallMapping, ImmutableList.of(avgInputType));
RexNode n = rexBuilder.makeCall(SqlStdOperatorTable.CASE, rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, tmpcountRef, rexBuilder.makeExactLiteral(BigDecimal.ZERO)), rexBuilder.constantNull(), tmpsumRef);
// NOTE: these references are with respect to the output
// of newAggRel
/*
RexNode numeratorRef =
rexBuilder.makeCall(CastHighOp,
rexBuilder.addAggCall(
sumCall,
nGroups,
newCalls,
aggCallMapping,
ImmutableList.of(avgInputType))
);
*/
RexNode numeratorRef = rexBuilder.makeCall(CastHighOp, n);
RexNode denominatorRef = rexBuilder.addAggCall(countCall, nGroups, newCalls, aggCallMapping, ImmutableList.of(avgInputType));
if (isInferenceEnabled) {
return rexBuilder.makeCall(new DrillSqlOperator("divide", 2, true, oldCall.getType(), false), numeratorRef, denominatorRef);
} else {
final RexNode divideRef = rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE, numeratorRef, denominatorRef);
return rexBuilder.makeCast(typeFactory.createSqlType(SqlTypeName.ANY), divideRef);
}
}
Aggregations