You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by mm...@apache.org on 2017/09/05 14:36:57 UTC

[14/16] calcite git commit: [CALCITE-1069] In Aggregate, deprecate indicators, and allow GROUPING to be used as an aggregate function

[CALCITE-1069] In Aggregate, deprecate indicators, and allow GROUPING to be used as an aggregate function

Deprecate the Aggregate.indicator field (strongly encouraging people
to set it to false) and to allow GROUPING (and its synonym, GROUP_ID)
to be used as an aggregate function. It will be handled at implement
time.

With indicator = false, even queries with more than one grouping set
will just output the join keys and the aggregate functions. A join key
will be nullable if it doesn't appear in all grouping sets.

The output row type of Aggregate will be more consistent, and this will
have benefits such as fewer bugs in rules.

Add RelBuilder.rename().

Remove SqlValidatorNamespace.translate() and
SqlQualified.suffixTranslated().

Mute deprecation warnings.

Remove MutableAggregate.indicator.

Close apache/calcite#470


Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/1e7ae1c3
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/1e7ae1c3
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/1e7ae1c3

Branch: refs/heads/branch-1.14
Commit: 1e7ae1c30a5e6f4335f2e4cc0059f2f2901e35fd
Parents: ddae841
Author: Julian Hyde <jh...@apache.org>
Authored: Wed Mar 22 12:33:46 2017 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Aug 29 21:01:50 2017 -0700

----------------------------------------------------------------------
 .../calcite/adapter/enumerable/AggContext.java  |  19 +
 .../adapter/enumerable/AggResultContext.java    |  14 +
 .../adapter/enumerable/EnumerableAggregate.java | 108 +++--
 .../adapter/enumerable/EnumerableWindow.java    |  17 +
 .../calcite/adapter/enumerable/RexImpTable.java |  60 +++
 .../enumerable/impl/AggAddContextImpl.java      |   2 +-
 .../enumerable/impl/AggResetContextImpl.java    |  14 +-
 .../enumerable/impl/AggResultContextImpl.java   |  36 +-
 .../impl/WinAggResultContextImpl.java           |   2 +-
 .../org/apache/calcite/plan/RelOptUtil.java     |  15 +-
 .../calcite/plan/SubstitutionVisitor.java       |   5 +-
 .../org/apache/calcite/rel/core/Aggregate.java  |  30 +-
 .../apache/calcite/rel/core/RelFactories.java   |   1 +
 .../calcite/rel/logical/LogicalAggregate.java   |  15 +
 .../calcite/rel/mutable/MutableAggregate.java   |  19 +-
 .../apache/calcite/rel/mutable/MutableRels.java |   7 +-
 .../rel/rules/AbstractMaterializedViewRule.java |   4 +-
 .../AggregateExpandDistinctAggregatesRule.java  | 149 +++---
 .../rel/rules/AggregateFilterTransposeRule.java |   4 +-
 .../rel/rules/AggregateJoinTransposeRule.java   |   4 +-
 .../rel/rules/AggregateProjectMergeRule.java    |   2 +-
 .../AggregateProjectPullUpConstantsRule.java    |   4 +-
 .../rel/rules/AggregateReduceFunctionsRule.java |   1 -
 .../rel/rules/AggregateUnionAggregateRule.java  |   2 +-
 .../rel/rules/AggregateUnionTransposeRule.java  |   4 +-
 .../rel/rules/FilterAggregateTransposeRule.java |   2 +-
 .../rel/rules/IntersectToDistinctRule.java      |   2 +-
 .../apache/calcite/rel/stream/StreamRules.java  |   7 +-
 .../apache/calcite/runtime/CalciteResource.java |   3 -
 .../org/apache/calcite/sql/SqlAggFunction.java  |   6 +
 .../sql/fun/SqlAbstractGroupFunction.java       |  16 +-
 .../calcite/sql/fun/SqlGroupIdFunction.java     |   5 +-
 .../calcite/sql/fun/SqlGroupingFunction.java    |   7 +
 .../calcite/sql/fun/SqlStdOperatorTable.java    |  16 +-
 .../apache/calcite/sql/validate/AggFinder.java  |   5 +-
 .../sql/validate/AggregatingSelectScope.java    |   2 -
 .../sql/validate/DelegatingNamespace.java       |   4 -
 .../sql/validate/IdentifierNamespace.java       |   4 -
 .../calcite/sql/validate/SqlQualified.java      |  33 +-
 .../calcite/sql/validate/SqlValidatorImpl.java  |  11 +-
 .../sql/validate/SqlValidatorNamespace.java     |   5 -
 .../apache/calcite/sql2rel/RelDecorrelator.java |  12 +-
 .../apache/calcite/sql2rel/RelFieldTrimmer.java |   4 +-
 .../calcite/sql2rel/SqlToRelConverter.java      | 151 ++----
 .../org/apache/calcite/tools/RelBuilder.java    |  87 +++-
 .../calcite/runtime/CalciteResource.properties  |   1 -
 .../org/apache/calcite/plan/RelWriterTest.java  |   3 +-
 .../org/apache/calcite/test/RelBuilderTest.java | 114 ++++-
 .../apache/calcite/test/RelMetadataTest.java    |   4 +-
 .../apache/calcite/test/SqlValidatorTest.java   |  45 +-
 .../org/apache/calcite/test/RelOptRulesTest.xml | 455 +++++++++----------
 .../calcite/test/SqlToRelConverterTest.xml      |  91 ++--
 core/src/test/resources/sql/agg.iq              | 295 +++++++++---
 53 files changed, 1144 insertions(+), 784 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/adapter/enumerable/AggContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/AggContext.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/AggContext.java
index 542e3a2..70e464a 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/AggContext.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/AggContext.java
@@ -18,6 +18,7 @@ package org.apache.calcite.adapter.enumerable;
 
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.sql.SqlAggFunction;
+import org.apache.calcite.util.ImmutableBitSet;
 
 import java.lang.reflect.Type;
 import java.util.List;
@@ -67,6 +68,24 @@ public interface AggContext {
    * @return Parameter types of the aggregate
    */
   List<? extends Type> parameterTypes();
+
+  /** Returns the ordinals of the input fields that make up the key. */
+  List<Integer> keyOrdinals();
+
+  /**
+   * Returns the types of the group key as
+   * {@link org.apache.calcite.rel.type.RelDataType}.
+   */
+  List<? extends RelDataType> keyRelTypes();
+
+  /**
+   * Returns the types of the group key as
+   * {@link java.lang.reflect.Type}.
+   */
+  List<? extends Type> keyTypes();
+
+  /** Returns the grouping sets we are aggregating on. */
+  List<ImmutableBitSet> groupSets();
 }
 
 // End AggContext.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/adapter/enumerable/AggResultContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/AggResultContext.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/AggResultContext.java
index fe7ee06..f80dd2b 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/AggResultContext.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/AggResultContext.java
@@ -16,6 +16,9 @@
  */
 package org.apache.calcite.adapter.enumerable;
 
+import org.apache.calcite.linq4j.tree.Expression;
+import org.apache.calcite.rel.core.AggregateCall;
+
 /**
  * Information for a call to
  * {@link AggImplementor#implementResult(AggContext, AggResultContext)}
@@ -25,6 +28,17 @@ package org.apache.calcite.adapter.enumerable;
  * implementation MUST NOT destroy the contents of {@link #accumulator()}.
  */
 public interface AggResultContext extends NestedBlockBuilder, AggResetContext {
+  /** Expression by which to reference the key upon which the values in the
+   * accumulator were aggregated. Most aggregate functions depend on only the
+   * accumulator, but quasi-aggregate functions such as GROUPING access at the
+   * key. */
+  Expression key();
+
+  /** Returns an expression that references the {@code i}th field of the key,
+   * cast to the appropriate type. */
+  Expression keyField(int i);
+
+  AggregateCall call();
 }
 
 // End AggResultContext.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java
index 2d8c497..4d6fb05 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java
@@ -46,6 +46,8 @@ import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 
 import java.lang.reflect.Type;
