Repository: calcite Updated Branches: refs/heads/master 425fa7b7f -> ebc43d928
[CALCITE-2654] In RelBuilder, add a fluent API for building complex aggregate calls To interface AggCall in RelBuilder, add methods distinct(boolean), filter(RexNode), approximate(boolean), alias(String). And simplify the RelBuilder.aggregateCall method to just two arguments: aggregateCall(op, operands). Thus you only specify the arguments that are of interest. Similar changes to count, countStar, min, max, sum, avg. Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/4cc46130 Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/4cc46130 Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/4cc46130 Branch: refs/heads/master Commit: 4cc46130f71d21e4f5b76f6e645380cd83d2c921 Parents: 425fa7b Author: Julian Hyde <[email protected]> Authored: Sat Nov 3 19:59:11 2018 -0700 Committer: Julian Hyde <[email protected]> Committed: Wed Nov 7 16:33:06 2018 -0800 ---------------------------------------------------------------------- .../rel/rules/AbstractMaterializedViewRule.java | 21 +- .../AggregateExpandDistinctAggregatesRule.java | 21 +- .../rel/rules/AggregateExtractProjectRule.java | 9 +- .../calcite/rel/rules/SubQueryRemoveRule.java | 8 +- .../apache/calcite/sql2rel/RelFieldTrimmer.java | 8 +- .../org/apache/calcite/tools/PigRelBuilder.java | 3 +- .../org/apache/calcite/tools/RelBuilder.java | 249 ++++++++++++++++--- .../rel/rel2sql/RelToSqlConverterTest.java | 4 +- .../org/apache/calcite/test/RelBuilderTest.java | 66 +++-- site/_docs/algebra.md | 22 +- 10 files changed, 298 insertions(+), 113 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/4cc46130/core/src/main/java/org/apache/calcite/rel/rules/AbstractMaterializedViewRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AbstractMaterializedViewRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AbstractMaterializedViewRule.java index 3a82f95..68a9382 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/AbstractMaterializedViewRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/AbstractMaterializedViewRule.java @@ -1194,13 +1194,14 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule { // Cannot rollup this aggregate, bail out return null; } + final RexInputRef operand = + rexBuilder.makeInputRef(relBuilder.peek(), + aggregate.getGroupCount() + i); aggregateCalls.add( - relBuilder.aggregateCall( - rollupAgg, - aggCall.isDistinct(), aggCall.isApproximate(), null, - aggCall.name, - rexBuilder.makeInputRef(relBuilder.peek(), - aggregate.getGroupCount() + i))); + relBuilder.aggregateCall(rollupAgg, operand) + .distinct(aggCall.isDistinct()) + .approximate(aggCall.isApproximate()) + .as(aggCall.name)); } RelNode prevNode = relBuilder.peek(); RelNode result = relBuilder @@ -1466,10 +1467,12 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule { // Cannot rollup this aggregate, bail out return null; } + final RexInputRef operand = rexBuilder.makeInputRef(input, k); aggregateCalls.add( - relBuilder.aggregateCall( - rollupAgg, queryAggCall.isDistinct(), queryAggCall.isApproximate(), - null, queryAggCall.name, rexBuilder.makeInputRef(input, k))); + relBuilder.aggregateCall(rollupAgg, operand) + .approximate(queryAggCall.isApproximate()) + .distinct(queryAggCall.isDistinct()) + .as(queryAggCall.name)); rewritingMapping.set(k, sourceIdx); added = true; } http://git-wip-us.apache.org/repos/asf/calcite/blob/4cc46130/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java index d150989..6d974d8 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java @@ -274,14 +274,15 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule { // Add the distinct aggregate column(s) to the group-by columns, // if not already a part of the group-by - final SortedSet<Integer> bottomGroupSet = new TreeSet<>(); - bottomGroupSet.addAll(aggregate.getGroupSet().asList()); + final SortedSet<Integer> bottomGroups = new TreeSet<>(); + bottomGroups.addAll(aggregate.getGroupSet().asList()); for (AggregateCall aggCall : originalAggCalls) { if (aggCall.isDistinct()) { - bottomGroupSet.addAll(aggCall.getArgList()); + bottomGroups.addAll(aggCall.getArgList()); break; // since we only have single distinct call } } + final ImmutableBitSet bottomGroupSet = ImmutableBitSet.of(bottomGroups); // Generate the intermediate aggregate B, the one on the bottom that converts // a distinct call to group by call. @@ -295,16 +296,15 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule { final AggregateCall newCall = AggregateCall.create(aggCall.getAggregation(), false, aggCall.isApproximate(), aggCall.getArgList(), -1, - ImmutableBitSet.of(bottomGroupSet).cardinality(), + bottomGroupSet.cardinality(), relBuilder.peek(), null, aggCall.name); bottomAggregateCalls.add(newCall); } } // Generate the aggregate B (see the reference example above) relBuilder.push( - aggregate.copy( - aggregate.getTraitSet(), relBuilder.build(), - false, ImmutableBitSet.of(bottomGroupSet), null, bottomAggregateCalls)); + aggregate.copy(aggregate.getTraitSet(), relBuilder.build(), + false, bottomGroupSet, null, bottomAggregateCalls)); // Add aggregate A (see the reference example above), the top aggregate // to handle the rest of the aggregation that the bottom aggregate hasn't handled @@ -316,7 +316,7 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule { if (aggCall.isDistinct()) { List<Integer> newArgList = new ArrayList<>(); for (int arg : aggCall.getArgList()) { - newArgList.add(bottomGroupSet.headSet(arg).size()); + newArgList.add(bottomGroups.headSet(arg).size()); } newCall = AggregateCall.create(aggCall.getAggregation(), @@ -332,7 +332,8 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule { // If aggregate B had a COUNT aggregate call the corresponding aggregate at // aggregate A must be SUM. For other aggregates, it remains the same. final List<Integer> newArgs = - Lists.newArrayList(bottomGroupSet.size() + nonDistinctAggCallProcessedSoFar); + Lists.newArrayList(bottomGroups.size() + + nonDistinctAggCallProcessedSoFar); if (aggCall.getAggregation().getKind() == SqlKind.COUNT) { newCall = AggregateCall.create(new SqlSumEmptyIsZeroAggFunction(), false, @@ -357,7 +358,7 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule { // output), minus the distinct aggCall's input. final Set<Integer> topGroupSet = new HashSet<>(); int groupSetToAdd = 0; - for (int bottomGroup : bottomGroupSet) { + for (int bottomGroup : bottomGroups) { if (originalGroupSet.get(bottomGroup)) { topGroupSet.add(groupSetToAdd); } http://git-wip-us.apache.org/repos/asf/calcite/blob/4cc46130/core/src/main/java/org/apache/calcite/rel/rules/AggregateExtractProjectRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateExtractProjectRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateExtractProjectRule.java index 5559c97..08b12dd 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateExtractProjectRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateExtractProjectRule.java @@ -116,9 +116,12 @@ public class AggregateExtractProjectRule extends RelOptRule { final RexNode filterArg = aggCall.filterArg < 0 ? null : relBuilder.field(Mappings.apply(mapping, aggCall.filterArg)); newAggCallList.add( - relBuilder.aggregateCall(aggCall.getAggregation(), - aggCall.isDistinct(), aggCall.isApproximate(), - filterArg, aggCall.name, args)); + relBuilder.aggregateCall(aggCall.getAggregation(), args) + .distinct(aggCall.isDistinct()) + .filter(filterArg) + .approximate(aggCall.isApproximate()) + .approximate(aggCall.isApproximate()) + .as(aggCall.name)); } final RelBuilder.GroupKey groupKey = http://git-wip-us.apache.org/repos/asf/calcite/blob/4cc46130/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java b/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java index 974c57d..39bccbf 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java @@ -124,8 +124,8 @@ public abstract class SubQueryRemoveRule extends RelOptRule { ImmutableBitSet.of()); if (unique == null || !unique) { builder.aggregate(builder.groupKey(), - builder.aggregateCall(SqlStdOperatorTable.SINGLE_VALUE, false, - false, null, null, builder.field(0))); + builder.aggregateCall(SqlStdOperatorTable.SINGLE_VALUE, + builder.field(0))); } builder.join(JoinRelType.LEFT, builder.literal(true), variablesSet); return field(builder, inputCount, offset); @@ -385,8 +385,8 @@ public abstract class SubQueryRemoveRule extends RelOptRule { // Builds the cross join builder.aggregate(builder.groupKey(), builder.count(false, "c"), - builder.aggregateCall(SqlStdOperatorTable.COUNT, false, false, null, - "ck", builder.fields())); + builder.aggregateCall(SqlStdOperatorTable.COUNT, builder.fields()) + .as("ck")); builder.as("ct"); if (!variablesSet.isEmpty()) { builder.join(JoinRelType.LEFT, builder.literal(true), variablesSet); http://git-wip-us.apache.org/repos/asf/calcite/blob/4cc46130/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java index 733ee02..e9031ba 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java @@ -867,9 +867,11 @@ public class RelFieldTrimmer implements ReflectiveVisitor { final RexNode filterArg = aggCall.filterArg < 0 ? null : relBuilder.field(Mappings.apply(inputMapping, aggCall.filterArg)); RelBuilder.AggCall newAggCall = - relBuilder.aggregateCall(aggCall.getAggregation(), - aggCall.isDistinct(), aggCall.isApproximate(), - filterArg, aggCall.name, args); + relBuilder.aggregateCall(aggCall.getAggregation(), args) + .distinct(aggCall.isDistinct()) + .filter(filterArg) + .approximate(aggCall.isApproximate()) + .as(aggCall.name); mapping.set(j, groupCount + indicatorCount + newAggCallList.size()); newAggCallList.add(newAggCall); } http://git-wip-us.apache.org/repos/asf/calcite/blob/4cc46130/core/src/main/java/org/apache/calcite/tools/PigRelBuilder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/tools/PigRelBuilder.java b/core/src/main/java/org/apache/calcite/tools/PigRelBuilder.java index dcac18b..50738cd 100644 --- a/core/src/main/java/org/apache/calcite/tools/PigRelBuilder.java +++ b/core/src/main/java/org/apache/calcite/tools/PigRelBuilder.java @@ -146,8 +146,7 @@ public class PigRelBuilder extends RelBuilder { cluster.getRexBuilder().makeCall(peek(1, 0).getRowType(), SqlStdOperatorTable.ROW, fields()); aggregate(groupKey.e, - aggregateCall(SqlStdOperatorTable.COLLECT, false, false, null, - getAlias(), row)); + aggregateCall(SqlStdOperatorTable.COLLECT, row).as(getAlias())); if (groupKey.i < n - 1) { push(r); List<RexNode> predicates = new ArrayList<>(); http://git-wip-us.apache.org/repos/asf/calcite/blob/4cc46130/core/src/main/java/org/apache/calcite/tools/RelBuilder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java index d2b5d5d..323f65a 100644 --- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java +++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java @@ -763,72 +763,129 @@ public class RelBuilder { @Deprecated // to be removed before 2.0 public AggCall aggregateCall(SqlAggFunction aggFunction, boolean distinct, RexNode filter, String alias, RexNode... operands) { - return aggregateCall(aggFunction, distinct, false, filter, alias, - ImmutableList.copyOf(operands)); + return aggregateCall(aggFunction, distinct, false, filter, + ImmutableList.of(), alias, ImmutableList.copyOf(operands)); } - /** Creates a call to an aggregate function. */ + @Deprecated // to be removed before 2.0 public AggCall aggregateCall(SqlAggFunction aggFunction, boolean distinct, boolean approximate, RexNode filter, String alias, RexNode... operands) { - return aggregateCall(aggFunction, distinct, approximate, filter, alias, - ImmutableList.copyOf(operands)); + return aggregateCall(aggFunction, distinct, approximate, filter, + ImmutableList.of(), alias, ImmutableList.copyOf(operands)); } @Deprecated // to be removed before 2.0 public AggCall aggregateCall(SqlAggFunction aggFunction, boolean distinct, RexNode filter, String alias, Iterable<? extends RexNode> operands) { - return aggregateCall(aggFunction, distinct, false, filter, alias, operands); + return aggregateCall(aggFunction, distinct, false, filter, + ImmutableList.of(), alias, ImmutableList.copyOf(operands)); } - /** Creates a call to an aggregate function. */ + @Deprecated // to be removed before 2.0 public AggCall aggregateCall(SqlAggFunction aggFunction, boolean distinct, boolean approximate, RexNode filter, String alias, Iterable<? extends RexNode> operands) { - if (filter != null) { - if (filter.getType().getSqlTypeName() != SqlTypeName.BOOLEAN) { - throw RESOURCE.filterMustBeBoolean().ex(); - } - if (filter.getType().isNullable()) { - filter = call(SqlStdOperatorTable.IS_TRUE, filter); - } - } + return aggregateCall(aggFunction, distinct, filter, alias, operands) + .approximate(approximate); + } + + /** Creates a call to an aggregate function. + * + * <p>To add other operands, apply + * {@link AggCall#filter(RexNode...)}, + * {@link AggCall#distinct()}, + * {@link AggCall#as}, + * {@link AggCall#sort} to the result. */ + public AggCall aggregateCall(SqlAggFunction aggFunction, + Iterable<? extends RexNode> operands) { + return aggregateCall(aggFunction, false, false, null, ImmutableList.of(), + null, ImmutableList.copyOf(operands)); + } + + /** Creates a call to an aggregate function. + * + * <p>To add other operands, apply + * {@link AggCall#filter(RexNode...)}, + * {@link AggCall#distinct()}, + * {@link AggCall#as}, + * {@link AggCall#sort} to the result. */ + public AggCall aggregateCall(SqlAggFunction aggFunction, + RexNode... operands) { + return aggregateCall(aggFunction, false, false, null, ImmutableList.of(), + null, ImmutableList.copyOf(operands)); + } + + /** Creates a call to an aggregate function with all applicable operands. */ + AggCall aggregateCall(SqlAggFunction aggFunction, boolean distinct, + boolean approximate, RexNode filter, ImmutableList<RexNode> orderKeys, + String alias, ImmutableList<RexNode> operands) { return new AggCallImpl(aggFunction, distinct, approximate, filter, alias, - ImmutableList.copyOf(operands)); + operands, orderKeys); + } + + /** Creates a call to the {@code COUNT} aggregate function. */ + public AggCall count(RexNode... operands) { + return count(false, null, operands); } - /** Creates a call to the COUNT aggregate function. */ + /** Creates a call to the {@code COUNT} aggregate function, + * optionally distinct and with an alias. */ public AggCall count(boolean distinct, String alias, RexNode... operands) { - return aggregateCall(SqlStdOperatorTable.COUNT, distinct, false, null, - alias, operands); + return aggregateCall(SqlStdOperatorTable.COUNT, distinct, null, alias, + ImmutableList.copyOf(operands)); } - /** Creates a call to the COUNT(*) aggregate function. */ + /** Creates a call to the {@code COUNT(*)} aggregate function. */ public AggCall countStar(String alias) { - return aggregateCall(SqlStdOperatorTable.COUNT, false, false, null, alias); + return count(false, alias); } - /** Creates a call to the SUM aggregate function. */ + /** Creates a call to the {@code SUM} aggregate function. */ + public AggCall sum(RexNode operand) { + return sum(false, null, operand); + } + + /** Creates a call to the {@code SUM} aggregate function, + * optionally distinct and with an alias. */ public AggCall sum(boolean distinct, String alias, RexNode operand) { - return aggregateCall(SqlStdOperatorTable.SUM, distinct, false, null, alias, - operand); + return aggregateCall(SqlStdOperatorTable.SUM, distinct, null, alias, + ImmutableList.of(operand)); } - /** Creates a call to the AVG aggregate function. */ + /** Creates a call to the {@code AVG} aggregate function. */ + public AggCall avg(RexNode operand) { + return avg(false, null, operand); + } + + /** Creates a call to the {@code AVG} aggregate function, + * optionally distinct and with an alias. */ public AggCall avg(boolean distinct, String alias, RexNode operand) { - return aggregateCall(SqlStdOperatorTable.AVG, distinct, false, null, alias, - operand); + return aggregateCall(SqlStdOperatorTable.AVG, distinct, null, alias, + ImmutableList.of(operand)); } - /** Creates a call to the MIN aggregate function. */ + /** Creates a call to the {@code MIN} aggregate function. */ + public AggCall min(RexNode operand) { + return min(null, operand); + } + + /** Creates a call to the {@code MIN} aggregate function, + * optionally with an alias. */ public AggCall min(String alias, RexNode operand) { - return aggregateCall(SqlStdOperatorTable.MIN, false, false, null, alias, - operand); + return aggregateCall(SqlStdOperatorTable.MIN, false, null, alias, + ImmutableList.of(operand)); + } + + /** Creates a call to the {@code MAX} aggregate function, + * optionally with an alias. */ + public AggCall max(RexNode operand) { + return max(null, operand); } - /** Creates a call to the MAX aggregate function. */ + /** Creates a call to the {@code MAX} aggregate function. */ public AggCall max(String alias, RexNode operand) { - return aggregateCall(SqlStdOperatorTable.MAX, false, false, null, alias, - operand); + return aggregateCall(SqlStdOperatorTable.MAX, false, null, alias, + ImmutableList.of(operand)); } // Methods for patterns @@ -2041,6 +2098,32 @@ public class RelBuilder { * * @see RelBuilder#aggregateCall */ public interface AggCall { + /** Returns a copy of this AggCall that applies a filter before aggregating + * values. */ + AggCall filter(RexNode condition); + + /** Returns a copy of this AggCall that sorts its input values by + * {@code orderKeys} before aggregating, as in SQL's {@code WITHIN GROUP} + * clause. */ + AggCall sort(Iterable<RexNode> orderKeys); + + /** Returns a copy of this AggCall that sorts its input values by + * {@code orderKeys} before aggregating, as in SQL's {@code WITHIN GROUP} + * clause. */ + AggCall sort(RexNode... orderKeys); + + /** Returns a copy of this AggCall that may return approximate results + * if {@code approximate} is true. */ + AggCall approximate(boolean approximate); + + /** Returns a copy of this AggCall with a given alias. */ + AggCall as(String alias); + + /** Returns a copy of this AggCall that is optionally distinct. */ + AggCall distinct(boolean distinct); + + /** Returns a copy of this AggCall that is distinct. */ + AggCall distinct(); } /** Information necessary to create the GROUP BY clause of an Aggregate. @@ -2081,23 +2164,79 @@ public class RelBuilder { } /** Implementation of {@link AggCall}. */ - private static class AggCallImpl implements AggCall { + private class AggCallImpl implements AggCall { private final SqlAggFunction aggFunction; private final boolean distinct; private final boolean approximate; - private final RexNode filter; - private final String alias; - private final ImmutableList<RexNode> operands; + private final RexNode filter; // may be null + private final String alias; // may be null + private final ImmutableList<RexNode> operands; // may be empty, never null + private final ImmutableList<RexNode> orderKeys; // may be empty, never null AggCallImpl(SqlAggFunction aggFunction, boolean distinct, boolean approximate, RexNode filter, - String alias, ImmutableList<RexNode> operands) { - this.aggFunction = aggFunction; + String alias, ImmutableList<RexNode> operands, + ImmutableList<RexNode> orderKeys) { + this.aggFunction = Objects.requireNonNull(aggFunction); this.distinct = distinct; this.approximate = approximate; - this.filter = filter; this.alias = alias; - this.operands = operands; + this.operands = Objects.requireNonNull(operands); + this.orderKeys = Objects.requireNonNull(orderKeys); + if (filter != null) { + if (filter.getType().getSqlTypeName() != SqlTypeName.BOOLEAN) { + throw RESOURCE.filterMustBeBoolean().ex(); + } + if (filter.getType().isNullable()) { + filter = call(SqlStdOperatorTable.IS_TRUE, filter); + } + } + this.filter = filter; + } + + public AggCall sort(Iterable<RexNode> orderKeys) { + final ImmutableList<RexNode> orderKeyList = + ImmutableList.copyOf(orderKeys); + return orderKeyList.equals(this.orderKeys) + ? this + : new AggCallImpl(aggFunction, distinct, approximate, filter, + alias, operands, orderKeyList); + } + + public AggCall sort(RexNode... orderKeys) { + return sort(ImmutableList.copyOf(orderKeys)); + } + + public AggCall approximate(boolean approximate) { + return approximate == this.approximate + ? this + : new AggCallImpl(aggFunction, distinct, approximate, filter, + alias, operands, orderKeys); + } + + public AggCall filter(RexNode condition) { + return Objects.equals(condition, this.filter) + ? this + : new AggCallImpl(aggFunction, distinct, approximate, condition, + alias, operands, orderKeys); + } + + public AggCall as(String alias) { + return Objects.equals(alias, this.alias) + ? this + : new AggCallImpl(aggFunction, distinct, approximate, filter, + alias, operands, orderKeys); + } + + public AggCall distinct(boolean distinct) { + return distinct == this.distinct + ? this + : new AggCallImpl(aggFunction, distinct, approximate, filter, + alias, operands, orderKeys); + } + + public AggCall distinct() { + return distinct(true); } } @@ -2109,6 +2248,34 @@ public class RelBuilder { AggCallImpl2(AggregateCall aggregateCall) { this.aggregateCall = Objects.requireNonNull(aggregateCall); } + + public AggCall sort(Iterable<RexNode> orderKeys) { + throw new UnsupportedOperationException(); + } + + public AggCall sort(RexNode... orderKeys) { + throw new UnsupportedOperationException(); + } + + public AggCall approximate(boolean approximate) { + throw new UnsupportedOperationException(); + } + + public AggCall filter(RexNode condition) { + throw new UnsupportedOperationException(); + } + + public AggCall as(String alias) { + throw new UnsupportedOperationException(); + } + + public AggCall distinct(boolean distinct) { + throw new UnsupportedOperationException(); + } + + public AggCall distinct() { + throw new UnsupportedOperationException(); + } } /** Collects the extra expressions needed for {@link #aggregate}. http://git-wip-us.apache.org/repos/asf/calcite/blob/4cc46130/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java index 70bf317..94b98b7 100644 --- a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java +++ b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java @@ -274,8 +274,8 @@ public class RelToSqlConverterTest { final RelNode root = builder .scan("EMP") .aggregate(builder.groupKey(), - builder.aggregateCall(SqlStdOperatorTable.SUM0, false, false, null, - "s", builder.field(3))) + builder.aggregateCall(SqlStdOperatorTable.SUM0, false, null, "s", + builder.field(3))) .build(); final String expectedMysql = "SELECT COALESCE(SUM(`MGR`), 0) AS `s`\n" + "FROM `scott`.`EMP`"; http://git-wip-us.apache.org/repos/asf/calcite/blob/4cc46130/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java index 3624204..e3d5b95 100644 --- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java +++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java @@ -505,7 +505,6 @@ public class RelBuilderTest { builder.literal(20))) .aggregate(builder.groupKey(0, 1, 2), builder.aggregateCall(SqlStdOperatorTable.SUM, - false, false, null, null, builder.field(0))) .project(builder.field("c"), builder.field("a")) @@ -661,8 +660,7 @@ public class RelBuilderTest { RelNode root = builder.scan("EMP") .aggregate(builder.groupKey(), - builder.aggregateCall(SqlStdOperatorTable.COUNT, true, false, - null, "C", builder.field("DEPTNO"))) + builder.count(true, "C", builder.field("DEPTNO"))) .build(); final String expected = "" + "LogicalAggregate(group=[{}], C=[COUNT(DISTINCT $7)])\n" @@ -684,12 +682,10 @@ public class RelBuilderTest { builder.field(4), builder.field(3)), builder.field(1)), - builder.aggregateCall(SqlStdOperatorTable.COUNT, false, false, - null, "C"), - builder.aggregateCall(SqlStdOperatorTable.SUM, false, false, - null, "S", + builder.countStar("C"), + builder.sum( builder.call(SqlStdOperatorTable.PLUS, builder.field(3), - builder.literal(1)))) + builder.literal(1))).as("S")) .build(); final String expected = "" + "LogicalAggregate(group=[{1, 8}], C=[COUNT()], S=[SUM($9)])\n" @@ -711,12 +707,9 @@ public class RelBuilderTest { final RelBuilder builder = RelBuilder.create(config().build()); RelNode root = builder.scan("EMP") - .aggregate( - builder.groupKey(builder.field(1)), - builder.aggregateCall(SqlStdOperatorTable.COUNT, false, false, - null, "C")) - .aggregate( - builder.groupKey(builder.field(0))) + .aggregate(builder.groupKey(builder.field(1)), + builder.count().as("C")) + .aggregate(builder.groupKey(builder.field(0))) .build(); final String expected = "" + "LogicalProject(ENAME=[$0])\n" @@ -738,8 +731,7 @@ public class RelBuilderTest { builder.scan("EMP") .aggregate( builder.groupKey(builder.field(1)), - builder.aggregateCall(SqlStdOperatorTable.COUNT, false, false, - null, "C")) + builder.count().as("C")) .filter( builder.call(SqlStdOperatorTable.GREATER_THAN, builder.field(1), builder.literal(3))) @@ -766,9 +758,11 @@ public class RelBuilderTest { builder.groupKey(ImmutableBitSet.of(7), ImmutableList.of(ImmutableBitSet.of(7), ImmutableBitSet.of())), - builder.aggregateCall(SqlStdOperatorTable.COUNT, false, false, - builder.call(SqlStdOperatorTable.GREATER_THAN, - builder.field("EMPNO"), builder.literal(100)), "C")) + builder.count() + .filter( + builder.call(SqlStdOperatorTable.GREATER_THAN, + builder.field("EMPNO"), builder.literal(100))) + .as("C")) .build(); final String expected = "" + "LogicalAggregate(group=[{7}], groups=[[{7}, {}]], C=[COUNT() FILTER $8])\n" @@ -788,8 +782,9 @@ public class RelBuilderTest { builder.scan("EMP") .aggregate( builder.groupKey(builder.field("DEPTNO")), - builder.aggregateCall(SqlStdOperatorTable.SUM, false, false, - builder.field("COMM"), "C", builder.field("SAL"))) + builder.sum(builder.field("SAL")) + .filter(builder.field("COMM")) + .as("C")) .build(); fail("expected error, got " + root); } catch (CalciteException e) { @@ -808,10 +803,11 @@ public class RelBuilderTest { builder.scan("EMP") .aggregate( builder.groupKey(builder.field("DEPTNO")), - builder.aggregateCall(SqlStdOperatorTable.SUM, false, false, - builder.call(SqlStdOperatorTable.LESS_THAN, - builder.field("COMM"), builder.literal(100)), "C", - builder.field("SAL"))) + builder.sum(builder.field("SAL")) + .filter( + builder.call(SqlStdOperatorTable.LESS_THAN, + builder.field("COMM"), builder.literal(100))) + .as("C")) .build(); final String expected = "" + "LogicalAggregate(group=[{7}], C=[SUM($5) FILTER $8])\n" @@ -912,8 +908,8 @@ public class RelBuilderTest { RelNode root = builder.scan("EMP") .aggregate(builder.groupKey(6, 7), - builder.aggregateCall(SqlStdOperatorTable.GROUPING, false, - false, null, "g", builder.field("DEPTNO"))) + builder.aggregateCall(SqlStdOperatorTable.GROUPING, + builder.field("DEPTNO")).as("g")) .build(); final String expected = "" + "LogicalAggregate(group=[{6, 7}], g=[GROUPING($7)])\n" @@ -927,8 +923,10 @@ public class RelBuilderTest { RelNode root = builder.scan("EMP") .aggregate(builder.groupKey(6, 7), - builder.aggregateCall(SqlStdOperatorTable.GROUPING, true, - false, null, "g", builder.field("DEPTNO"))) + builder.aggregateCall(SqlStdOperatorTable.GROUPING, + builder.field("DEPTNO")) + .distinct(true) + .as("g")) .build(); fail("expected error, got " + root); } catch (IllegalArgumentException e) { @@ -942,9 +940,10 @@ public class RelBuilderTest { RelNode root = builder.scan("EMP") .aggregate(builder.groupKey(6, 7), - builder.aggregateCall(SqlStdOperatorTable.GROUPING, false, - false, builder.literal(true), "g", - builder.field("DEPTNO"))) + builder.aggregateCall(SqlStdOperatorTable.GROUPING, + builder.field("DEPTNO")) + .filter(builder.literal(true)) + .as("g")) .build(); fail("expected error, got " + root); } catch (IllegalArgumentException e) { @@ -1482,8 +1481,7 @@ public class RelBuilderTest { .project(builder.field("DEPTNO"), builder.literal(20)) .aggregate(builder.groupKey(builder.field("EMP_alias", "DEPTNO")), - builder.aggregateCall(SqlStdOperatorTable.SUM, false, false, - null, null, builder.field(1))) + builder.sum(builder.field(1))) .project(builder.alias(builder.field(1), "sum"), builder.field("EMP_alias", "DEPTNO")) .build(); http://git-wip-us.apache.org/repos/asf/calcite/blob/4cc46130/site/_docs/algebra.md ---------------------------------------------------------------------- diff --git a/site/_docs/algebra.md b/site/_docs/algebra.md index 2b5c66a..e5b505b 100644 --- a/site/_docs/algebra.md +++ b/site/_docs/algebra.md @@ -390,9 +390,21 @@ The following methods return an | Method | Description |:------------------- |:----------- -| `aggregateCall(op, distinct, approximate, filter, alias, expr...)`<br/>`aggregateCall(op, distinct, approximate, filter, alias, exprList)` | Creates a call to a given aggregate function, with an optional filter expression -| `count(distinct, alias, expr...)` | Creates a call to the COUNT aggregate function +| `aggregateCall(op, distinct, approximate, filter, orderKeys, alias, expr...)`<br/>`aggregateCall(op, distinct, approximate, filter, orderKeys, alias, exprList)` | Creates a call to a given aggregate function, with an optional filter expression and a list of optional ordering keys (for sorting input values before aggregation) +| `count( [ distinct, alias, ] expr...)` | Creates a call to the COUNT aggregate function | `countStar(alias)` | Creates a call to the COUNT(*) aggregate function -| `sum(distinct, alias, expr)` | Creates a call to the SUM aggregate function -| `min(alias, expr)` | Creates a call to the MIN aggregate function -| `max(alias, expr)` | Creates a call to the MAX aggregate function +| `sum( [ distinct, alias, ] expr)` | Creates a call to the SUM aggregate function +| `min( [ alias, ] expr)` | Creates a call to the MIN aggregate function +| `max( [ alias, ] expr)` | Creates a call to the MAX aggregate function + +To further modify the `AggCall`, call its methods: + +| Method | Description +|:-------------------- |:----------- +| `distinct()` | Eliminates duplicate values before aggregating (see SQL `DISTINCT`) +| `distinct(distinct)` | Eliminates duplicate values before aggregating if `distinct` +| `as(alias)` | Assigns a column alias to this expression (see SQL `AS`) +| `filter(expr)` | Filters rows before aggregating (see SQL `FILTER (WHERE ...)`) +| `sort(expr, ...)`<br/>`sort(exprList)` | Sorts rows before aggregating (see SQL `WITHIN GROUP`) +| `approximate(approximate)` | Allows approximate value for the aggregate of `approximate` +