@@ -66,6 +68,8 @@ public class EnumerableAggregate extends Aggregate implements EnumerableRel {
       List<AggregateCall> aggCalls)
       throws InvalidRelException {
     super(cluster, traitSet, child, indicator, groupSet, groupSets, aggCalls);
+    Preconditions.checkArgument(!indicator,
+        "EnumerableAggregate no longer supports indicator fields");
     assert getConvention() instanceof EnumerableConvention;
 
     for (AggregateCall aggCall : aggCalls) {
@@ -104,7 +108,6 @@ public class EnumerableAggregate extends Aggregate implements EnumerableRel {
         builder.append(
             "child",
             result.block);
-    final RelDataType inputRowType = getInput().getRowType();
 
     final PhysType physType =
         PhysTypeImpl.of(
@@ -178,7 +181,6 @@ public class EnumerableAggregate extends Aggregate implements EnumerableRel {
         inputPhysType.project(groupSet.asList(), getGroupType() != Group.SIMPLE,
             JavaRowFormat.LIST);
     final int groupCount = getGroupCount();
-    final int indicatorCount = getIndicatorCount();
 
     final List<AggImpState> aggs = new ArrayList<>(aggCalls.size());
     for (Ord<AggregateCall> call : Ord.zip(aggCalls)) {
@@ -196,34 +198,11 @@ public class EnumerableAggregate extends Aggregate implements EnumerableRel {
 
     final List<Type> aggStateTypes = new ArrayList<>();
     for (final AggImpState agg : aggs) {
-      agg.context =
-          new AggContext() {
-            public SqlAggFunction aggregation() {
-              return agg.call.getAggregation();
-            }
-
-            public RelDataType returnRelType() {
-              return agg.call.type;
-            }
-
-            public Type returnType() {
-              return EnumUtils.javaClass(typeFactory, returnRelType());
-            }
-
-            public List<? extends RelDataType> parameterRelTypes() {
-              return EnumUtils.fieldRowTypes(inputRowType, null,
-                  agg.call.getArgList());
-            }
-
-            public List<? extends Type> parameterTypes() {
-              return EnumUtils.fieldTypes(typeFactory,
-                  parameterRelTypes());
-            }
-          };
-      List<Type> state =
-          agg.implementor.getStateType(agg.context);
+      agg.context = new AggContextImpl(agg, typeFactory);
+      final List<Type> state = agg.implementor.getStateType(agg.context);
 
       if (state.isEmpty()) {
+        agg.state = ImmutableList.of();
         continue;
       }
 
@@ -246,12 +225,11 @@ public class EnumerableAggregate extends Aggregate implements EnumerableRel {
       agg.state = decls;
       initExpressions.addAll(decls);
       agg.implementor.implementReset(agg.context,
-          new AggResultContextImpl(initBlock, decls));
+          new AggResultContextImpl(initBlock, agg.call, decls, null, null));
     }
 
     final PhysType accPhysType =
-        PhysTypeImpl.of(
-            typeFactory,
+        PhysTypeImpl.of(typeFactory,
             typeFactory.createSyntheticType(aggStateTypes));
 
 
@@ -369,15 +347,24 @@ public class EnumerableAggregate extends Aggregate implements EnumerableRel {
     } else {
       final Type keyType = keyPhysType.getJavaRowType();
       key_ = Expressions.parameter(keyType, "key");
-      for (int j = 0; j < groupCount + indicatorCount; j++) {
-        results.add(
-            keyPhysType.fieldReference(key_, j));
+      for (int j = 0; j < groupCount; j++) {
+        final Expression ref = keyPhysType.fieldReference(key_, j);
+        if (getGroupType() == Group.SIMPLE) {
+          results.add(ref);
+        } else {
+          results.add(
+              Expressions.condition(
+                  keyPhysType.fieldReference(key_, groupCount + j),
+                  Expressions.constant(null),
+                  Expressions.box(ref)));
+        }
       }
     }
     for (final AggImpState agg : aggs) {
       results.add(
           agg.implementor.implementResult(agg.context,
-              new AggResultContextImpl(resultBlock, agg.state)));
+              new AggResultContextImpl(resultBlock, agg.call, agg.state, key_,
+                  keyPhysType)));
     }
     resultBlock.add(physType.record(results));
     if (getGroupType() != Group.SIMPLE) {
@@ -461,6 +448,57 @@ public class EnumerableAggregate extends Aggregate implements EnumerableRel {
     }
     return implementor.result(physType, builder.toBlock());
   }
+
+  /** An implementation of {@link AggContext}. */
+  private class AggContextImpl implements AggContext {
+    private final AggImpState agg;
+    private final JavaTypeFactory typeFactory;
+
+    AggContextImpl(AggImpState agg, JavaTypeFactory typeFactory) {
+      this.agg = agg;
+      this.typeFactory = typeFactory;
+    }
+
+    public SqlAggFunction aggregation() {
+      return agg.call.getAggregation();
+    }
+
+    public RelDataType returnRelType() {
+      return agg.call.type;
+    }
+
+    public Type returnType() {
+      return EnumUtils.javaClass(typeFactory, returnRelType());
+    }
+
+    public List<? extends RelDataType> parameterRelTypes() {
+      return EnumUtils.fieldRowTypes(getInput().getRowType(), null,
+          agg.call.getArgList());
+    }
+
+    public List<? extends Type> parameterTypes() {
+      return EnumUtils.fieldTypes(
+          typeFactory,
+          parameterRelTypes());
+    }
+
+    public List<ImmutableBitSet> groupSets() {
+      return groupSets;
+    }
+
+    public List<Integer> keyOrdinals() {
+      return groupSet.asList();
+    }
+
+    public List<? extends RelDataType> keyRelTypes() {
+      return EnumUtils.fieldRowTypes(getInput().getRowType(), null,
+          groupSet.asList());
+    }
+
+    public List<? extends Type> keyTypes() {
+      return EnumUtils.fieldTypes(typeFactory, keyRelTypes());
+    }
+  }
 }
 
 // End EnumerableAggregate.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java
index 9afee80..0e32225 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java
@@ -49,6 +49,7 @@ import org.apache.calcite.rex.RexWindowBound;
 import org.apache.calcite.runtime.SortedMultiMap;
 import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.util.BuiltInMethod;
+import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
@@ -788,6 +789,22 @@ public class EnumerableWindow extends Window implements EnumerableRel {
               return EnumUtils.fieldRowTypes(result.physType.getRowType(),
                   constants, agg.call.getArgList());
             }
+
+            public List<ImmutableBitSet> groupSets() {
+              throw new UnsupportedOperationException();
+            }
+
+            public List<Integer> keyOrdinals() {
+              throw new UnsupportedOperationException();
+            }
+
+            public List<? extends RelDataType> keyRelTypes() {
+              throw new UnsupportedOperationException();
+            }
+
+            public List<? extends Type> keyTypes() {
+              throw new UnsupportedOperationException();
+            }
           };
       String aggName = "a" + agg.aggIdx;
       if (CalcitePrepareImpl.DEBUG) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
index 17cb540..0c1f542 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
@@ -53,6 +53,7 @@ import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.validate.SqlUserDefinedAggFunction;
 import org.apache.calcite.sql.validate.SqlUserDefinedFunction;
 import org.apache.calcite.util.BuiltInMethod;
+import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.Util;
 
 import com.google.common.base.Supplier;
@@ -129,6 +130,9 @@ import static org.apache.calcite.sql.fun.SqlStdOperatorTable.FIRST_VALUE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.FLOOR;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.GREATER_THAN;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.GREATER_THAN_OR_EQUAL;
+import static org.apache.calcite.sql.fun.SqlStdOperatorTable.GROUPING;
+import static org.apache.calcite.sql.fun.SqlStdOperatorTable.GROUPING_ID;
+import static org.apache.calcite.sql.fun.SqlStdOperatorTable.GROUP_ID;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.INITCAP;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_FALSE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_NOT_FALSE;
@@ -410,6 +414,11 @@ public class RexImpTable {
     aggMap.put(MAX, minMax);
     aggMap.put(SINGLE_VALUE, constructorSupplier(SingleValueImplementor.class));
     aggMap.put(COLLECT, constructorSupplier(CollectImplementor.class));
+    final Supplier<GroupingImplementor> grouping =
+        constructorSupplier(GroupingImplementor.class);
+    aggMap.put(GROUPING, grouping);
+    aggMap.put(GROUP_ID, grouping);
+    aggMap.put(GROUPING_ID, grouping);
     winAggMap.put(RANK, constructorSupplier(RankImplementor.class));
     winAggMap.put(DENSE_RANK, constructorSupplier(DenseRankImplementor.class));
     winAggMap.put(ROW_NUMBER, constructorSupplier(RowNumberImplementor.class));
@@ -1229,6 +1238,57 @@ public class RexImpTable {
     }
   }
 
+  /** Implementor for the {@code GROUPING} aggregate function. */
+  static class GroupingImplementor implements AggImplementor {
+    public List<Type> getStateType(AggContext info) {
+      return ImmutableList.of();
+    }
+
+    public void implementReset(AggContext info, AggResetContext reset) {
+    }
+
+    public void implementAdd(AggContext info, AggAddContext add) {
+    }
+
+    public Expression implementResult(AggContext info,
+        AggResultContext result) {
+      final List<Integer> keys;
+      switch (info.aggregation().kind) {
+      case GROUPING: // "GROUPING(e, ...)", also "GROUPING_ID(e, ...)"
+        keys = result.call().getArgList();
+        break;
+      case GROUP_ID: // "GROUP_ID()"
+        // We don't implement GROUP_ID properly. In most circumstances, it
+        // returns 0, so we always return 0. Logged
+        // [CALCITE-1824] GROUP_ID returns wrong result
+        keys = ImmutableIntList.of();
+        break;
+      default:
+        throw new AssertionError();
+      }
+      Expression e = null;
+      if (info.groupSets().size() > 1) {
+        final List<Integer> keyOrdinals = info.keyOrdinals();
+        long x = 1L << (keys.size() - 1);
+        for (int k : keys) {
+          final int i = keyOrdinals.indexOf(k);
+          assert i >= 0;
+          final Expression e2 =
+              Expressions.condition(result.keyField(keyOrdinals.size() + i),
+                  Expressions.constant(x),
+                  Expressions.constant(0L));
+          if (e == null) {
+            e = e2;
+          } else {
+            e = Expressions.add(e, e2);
+          }
+          x >>= 1;
+        }
+      }
+      return e != null ? e : Expressions.constant(0, info.returnType());
+    }
+  }
+
   /** Implementor for user-defined aggregate functions. */
   public static class UserDefinedAggReflectiveImplementor
       extends StrictAggImplementor {

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggAddContextImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggAddContextImpl.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggAddContextImpl.java
index 18ba8cc..8d575bf 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggAddContextImpl.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggAddContextImpl.java
@@ -29,7 +29,7 @@ import java.util.List;
 public abstract class AggAddContextImpl extends AggResultContextImpl
     implements AggAddContext {
   public AggAddContextImpl(BlockBuilder block, List<Expression> accumulator) {
-    super(block, accumulator);
+    super(block, null, accumulator, null, null);
   }
 
   public final List<Expression> arguments() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggResetContextImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggResetContextImpl.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggResetContextImpl.java
index 3e66705..c159073 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggResetContextImpl.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggResetContextImpl.java
@@ -20,6 +20,7 @@ import org.apache.calcite.adapter.enumerable.AggResetContext;
 import org.apache.calcite.adapter.enumerable.NestedBlockBuilderImpl;
 import org.apache.calcite.linq4j.tree.BlockBuilder;
 import org.apache.calcite.linq4j.tree.Expression;
+import org.apache.calcite.rel.core.AggregateCall;
 
 import java.util.List;
 
@@ -27,14 +28,15 @@ import java.util.List;
  * Implementation of
  * {@link org.apache.calcite.adapter.enumerable.AggResetContext}
  */
-public class AggResetContextImpl extends NestedBlockBuilderImpl
+public abstract class AggResetContextImpl extends NestedBlockBuilderImpl
     implements AggResetContext {
   private final List<Expression> accumulator;
 
   /**
-   * Creates aggregate reset context
-   * @param block code block that will contain the added initialization
-   * @param accumulator accumulator variables that store the intermediate
+   * Creates aggregate reset context.
+   *
+   * @param block Code block that will contain the added initialization
+   * @param accumulator Accumulator variables that store the intermediate
    *                    aggregate state
    */
   public AggResetContextImpl(BlockBuilder block, List<Expression> accumulator) {
@@ -45,6 +47,10 @@ public class AggResetContextImpl extends NestedBlockBuilderImpl
   public List<Expression> accumulator() {
     return accumulator;
   }
+
+  public AggregateCall call() {
+    throw new UnsupportedOperationException();
+  }
 }
 
 // End AggResetContextImpl.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggResultContextImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggResultContextImpl.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggResultContextImpl.java
index 1da28c6..6e02756 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggResultContextImpl.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggResultContextImpl.java
@@ -17,8 +17,11 @@
 package org.apache.calcite.adapter.enumerable.impl;
 
 import org.apache.calcite.adapter.enumerable.AggResultContext;
+import org.apache.calcite.adapter.enumerable.PhysType;
 import org.apache.calcite.linq4j.tree.BlockBuilder;
 import org.apache.calcite.linq4j.tree.Expression;
+import org.apache.calcite.linq4j.tree.ParameterExpression;
+import org.apache.calcite.rel.core.AggregateCall;
 
 import java.util.List;
 
@@ -28,15 +31,38 @@ import java.util.List;
  */
 public class AggResultContextImpl extends AggResetContextImpl
     implements AggResultContext {
+  private final AggregateCall call;
+  private final ParameterExpression key;
+  private final PhysType keyPhysType;
+
   /**
-   * Creates aggregate result context
-   * @param block code block that will contain the result calculation statements
-   * @param accumulator accumulator variables that store the intermediate
+   * Creates aggregate result context.
+   *
+   * @param block Code block that will contain the result calculation statements
+   * @param call Aggregate call
+   * @param accumulator Accumulator variables that store the intermediate
    *                    aggregate state
+   * @param key Key
    */
-  public AggResultContextImpl(BlockBuilder block,
-      List<Expression> accumulator) {
+  public AggResultContextImpl(BlockBuilder block, AggregateCall call,
+      List<Expression> accumulator, ParameterExpression key,
+      PhysType keyPhysType) {
     super(block, accumulator);
+    this.call = call;
+    this.key = key;
+    this.keyPhysType = keyPhysType;
+  }
+
+  public Expression key() {
+    return key;
+  }
+
+  public Expression keyField(int i) {
+    return keyPhysType.fieldReference(key, i);
+  }
+
+  @Override public AggregateCall call() {
+    return call;
   }
 }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/WinAggResultContextImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/WinAggResultContextImpl.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/WinAggResultContextImpl.java
index d4a5c6f..df0d639 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/WinAggResultContextImpl.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/WinAggResultContextImpl.java
@@ -45,7 +45,7 @@ public abstract class WinAggResultContextImpl extends AggResultContextImpl
   public WinAggResultContextImpl(BlockBuilder block,
       List<Expression> accumulator,
       Function<BlockBuilder, WinAggFrameResultContext> frameContextBuilder) {
-    super(block, accumulator);
+    super(block, null, accumulator, null, null);
     this.frame = frameContextBuilder;
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
index 5c4aa0b..238cf3c 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -508,7 +508,7 @@ public abstract class RelOptUtil {
               extraName);
 
       ret =
-          LogicalAggregate.create(ret, false,
+          LogicalAggregate.create(ret,
               ImmutableBitSet.of(), null, ImmutableList.of(aggCall));
     }
 
@@ -557,8 +557,7 @@ public abstract class RelOptUtil {
         || logic == RelOptUtil.Logic.TRUE_FALSE_UNKNOWN;
     if (!outerJoin) {
       final LogicalAggregate aggregate =
-          LogicalAggregate.create(ret, false,
-              ImmutableBitSet.range(keyCount), null,
+          LogicalAggregate.create(ret, ImmutableBitSet.range(keyCount), null,
               ImmutableList.<AggregateCall>of());
       return new Exists(aggregate, false, false);
     }
@@ -586,9 +585,8 @@ public abstract class RelOptUtil {
             null,
             null);
 
-    ret = LogicalAggregate.create(ret, false,
-        ImmutableBitSet.range(projectedKeyCount), null,
-        ImmutableList.of(aggCall));
+    ret = LogicalAggregate.create(ret, ImmutableBitSet.range(projectedKeyCount),
+        null, ImmutableList.of(aggCall));
 
     switch (logic) {
     case TRUE_FALSE_UNKNOWN:
@@ -787,14 +785,13 @@ public abstract class RelOptUtil {
               0, rel, null, null));
     }
 
-    return LogicalAggregate.create(rel, false,
-        ImmutableBitSet.of(), null, aggCalls);
+    return LogicalAggregate.create(rel, ImmutableBitSet.of(), null, aggCalls);
   }
 
   /** @deprecated Use {@link RelBuilder#distinct()}. */
   @Deprecated // to be removed before 2.0
   public static RelNode createDistinctRel(RelNode rel) {
-    return LogicalAggregate.create(rel, false,
+    return LogicalAggregate.create(rel,
         ImmutableBitSet.range(rel.getRowType().getFieldCount()), null,
         ImmutableList.<AggregateCall>of());
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
index 15cedcb..5fd8f6e 100644
--- a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
+++ b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
@@ -1204,8 +1204,7 @@ public class SubstitutionVisitor {
         Mappings.apply2(mapping, aggregate.groupSets);
     List<AggregateCall> aggregateCalls =
         apply(mapping, aggregate.aggCalls);
-    return MutableAggregate.of(input, aggregate.indicator, groupSet, groupSets,
-        aggregateCalls);
+    return MutableAggregate.of(input, groupSet, groupSets, aggregateCalls);
   }
 
   private static List<AggregateCall> apply(final Mapping mapping,
@@ -1267,7 +1266,7 @@ public class SubstitutionVisitor {
                 ImmutableList.of(target.groupSet.cardinality() + i), -1,
                 aggregateCall.type, aggregateCall.name));
       }
-      result = MutableAggregate.of(target, false, groupSet.build(), null,
+      result = MutableAggregate.of(target, groupSet.build(), null,
           aggregateCalls);
     }
     return MutableRels.createCastRel(result, query.rowType, true);

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java b/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
index 7388713..93f9948 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
@@ -80,6 +80,13 @@ public abstract class Aggregate extends SingleRel {
         }
       };
 
+  public static final Predicate<Aggregate> NO_INDICATOR =
+      new PredicateImpl<Aggregate>() {
+        public boolean test(Aggregate input) {
+          return !input.indicator;
+        }
+      };
+
   public static final Predicate<Aggregate> IS_NOT_GRAND_TOTAL =
       new PredicateImpl<Aggregate>() {
         public boolean test(Aggregate input) {
@@ -89,6 +96,11 @@ public abstract class Aggregate extends SingleRel {
 
   //~ Instance fields --------------------------------------------------------
 
+  /** Whether there are indicator fields.
+   *
+   * <p>We strongly discourage the use indicator fields, because they cause the
+   * output row type of GROUPING SETS queries to be different from regular GROUP
+   * BY queries, and recommend that you set this field to {@code false}. */
   public final boolean indicator;
   protected final List<AggregateCall> aggCalls;
   protected final ImmutableBitSet groupSet;
@@ -118,8 +130,7 @@ public abstract class Aggregate extends SingleRel {
    * @param traits   Traits
    * @param child    Child
    * @param indicator Whether row type should include indicator fields to
-   *                 indicate which grouping set is active; must be true if
-   *                 aggregate is not simple
+   *                 indicate which grouping set is active; true is deprecated
    * @param groupSet Bit set of grouping fields
    * @param groupSets List of all grouping sets; null for just {@code groupSet}
    * @param aggCalls Collection of calls to aggregate functions
@@ -133,7 +144,7 @@ public abstract class Aggregate extends SingleRel {
       List<ImmutableBitSet> groupSets,
       List<AggregateCall> aggCalls) {
     super(cluster, traits, child);
-    this.indicator = indicator;
+    this.indicator = indicator; // true is allowed, but discouraged
     this.aggCalls = ImmutableList.copyOf(aggCalls);
     this.groupSet = Preconditions.checkNotNull(groupSet);
     if (groupSets == null) {
@@ -346,6 +357,9 @@ public abstract class Aggregate extends SingleRel {
       final RelDataTypeField field = fieldList.get(groupKey);
       containedNames.add(field.getName());
       builder.add(field);
+      if (groupSets != null && !allContain(groupSets, groupKey)) {
+        builder.nullable(true);
+      }
     }
     if (indicator) {
       for (int groupKey : groupList) {
@@ -380,6 +394,16 @@ public abstract class Aggregate extends SingleRel {
     return builder.build();
   }
 
+  private static boolean allContain(List<ImmutableBitSet> groupSets,
+      int groupKey) {
+    for (ImmutableBitSet groupSet : groupSets) {
+      if (!groupSet.get(groupKey)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
   public boolean isValid(Litmus litmus, Context context) {
     return super.isValid(litmus, context)
         && litmus.check(Util.isDistinct(getRowType().getFieldNames()),

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java b/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
index c98a109..477bbd4 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
@@ -206,6 +206,7 @@ public class RelFactories {
    * that returns a vanilla {@link LogicalAggregate}.
    */
   private static class AggregateFactoryImpl implements AggregateFactory {
+    @SuppressWarnings("deprecation")
     public RelNode createAggregate(RelNode input, boolean indicator,
         ImmutableBitSet groupSet, ImmutableList<ImmutableBitSet> groupSets,
         List<AggregateCall> aggCalls) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
index d6b9e57..720491d 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
@@ -86,6 +86,21 @@ public final class LogicalAggregate extends Aggregate {
 
   /** Creates a LogicalAggregate. */
   public static LogicalAggregate create(final RelNode input,
+      ImmutableBitSet groupSet, List<ImmutableBitSet> groupSets,
+      List<AggregateCall> aggCalls) {
+    return create_(input, false, groupSet, groupSets, aggCalls);
+  }
+
+  @Deprecated // to be removed before 2.0
+  public static LogicalAggregate create(final RelNode input,
+      boolean indicator,
+      ImmutableBitSet groupSet,
+      List<ImmutableBitSet> groupSets,
+      List<AggregateCall> aggCalls) {
+    return create_(input, indicator, groupSet, groupSets, aggCalls);
+  }
+
+  private static LogicalAggregate create_(final RelNode input,
       boolean indicator,
       ImmutableBitSet groupSet,
       List<ImmutableBitSet> groupSets,

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/rel/mutable/MutableAggregate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/mutable/MutableAggregate.java b/core/src/main/java/org/apache/calcite/rel/mutable/MutableAggregate.java
index 546b62a..83ae7b9 100644
--- a/core/src/main/java/org/apache/calcite/rel/mutable/MutableAggregate.java
+++ b/core/src/main/java/org/apache/calcite/rel/mutable/MutableAggregate.java
@@ -28,16 +28,14 @@ import java.util.Objects;
 
 /** Mutable equivalent of {@link org.apache.calcite.rel.core.Aggregate}. */
 public class MutableAggregate extends MutableSingleRel {
-  public final boolean indicator;
   public final ImmutableBitSet groupSet;
   public final ImmutableList<ImmutableBitSet> groupSets;
   public final List<AggregateCall> aggCalls;
 
   private MutableAggregate(MutableRel input, RelDataType rowType,
-      boolean indicator, ImmutableBitSet groupSet,
+      ImmutableBitSet groupSet,
       List<ImmutableBitSet> groupSets, List<AggregateCall> aggCalls) {
     super(MutableRelType.AGGREGATE, rowType, input);
-    this.indicator = indicator;
     this.groupSet = groupSet;
     this.groupSets = groupSets == null
         ? ImmutableList.of(groupSet)
@@ -49,20 +47,16 @@ public class MutableAggregate extends MutableSingleRel {
    * Creates a MutableAggregate.
    *
    * @param input     Input relational expression
-   * @param indicator Whether row type should include indicator fields to
-   *                  indicate which grouping set is active; must be true if
-   *                  aggregate is not simple
    * @param groupSet  Bit set of grouping fields
    * @param groupSets List of all grouping sets; null for just {@code groupSet}
    * @param aggCalls  Collection of calls to aggregate functions
    */
-  public static MutableAggregate of(MutableRel input, boolean indicator,
-      ImmutableBitSet groupSet, ImmutableList<ImmutableBitSet> groupSets,
-      List<AggregateCall> aggCalls) {
+  public static MutableAggregate of(MutableRel input, ImmutableBitSet groupSet,
+      ImmutableList<ImmutableBitSet> groupSets, List<AggregateCall> aggCalls) {
     RelDataType rowType =
         Aggregate.deriveRowType(input.cluster.getTypeFactory(),
-            input.rowType, indicator, groupSet, groupSets, aggCalls);
-    return new MutableAggregate(input, rowType, indicator, groupSet,
+            input.rowType, false, groupSet, groupSets, aggCalls);
+    return new MutableAggregate(input, rowType, groupSet,
         groupSets, aggCalls);
   }
 
@@ -89,8 +83,7 @@ public class MutableAggregate extends MutableSingleRel {
   }
 
   @Override public MutableRel clone() {
-    return MutableAggregate.of(input.clone(),
-        indicator, groupSet, groupSets, aggCalls);
+    return MutableAggregate.of(input.clone(), groupSet, groupSets, aggCalls);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/rel/mutable/MutableRels.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/mutable/MutableRels.java b/core/src/main/java/org/apache/calcite/rel/mutable/MutableRels.java
index b07da0e..8470dc6 100644
--- a/core/src/main/java/org/apache/calcite/rel/mutable/MutableRels.java
+++ b/core/src/main/java/org/apache/calcite/rel/mutable/MutableRels.java
@@ -194,7 +194,7 @@ public abstract class MutableRels {
       final MutableAggregate aggregate = (MutableAggregate) node;
       relBuilder.push(fromMutable(aggregate.input, relBuilder));
       relBuilder.aggregate(
-          relBuilder.groupKey(aggregate.groupSet, aggregate.indicator, aggregate.groupSets),
+          relBuilder.groupKey(aggregate.groupSet, aggregate.groupSets),
           aggregate.aggCalls);
       return relBuilder.build();
     case SORT:
@@ -312,9 +312,8 @@ public abstract class MutableRels {
     if (rel instanceof Aggregate) {
       final Aggregate aggregate = (Aggregate) rel;
       final MutableRel input = toMutable(aggregate.getInput());
-      return MutableAggregate.of(input, aggregate.indicator,
-          aggregate.getGroupSet(), aggregate.getGroupSets(),
-          aggregate.getAggCallList());
+      return MutableAggregate.of(input, aggregate.getGroupSet(),
+          aggregate.getGroupSets(), aggregate.getAggCallList());
     }
     if (rel instanceof Sort) {
       final Sort sort = (Sort) rel;

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/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 665bccf..7202b81 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
@@ -1053,7 +1053,7 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule {
                         relBuilder.peek(), aggregate.getGroupCount() + i))));
       }
       RelNode result = relBuilder
-          .aggregate(relBuilder.groupKey(groupSet, false, null), aggregateCalls)
+          .aggregate(relBuilder.groupKey(groupSet, null), aggregateCalls)
           .build();
       if (topProject != null) {
         // Top project
@@ -1274,7 +1274,7 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule {
         }
         result = relBuilder
             .push(result)
-            .aggregate(relBuilder.groupKey(groupSet, false, null), aggregateCalls)
+            .aggregate(relBuilder.groupKey(groupSet, null), aggregateCalls)
             .build();
         // We introduce a project on top, as group by columns order is lost
         List<RexNode> projects = new ArrayList<>();

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/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 dee822d..ca95bcc 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
@@ -16,8 +16,8 @@
  */
 package org.apache.calcite.rel.rules;
 
+import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.plan.Contexts;
-import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.rel.RelNode;
@@ -26,8 +26,6 @@ import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.logical.LogicalAggregate;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexInputRef;
@@ -36,7 +34,6 @@ import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.fun.SqlSumEmptyIsZeroAggFunction;
-import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.ImmutableBitSet;
@@ -49,10 +46,10 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 
-import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -90,8 +87,6 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
       new AggregateExpandDistinctAggregatesRule(LogicalAggregate.class, false,
           RelFactories.LOGICAL_BUILDER);
 
-  private static final BigDecimal TWO = BigDecimal.valueOf(2L);
-
   public final boolean useGroupingSets;
 
   //~ Constructors -----------------------------------------------------------
@@ -161,7 +156,9 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
 
     // If all of the agg expressions are distinct and have the same
     // arguments then we can use a more efficient form.
-    if (nonDistinctAggCallCount == 0 && argLists.size() == 1) {
+    if (nonDistinctAggCallCount == 0
+        && argLists.size() == 1
+        && aggregate.getGroupSets().size() == 1) {
       final Pair<List<Integer>, Integer> pair =
           Iterables.getOnlyElement(argLists);
       final RelBuilder relBuilder = call.builder();
@@ -171,7 +168,7 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
     }
 
     if (useGroupingSets) {
-      rewriteUsingGroupingSets(call, aggregate, argLists);
+      rewriteUsingGroupingSets(call, aggregate);
       return;
     }
 
@@ -224,7 +221,7 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
     int n = 0;
     if (!newAggCallList.isEmpty()) {
       final RelBuilder.GroupKey groupKey =
-          relBuilder.groupKey(groupSet, aggregate.indicator, aggregate.getGroupSets());
+          relBuilder.groupKey(groupSet, aggregate.getGroupSets());
       relBuilder.aggregate(groupKey, newAggCallList);
       ++n;
     }
@@ -370,17 +367,19 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
     return relBuilder;
   }
 
-  @SuppressWarnings("DanglingJavadoc")
   private void rewriteUsingGroupingSets(RelOptRuleCall call,
-      Aggregate aggregate, Set<Pair<List<Integer>, Integer>> argLists) {
+      Aggregate aggregate) {
     final Set<ImmutableBitSet> groupSetTreeSet =
         new TreeSet<>(ImmutableBitSet.ORDERING);
-    groupSetTreeSet.add(aggregate.getGroupSet());
-    for (Pair<List<Integer>, Integer> argList : argLists) {
-      groupSetTreeSet.add(
-          ImmutableBitSet.of(argList.left)
-              .setIf(argList.right, argList.right >= 0)
-              .union(aggregate.getGroupSet()));
+    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 =
@@ -396,87 +395,38 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
 
     final RelBuilder relBuilder = call.builder();
     relBuilder.push(aggregate.getInput());
-    final boolean indicator = groupSets.size() > 1;
-    relBuilder.aggregate(
-        relBuilder.groupKey(fullGroupSet, indicator, groupSets),
-        distinctAggCalls);
-    final RelNode distinct = relBuilder.peek();
     final int groupCount = fullGroupSet.cardinality();
-    final int indicatorCount = indicator ? groupCount : 0;
-
-    final RelOptCluster cluster = aggregate.getCluster();
-    final RexBuilder rexBuilder = cluster.getRexBuilder();
-    final RelDataTypeFactory typeFactory = cluster.getTypeFactory();
-    final RelDataType booleanType =
-        typeFactory.createTypeWithNullability(
-            typeFactory.createSqlType(SqlTypeName.BOOLEAN), false);
-    final List<Pair<RexNode, String>> predicates = new ArrayList<>();
-    final Map<ImmutableBitSet, Integer> filters = new HashMap<>();
-
-    /** Function to register a filter for a group set. */
-    class Registrar {
-      RexNode group = null;
-
-      private int register(ImmutableBitSet groupSet) {
-        if (group == null) {
-          group = makeGroup(groupCount - 1);
-        }
-        final RexNode node =
-            rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, group,
-                rexBuilder.makeExactLiteral(
-                    toNumber(remap(fullGroupSet, groupSet))));
-        predicates.add(Pair.of(node, toString(groupSet)));
-        return groupCount + indicatorCount + distinctAggCalls.size()
-            + predicates.size() - 1;
-      }
 
-      private RexNode makeGroup(int i) {
-        final RexInputRef ref =
-            rexBuilder.makeInputRef(booleanType, groupCount + i);
-        final RexNode kase =
-            rexBuilder.makeCall(SqlStdOperatorTable.CASE, ref,
-                rexBuilder.makeExactLiteral(BigDecimal.ZERO),
-                rexBuilder.makeExactLiteral(TWO.pow(i)));
-        if (i == 0) {
-          return kase;
-        } else {
-          return rexBuilder.makeCall(SqlStdOperatorTable.PLUS,
-              makeGroup(i - 1), kase);
-        }
-      }
-
-      private BigDecimal toNumber(ImmutableBitSet bitSet) {
-        BigDecimal n = BigDecimal.ZERO;
-        for (int key : bitSet) {
-          n = n.add(TWO.pow(key));
-        }
-        return n;
-      }
-
-      private String toString(ImmutableBitSet bitSet) {
-        final StringBuilder buf = new StringBuilder("$i");
-        for (int key : bitSet) {
-          buf.append(key).append('_');
-        }
-        return buf.substring(0, buf.length() - 1);
-      }
-    }
-    final Registrar registrar = new Registrar();
-    for (ImmutableBitSet groupSet : groupSets) {
-      filters.put(groupSet, indicator ? registrar.register(groupSet) : -1);
+    final Map<ImmutableBitSet, Integer> filters = new LinkedHashMap<>();
+    final int z = groupCount + distinctAggCalls.size();
+    distinctAggCalls.add(
+        AggregateCall.create(SqlStdOperatorTable.GROUPING, 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);
     }
 
-    if (!predicates.isEmpty()) {
-      List<Pair<RexNode, String>> nodes = new ArrayList<>();
-      for (RelDataTypeField f : relBuilder.peek().getRowType().getFieldList()) {
-        final RexNode node = rexBuilder.makeInputRef(f.getType(), f.getIndex());
-        nodes.add(Pair.of(node, f.getName()));
+    relBuilder.aggregate(relBuilder.groupKey(fullGroupSet, groupSets),
+        distinctAggCalls);
+    final RelNode distinct = relBuilder.peek();
+
+    // GROUPING returns an integer (0 or 1). Add a project to convert those
+    // 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));
       }
-      nodes.addAll(predicates);
-      relBuilder.project(Pair.left(nodes), Pair.right(nodes));
+      relBuilder.project(nodes);
     }
 
-    int x = groupCount + indicatorCount;
+    int x = groupCount;
     final List<AggregateCall> newCalls = new ArrayList<>();
     for (AggregateCall aggCall : aggregate.getAggCallList()) {
       final int newFilterArg;
@@ -504,13 +454,26 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
     relBuilder.aggregate(
         relBuilder.groupKey(
             remap(fullGroupSet, aggregate.getGroupSet()),
-            aggregate.indicator,
             remap(fullGroupSet, aggregate.getGroupSets())),
         newCalls);
     relBuilder.convert(aggregate.getRowType(), true);
     call.transformTo(relBuilder.build());
   }
 
+  private static long groupValue(ImmutableBitSet fullGroupSet,
+      ImmutableBitSet groupSet) {
+    long v = 0;
+    long x = 1L << (fullGroupSet.cardinality() - 1);
+    assert fullGroupSet.contains(groupSet);
+    for (int i : fullGroupSet) {
+      if (!groupSet.get(i)) {
+        v |= x;
+      }
+      x >>= 1;
+    }
+    return v;
+  }
+
   private static ImmutableBitSet remap(ImmutableBitSet groupSet,
       ImmutableBitSet bitSet) {
     final ImmutableBitSet.Builder builder = ImmutableBitSet.builder();

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java
index 932a18f..dfe28f5 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java
@@ -106,7 +106,7 @@ public class AggregateFilterTransposeRule extends RelOptRule {
         RexUtil.apply(mapping, filter.getCondition());
     final Filter newFilter = filter.copy(filter.getTraitSet(),
         newAggregate, newCondition);
-    if (allColumnsInAggregate && !aggregate.indicator) {
+    if (allColumnsInAggregate && aggregate.getGroupSets().size() == 1) {
       // Everything needed by the filter is returned by the aggregate.
       assert newGroupSet.equals(aggregate.getGroupSet());
       call.transformTo(newFilter);
@@ -119,7 +119,7 @@ public class AggregateFilterTransposeRule extends RelOptRule {
         topGroupSet.set(newGroupSet.indexOf(c));
       }
       ImmutableList<ImmutableBitSet> newGroupingSets = null;
-      if (aggregate.indicator) {
+      if (aggregate.groupSets.size() > 1) {
         ImmutableList.Builder<ImmutableBitSet> newGroupingSetsBuilder =
                 ImmutableList.builder();
         for (ImmutableBitSet groupingSet : aggregate.getGroupSets()) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java
index 6544db0..3806f07 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java
@@ -253,7 +253,7 @@ public class AggregateJoinTransposeRule extends RelOptRule {
           }
         }
         side.newInput = relBuilder.push(joinInput)
-            .aggregate(relBuilder.groupKey(belowAggregateKey, false, null),
+            .aggregate(relBuilder.groupKey(belowAggregateKey, null),
                 belowAggCalls)
             .build();
       }
@@ -336,7 +336,7 @@ public class AggregateJoinTransposeRule extends RelOptRule {
     if (!aggConvertedToProjects) {
       relBuilder.aggregate(
           relBuilder.groupKey(Mappings.apply(mapping, aggregate.getGroupSet()),
-              aggregate.indicator, Mappings.apply2(mapping, aggregate.getGroupSets())),
+              Mappings.apply2(mapping, aggregate.getGroupSets())),
           newAggCalls);
     }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectMergeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectMergeRule.java
index 5b486eb..432a891 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectMergeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectMergeRule.java
@@ -88,7 +88,7 @@ public class AggregateProjectMergeRule extends RelOptRule {
 
     final ImmutableBitSet newGroupSet = aggregate.getGroupSet().permute(map);
     ImmutableList<ImmutableBitSet> newGroupingSets = null;
-    if (aggregate.indicator) {
+    if (aggregate.getGroupSets().size() > 1) {
       newGroupingSets =
           ImmutableBitSet.ORDERING.immutableSortedCopy(
               ImmutableBitSet.permute(aggregate.getGroupSets(), map));

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java
index 6bb1d3b..75af27d 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java
@@ -153,9 +153,7 @@ public class AggregateProjectPullUpConstantsRule extends RelOptRule {
           aggCall.adaptTo(input, aggCall.getArgList(), aggCall.filterArg,
               groupCount, newGroupCount));
     }
-    relBuilder.aggregate(
-        relBuilder.groupKey(newGroupSet, false, null),
-        newAggCalls);
+    relBuilder.aggregate(relBuilder.groupKey(newGroupSet, null), newAggCalls);
 
     // Create a projection back again.
     List<Pair<RexNode, String>> projects = new ArrayList<>();

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
index 7e6e4a1..a9bdb84 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
@@ -560,7 +560,6 @@ public class AggregateReduceFunctionsRule extends RelOptRule {
       List<AggregateCall> newCalls) {
     relBuilder.aggregate(
         relBuilder.groupKey(oldAggregate.getGroupSet(),
-            oldAggregate.indicator,
             oldAggregate.getGroupSets()),
         newCalls);
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java
index a99a29e..8eeaaa7 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java
@@ -104,7 +104,7 @@ public class AggregateUnionAggregateRule extends RelOptRule {
     }
 
     relBuilder.union(true);
-    relBuilder.aggregate(relBuilder.groupKey(topAggRel.getGroupSet(), false, null),
+    relBuilder.aggregate(relBuilder.groupKey(topAggRel.getGroupSet(), null),
         topAggRel.getAggCallList());
     call.transformTo(relBuilder.build());
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
index 2d8a7e0..0e07256 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
@@ -125,7 +125,7 @@ public class AggregateUnionTransposeRule extends RelOptRule {
       relBuilder.push(input);
       if (!alreadyUnique) {
         ++transformCount;
-        relBuilder.aggregate(relBuilder.groupKey(aggRel.getGroupSet(), false, null),
+        relBuilder.aggregate(relBuilder.groupKey(aggRel.getGroupSet(), null),
             aggRel.getAggCallList());
       }
     }
@@ -140,7 +140,7 @@ public class AggregateUnionTransposeRule extends RelOptRule {
     // create a new union whose children are the aggregates created above
     relBuilder.union(true, union.getInputs().size());
     relBuilder.aggregate(
-        relBuilder.groupKey(aggRel.getGroupSet(), aggRel.indicator, aggRel.getGroupSets()),
+        relBuilder.groupKey(aggRel.getGroupSet(), aggRel.getGroupSets()),
         transformedAggCalls);
     call.transformTo(relBuilder.build());
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
index 118e637..f971be3 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
@@ -137,7 +137,7 @@ public class FilterAggregateTransposeRule extends RelOptRule {
       return false;
     }
 
-    if (aggregate.indicator) {
+    if (aggregate.getGroupSets().size() > 1) {
       // If grouping sets are used, the filter can be pushed if
       // the columns referenced in the predicate are present in
       // all the grouping sets.

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/rel/rules/IntersectToDistinctRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/IntersectToDistinctRule.java b/core/src/main/java/org/apache/calcite/rel/rules/IntersectToDistinctRule.java
index f105c53..2b4bfbb 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/IntersectToDistinctRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/IntersectToDistinctRule.java
@@ -107,7 +107,7 @@ public class IntersectToDistinctRule extends RelOptRule {
 
     final ImmutableBitSet groupSet =
         ImmutableBitSet.range(fieldCount - 1);
-    relBuilder.aggregate(relBuilder.groupKey(groupSet, false, null),
+    relBuilder.aggregate(relBuilder.groupKey(groupSet, null),
         relBuilder.countStar(null));
 
     // add a filter count(c) = #branches

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/rel/stream/StreamRules.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/stream/StreamRules.java b/core/src/main/java/org/apache/calcite/rel/stream/StreamRules.java
index 538261c..80ee68f 100644
--- a/core/src/main/java/org/apache/calcite/rel/stream/StreamRules.java
+++ b/core/src/main/java/org/apache/calcite/rel/stream/StreamRules.java
@@ -108,7 +108,7 @@ public class StreamRules {
     private DeltaAggregateTransposeRule() {
       super(
           operand(Delta.class,
-              operand(Aggregate.class, any())));
+              operand(Aggregate.class, null, Aggregate.NO_INDICATOR, any())));
     }
 
     @Override public void onMatch(RelOptRuleCall call) {
@@ -118,9 +118,8 @@ public class StreamRules {
       final LogicalDelta newDelta =
           LogicalDelta.create(aggregate.getInput());
       final LogicalAggregate newAggregate =
-          LogicalAggregate.create(newDelta, aggregate.indicator,
-              aggregate.getGroupSet(), aggregate.groupSets,
-              aggregate.getAggCallList());
+          LogicalAggregate.create(newDelta, aggregate.getGroupSet(),
+              aggregate.groupSets, aggregate.getAggCallList());
       call.transformTo(newAggregate);
     }
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
index b42b1a0..1f34ec7 100644
--- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
+++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
@@ -320,9 +320,6 @@ public interface CalciteResource {
   @BaseMessage("Windowed aggregate expression is illegal in {0} clause")
   ExInst<SqlValidatorException> windowedAggregateIllegalInClause(String a0);
 
-  @BaseMessage("Aggregate expression is illegal in GROUP BY clause")
-  ExInst<SqlValidatorException> aggregateIllegalInGroupBy();
-
   @BaseMessage("Aggregate expressions cannot be nested")
   ExInst<SqlValidatorException> nestedAggIllegal();
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java
index e2875c0..6c1f648 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java
@@ -125,6 +125,12 @@ public abstract class SqlAggFunction extends SqlFunction implements Context {
   public RelDataType getReturnType(RelDataTypeFactory typeFactory) {
     throw new UnsupportedOperationException("remove before calcite-2.0");
   }
+
+  /** Whether this aggregate function allows a {@code FILTER (WHERE ...)}
+   * clause. */
+  public boolean allowsFilter() {
+    return true;
+  }
 }
 
 // End SqlAggFunction.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/sql/fun/SqlAbstractGroupFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlAbstractGroupFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlAbstractGroupFunction.java
index 443bd4f..d1001dd 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlAbstractGroupFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlAbstractGroupFunction.java
@@ -16,8 +16,8 @@
  */
 package org.apache.calcite.sql.fun;
 
+import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlCall;
-import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlNode;
@@ -37,7 +37,7 @@ import org.apache.calcite.util.Static;
  * Base class for grouping functions {@code GROUP_ID}, {@code GROUPING_ID},
  * {@code GROUPING}.
  */
-public class SqlAbstractGroupFunction extends SqlFunction {
+public class SqlAbstractGroupFunction extends SqlAggFunction {
   /**
    * Creates a SqlAbstractGroupFunction.
    *
@@ -54,8 +54,8 @@ public class SqlAbstractGroupFunction extends SqlFunction {
       SqlOperandTypeInference operandTypeInference,
       SqlOperandTypeChecker operandTypeChecker,
       SqlFunctionCategory category) {
-    super(name, kind, returnTypeInference, operandTypeInference,
-        operandTypeChecker, category);
+    super(name, null, kind, returnTypeInference, operandTypeInference,
+        operandTypeChecker, category, false, false);
   }
 
   @Override public void validateCall(SqlCall call, SqlValidator validator,
@@ -88,6 +88,14 @@ public class SqlAbstractGroupFunction extends SqlFunction {
       }
     }
   }
+
+  @Override public boolean isQuantifierAllowed() {
+    return false;
+  }
+
+  @Override public boolean allowsFilter() {
+    return false;
+  }
 }
 
 // End SqlAbstractGroupFunction.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupIdFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupIdFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupIdFunction.java
index 8f74d36..6b1138b 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupIdFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupIdFunction.java
@@ -22,7 +22,10 @@ import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
 
 /**
- * The {@code GROUP_ID} function.
+ * The {@code GROUP_ID()} function.
+ *
+ * <p>Accepts no arguments. If the query has {@code GROUP BY x, y, z} then
+ * {@code GROUP_ID()} is the same as {@code GROUPING(x, y, z)}.
  *
  * <p>This function is not defined in the SQL standard; our implementation is
  * consistent with Oracle.

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupingFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupingFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupingFunction.java
index 9abbd60..5504464 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupingFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupingFunction.java
@@ -24,6 +24,13 @@ import org.apache.calcite.sql.type.ReturnTypes;
 /**
  * The {@code GROUPING} function.
  *
+ * <p>Accepts 1 or more arguments.
+ * Example: {@code GROUPING(deptno, gender)} returns
+ * 3 if both deptno and gender are being grouped,
+ * 2 if only deptno is being grouped,
+ * 1 if only gender is being groped,
+ * 0 if neither deptno nor gender are being grouped.
+ *
  * <p>This function is defined in the SQL standard.
  * {@code GROUPING_ID} is a non-standard synonym.
  *

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
index 39a45b3..7b6b771 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
@@ -195,26 +195,28 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable {
   public static final SqlInternalOperator GROUPING_SETS =
       new SqlRollupOperator("GROUPING SETS", SqlKind.GROUPING_SETS);
 
-  /** {@code GROUPING} function. Occurs in similar places to an aggregate
+  /** {@code GROUPING(c1 [, c2, ...])} function.
+   *
+   * <p>Occurs in similar places to an aggregate
    * function ({@code SELECT}, {@code HAVING} clause, etc. of an aggregate
    * query), but not technically an aggregate function. */
   public static final SqlGroupingFunction GROUPING =
       new SqlGroupingFunction("GROUPING");
 
-  /** {@code GROUP_ID} function. */
+  /** {@code GROUP_ID()} function. (Oracle-specific.) */
   public static final SqlGroupIdFunction GROUP_ID =
       new SqlGroupIdFunction();
 
-  /** {@code GROUP_ID} function is a synonym for {@code GROUPING}.
+  /** {@code GROUPING_ID} function is a synonym for {@code GROUPING}.
    *
    * <p>Some history. The {@code GROUPING} function is in the SQL standard,
-   * and originally supported only one argument. The {@code GROUP_ID} is not
-   * standard (though supported in Oracle and SQL Server) and supports zero or
+   * and originally supported only one argument. {@code GROUPING_ID} is not
+   * standard (though supported in Oracle and SQL Server) and supports one or
    * more arguments.
    *
    * <p>The SQL standard has changed to allow {@code GROUPING} to have multiple
-   * arguments. It is now equivalent to {@code GROUP_ID}, so we made
-   * {@code GROUP_ID} a synonym for {@code GROUPING}. */
+   * arguments. It is now equivalent to {@code GROUPING_ID}, so we made
+   * {@code GROUPING_ID} a synonym for {@code GROUPING}. */
   public static final SqlGroupingFunction GROUPING_ID =
       new SqlGroupingFunction("GROUPING_ID");
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/sql/validate/AggFinder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/AggFinder.java b/core/src/main/java/org/apache/calcite/sql/validate/AggFinder.java
index d8d51f0..0dd7f1d 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/AggFinder.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/AggFinder.java
@@ -23,6 +23,7 @@ import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlOperatorTable;
 import org.apache.calcite.sql.SqlSyntax;
+import org.apache.calcite.sql.fun.SqlAbstractGroupFunction;
 import org.apache.calcite.sql.util.SqlBasicVisitor;
 import org.apache.calcite.util.Util;
 
@@ -105,7 +106,9 @@ class AggFinder extends SqlBasicVisitor<Void> {
   public Void visit(SqlCall call) {
     final SqlOperator operator = call.getOperator();
     // If nested aggregates disallowed or found an aggregate at invalid level
-    if (operator.isAggregator() && !operator.requiresOver()) {
+    if (operator.isAggregator()
+        && !(operator instanceof SqlAbstractGroupFunction)
+        && !operator.requiresOver()) {
       if (delegate != null) {
         return operator.acceptCall(delegate, call);
       }

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/sql/validate/AggregatingSelectScope.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/AggregatingSelectScope.java b/core/src/main/java/org/apache/calcite/sql/validate/AggregatingSelectScope.java
index 656f8d6..5df9374 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/AggregatingSelectScope.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/AggregatingSelectScope.java
@@ -248,7 +248,6 @@ public class AggregatingSelectScope
     public final ImmutableList<SqlNode> groupExprList;
     public final ImmutableBitSet groupSet;
     public final ImmutableList<ImmutableBitSet> groupSets;
-    public final boolean indicator;
     public final Map<Integer, Integer> groupExprProjection;
 
     Resolved(List<SqlNode> extraExprList, List<SqlNode> groupExprList,
@@ -258,7 +257,6 @@ public class AggregatingSelectScope
       this.groupExprList = ImmutableList.copyOf(groupExprList);
       this.groupSet = ImmutableBitSet.range(groupExprList.size());
       this.groupSets = ImmutableList.copyOf(groupSets);
-      this.indicator = !this.groupSets.equals(ImmutableList.of(groupSet));
       this.groupExprProjection = ImmutableMap.copyOf(groupExprProjection);
     }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/sql/validate/DelegatingNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/DelegatingNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/DelegatingNamespace.java
index c5754e8..b8c2af1 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/DelegatingNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/DelegatingNamespace.java
@@ -101,10 +101,6 @@ public abstract class DelegatingNamespace implements SqlValidatorNamespace {
   public void makeNullable() {
   }
 
-  public String translate(String name) {
-    return namespace.translate(name);
-  }
-
   public <T> T unwrap(Class<T> clazz) {
     if (clazz.isInstance(this)) {
       return clazz.cast(this);

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java
index e9e12e6..e3395db 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java
@@ -246,10 +246,6 @@ public class IdentifierNamespace extends AbstractNamespace {
     return resolvedNamespace.resolve();
   }
 
-  @Override public String translate(String name) {
-    return resolvedNamespace.translate(name);
-  }
-
   @Override public SqlValidatorTable getTable() {
     return resolvedNamespace == null ? null : resolve().getTable();
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/sql/validate/SqlQualified.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlQualified.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlQualified.java
index 52d4e1b..6303cb8 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlQualified.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlQualified.java
@@ -19,8 +19,6 @@ package org.apache.calcite.sql.validate;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.util.Util;
 
-import com.google.common.collect.ImmutableList;
-
 import java.util.List;
 
 /**
@@ -34,14 +32,13 @@ import java.util.List;
  * <p>It is immutable.
  */
 public class SqlQualified {
-  private final SqlValidatorScope scope;
   public final int prefixLength;
   public final SqlValidatorNamespace namespace;
   public final SqlIdentifier identifier;
 
   private SqlQualified(SqlValidatorScope scope, int prefixLength,
       SqlValidatorNamespace namespace, SqlIdentifier identifier) {
-    this.scope = scope;
+    Util.discard(scope);
     this.prefixLength = prefixLength;
     this.namespace = namespace;
     this.identifier = identifier;
@@ -56,30 +53,6 @@ public class SqlQualified {
     return new SqlQualified(scope, prefixLength, namespace, identifier);
   }
 
-  public List<String> translatedNames() {
-    if (scope == null) {
-      return identifier.names;
-    }
-    final SqlNameMatcher nameMatcher =
-        scope.getValidator().getCatalogReader().nameMatcher();
-    final ImmutableList.Builder<String> builder = ImmutableList.builder();
-    final SqlValidatorScope.ResolvedImpl resolved =
-        new SqlValidatorScope.ResolvedImpl();
-    final List<String> prefix = Util.skipLast(identifier.names);
-    scope.resolve(prefix, nameMatcher, false, resolved);
-    SqlValidatorNamespace namespace =
-        resolved.count() == 1 ? resolved.only().namespace : null;
-    builder.add(identifier.names.get(0));
-    for (String name : Util.skip(identifier.names)) {
-      if (namespace != null) {
-        name = namespace.translate(name);
-        namespace = null;
-      }
-      builder.add(name);
-    }
-    return builder.build();
-  }
-
   public final List<String> prefix() {
     return identifier.names.subList(0, prefixLength);
   }
@@ -87,10 +60,6 @@ public class SqlQualified {
   public final List<String> suffix() {
     return Util.skip(identifier.names, prefixLength);
   }
-
-  public final List<String> suffixTranslated() {
-    return Util.skip(translatedNames(), prefixLength);
-  }
 }
 
 // End SqlQualified.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
index 68106a9..cd83186 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
@@ -3793,7 +3793,8 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
     if (groupList == null) {
       return;
     }
-    validateNoAggs(aggOrOverFinder, groupList, "GROUP BY");
+    final String clause = "GROUP BY";
+    validateNoAggs(aggOrOverFinder, groupList, clause);
     final SqlValidatorScope groupScope = getGroupScope(select);
     inferUnknownTypes(unknownType, groupScope, groupList);
 
@@ -3842,7 +3843,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
 
     SqlNode agg = aggFinder.findAgg(groupList);
     if (agg != null) {
-      throw newValidationError(agg, RESOURCE.aggregateIllegalInGroupBy());
+      throw newValidationError(agg, RESOURCE.aggregateIllegalInClause(clause));
     }
   }
 
@@ -3886,8 +3887,8 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
   protected void validateWhereOrOn(
       SqlValidatorScope scope,
       SqlNode condition,
-      String keyword) {
-    validateNoAggs(aggOrOverOrGroupFinder, condition, keyword);
+      String clause) {
+    validateNoAggs(aggOrOverOrGroupFinder, condition, clause);
     inferUnknownTypes(
         booleanType,
         scope,
@@ -3896,7 +3897,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
 
     final RelDataType type = deriveType(scope, condition);
     if (!SqlTypeUtil.inBooleanFamily(type)) {
-      throw newValidationError(condition, RESOURCE.condMustBeBoolean(keyword));
+      throw newValidationError(condition, RESOURCE.condMustBeBoolean(clause));
     }
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorNamespace.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorNamespace.java
index da8d031..3c0b5f1 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorNamespace.java
@@ -162,11 +162,6 @@ public interface SqlValidatorNamespace {
   void makeNullable();
 
   /**
-   * Translates a field name to the name in the underlying namespace.
-   */
-  String translate(String name);
-
-  /**
    * Returns this namespace, or a wrapped namespace, cast to a particular
    * class.
    *

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
index c21b7c7..cb71879 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
@@ -578,11 +578,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
     }
 
     relBuilder.push(
-        LogicalAggregate.create(newProject,
-            false,
-            newGroupSet,
-            null,
-            newAggCalls));
+        LogicalAggregate.create(newProject, newGroupSet, null, newAggCalls));
 
     if (!omittedConstants.isEmpty()) {
       final List<RexNode> postProjects = new ArrayList<>(relBuilder.fields());
@@ -2311,12 +2307,8 @@ public class RelDecorrelator implements ReflectiveVisitor {
       ImmutableBitSet groupSet =
           ImmutableBitSet.range(groupCount);
       LogicalAggregate newAggregate =
-          LogicalAggregate.create(joinOutputProject,
-              false,
-              groupSet,
-              null,
+          LogicalAggregate.create(joinOutputProject, groupSet, null,
               newAggCalls);
-
       List<RexNode> newAggOutputProjectList = Lists.newArrayList();
       for (int i : groupSet) {
         newAggOutputProjectList.add(

http://git-wip-us.apache.org/repos/asf/calcite/blob/1e7ae1c3/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 ff0529d..0b7af6f 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
@@ -873,8 +873,8 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
       ++j;
     }
 
-    final RelBuilder.GroupKey groupKey = relBuilder.groupKey(newGroupSet,
-        aggregate.indicator, newGroupSets);
+    final RelBuilder.GroupKey groupKey =
+        relBuilder.groupKey(newGroupSet, newGroupSets);
     relBuilder.aggregate(groupKey, newAggCallList);
 
     return result(relBuilder.build(), mapping);