This is an automated email from the ASF dual-hosted git repository.

xuzifu666 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/main by this push:
     new 8668ee1d4e [CALCITE-6537] Add syntax to allow non-aggregated rows to 
be used in GROUPING SETS
8668ee1d4e is described below

commit 8668ee1d4eacbd8e53d6fec83879abe649a00db8
Author: Yu Xu <[email protected]>
AuthorDate: Sat Aug 22 22:51:02 2026 +0800

    [CALCITE-6537] Add syntax to allow non-aggregated rows to be used in 
GROUPING SETS
---
 core/src/main/codegen/templates/Parser.jj          |  77 ++++++++-
 .../calcite/sql/validate/SqlConformance.java       |  26 +++
 .../calcite/sql/validate/SqlConformanceEnum.java   |  10 ++
 .../sql/validate/SqlDelegatingConformance.java     |   4 +
 .../calcite/sql/validate/SqlValidatorImpl.java     | 119 ++++++++++++++
 .../org/apache/calcite/test/SqlValidatorTest.java  |  78 +++++++++
 core/src/test/resources/sql/agg.iq                 | 180 +++++++++++++++++++++
 7 files changed, 491 insertions(+), 3 deletions(-)

diff --git a/core/src/main/codegen/templates/Parser.jj 
b/core/src/main/codegen/templates/Parser.jj
index 42e4fc791a..1105df6bcb 100644
--- a/core/src/main/codegen/templates/Parser.jj
+++ b/core/src/main/codegen/templates/Parser.jj
@@ -187,6 +187,34 @@ public class ${parser.class} extends SqlAbstractParserImpl
         return rowValueStarCount > 0;
     }
 
+    /**
+     * Whether {@code *} is currently allowed as a bare grouping element in
+     * GROUPING SETS / ROLLUP / CUBE. Set while parsing a grouping element
+     * when the {@code isGroupingSetsStarAllowed} conformance is on.
+     *
+     * <p>Note that the validator expands such a star only in the
+     * well-defined positions of the syntax: a complete grouping set, an
+     * element of a grouping set, or an argument of ROLLUP or CUBE (including
+     * grouping constructs nested within GROUPING SETS). A star nested inside
+     * other expressions, say {@code ABS(*)}, parses too, but the validator
+     * does not expand it, and validation fails because {@code *} is not a
+     * known column.
+     */
+    private int groupingStarCount;
+
+    private void pushGroupingStar() {
+        groupingStarCount++;
+    }
+
+    private void popGroupingStar() {
+        assert groupingStarCount > 0;
+        groupingStarCount--;
+    }
+
+    private boolean allowGroupingStar() {
+        return groupingStarCount > 0;
+    }
+
     /**
      * {@link SqlParserImplFactory} implementation for creating parser.
      */
@@ -2901,11 +2929,23 @@ SqlNodeList GroupBy() :
 List<SqlNode> GroupingElementList() :
 {
     final List<SqlNode> list = new ArrayList<SqlNode>();
+    final boolean starAllowed =
+        this.conformance.isGroupingSetsStarAllowed();
 }
 {
+    {
+        if (starAllowed) {
+            pushGroupingStar();
+        }
+    }
     AddGroupingElement(list)
     ( LOOKAHEAD(2) <COMMA> AddGroupingElement(list) )*
-    { return list; }
+    {
+        if (starAllowed) {
+            popGroupingStar();
+        }
+        return list;
+    }
 }
 
 void AddGroupingElement(List<SqlNode> list) :
@@ -2913,6 +2953,8 @@ void AddGroupingElement(List<SqlNode> list) :
     final List<SqlNode> subList;
     final SqlNodeList nodes;
     final Span s;
+    final boolean starAllowed =
+        this.conformance.isGroupingSetsStarAllowed();
 }
 {
     LOOKAHEAD(2)
@@ -2922,14 +2964,30 @@ void AddGroupingElement(List<SqlNode> list) :
             SqlStdOperatorTable.GROUPING_SETS.createCall(s.end(this), 
subList));
     }
 |   <ROLLUP> { s = span(); }
-    <LPAREN> nodes = ExpressionCommaList(s, ExprContext.ACCEPT_SUB_QUERY)
+    <LPAREN> {
+        if (starAllowed) {
+            pushGroupingStar();
+        }
+    }
+    nodes = ExpressionCommaList(s, ExprContext.ACCEPT_SUB_QUERY)
     <RPAREN> {
+        if (starAllowed) {
+            popGroupingStar();
+        }
         list.add(
             SqlStdOperatorTable.ROLLUP.createCall(s.end(this), 
nodes.getList()));
     }
 |   <CUBE> { s = span(); }
-    <LPAREN> nodes = ExpressionCommaList(s, ExprContext.ACCEPT_SUB_QUERY)
+    <LPAREN> {
+        if (starAllowed) {
+            pushGroupingStar();
+        }
+    }
+    nodes = ExpressionCommaList(s, ExprContext.ACCEPT_SUB_QUERY)
     <RPAREN> {
+        if (starAllowed) {
+            popGroupingStar();
+        }
         list.add(
             SqlStdOperatorTable.CUBE.createCall(s.end(this), nodes.getList()));
     }
@@ -2937,6 +2995,10 @@ void AddGroupingElement(List<SqlNode> list) :
     <LPAREN> { s = span(); } <RPAREN> {
         list.add(new SqlNodeList(s.end(this)));
     }
+|   LOOKAHEAD({ allowGroupingStar() && getToken(1).kind == STAR })
+    <STAR> {
+        list.add(SqlIdentifier.star(getPos()));
+    }
 |   AddExpression(list, ExprContext.ACCEPT_SUB_QUERY)
 }
 
@@ -4824,6 +4886,15 @@ SqlNode AtomicRowExpression() :
         |
             { return starId; }
         )
+    |
+        // Parses a bare "*" grouping element appearing inside a tuple or
+        // argument list of GROUPING SETS / ROLLUP / CUBE. (A star nested
+        // inside other expressions, say ABS(*), parses too, but the
+        // validator does not expand it and validation fails.)
+        LOOKAHEAD({ allowGroupingStar() && getToken(1).kind == STAR })
+        <STAR> {
+            return SqlIdentifier.star(getPos());
+        }
     |
         e = NewSpecification()
     |
diff --git 
a/core/src/main/java/org/apache/calcite/sql/validate/SqlConformance.java 
b/core/src/main/java/org/apache/calcite/sql/validate/SqlConformance.java
index 703dfd4a14..0a4041bbde 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlConformance.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlConformance.java
@@ -747,4 +747,30 @@ default boolean isColonFieldAccessAllowed() {
   default boolean isCorrelatedAggregateAllowed() {
     return false;
   }
+
+  /**
+   * Whether {@code *} is allowed as a grouping element in
+   * {@code GROUPING SETS}, {@code ROLLUP} and {@code CUBE} sub-clauses of
+   * {@code GROUP BY}, to produce non-aggregated (detail) rows.
+   *
+   * <p>By analogy with {@code COUNT(*)}, a grouping set containing {@code *}
+   * groups by every input column, so no rows are merged (except identical
+   * duplicate rows) and each input row appears in the output.
+   *
+   * <p>The star may appear only in well-defined positions: as a complete
+   * grouping set ({@code GROUPING SETS (*)}), as an element of a grouping
+   * set ({@code GROUPING SETS ((deptno), (*))}), or as an argument of
+   * {@code ROLLUP} or {@code CUBE} ({@code ROLLUP (deptno, *)}), including
+   * grouping constructs nested within {@code GROUPING SETS}. It may not
+   * appear at the top level of {@code GROUP BY}, nor inside other
+   * expressions.
+   *
+   * <p>Among the built-in conformance levels, true in
+   * {@link SqlConformanceEnum#BABEL},
+   * {@link SqlConformanceEnum#LENIENT};
+   * false otherwise.
+   */
+  default boolean isGroupingSetsStarAllowed() {
+    return false;
+  }
 }
diff --git 
a/core/src/main/java/org/apache/calcite/sql/validate/SqlConformanceEnum.java 
b/core/src/main/java/org/apache/calcite/sql/validate/SqlConformanceEnum.java
index 681835724f..072cdc0f68 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlConformanceEnum.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlConformanceEnum.java
@@ -572,4 +572,14 @@ public enum SqlConformanceEnum implements SqlConformance {
       return false;
     }
   }
+
+  @Override public boolean isGroupingSetsStarAllowed() {
+    switch (this) {
+    case BABEL:
+    case LENIENT:
+      return true;
+    default:
+      return false;
+    }
+  }
 }
diff --git 
a/core/src/main/java/org/apache/calcite/sql/validate/SqlDelegatingConformance.java
 
b/core/src/main/java/org/apache/calcite/sql/validate/SqlDelegatingConformance.java
index 7bed86a410..94ed901bca 100644
--- 
a/core/src/main/java/org/apache/calcite/sql/validate/SqlDelegatingConformance.java
+++ 
b/core/src/main/java/org/apache/calcite/sql/validate/SqlDelegatingConformance.java
@@ -193,4 +193,8 @@ protected SqlDelegatingConformance(SqlConformance delegate) 
{
   @Override public boolean isCorrelatedAggregateAllowed() {
     return delegate.isCorrelatedAggregateAllowed();
   }
+
+  @Override public boolean isGroupingSetsStarAllowed() {
+    return delegate.isGroupingSetsStarAllowed();
+  }
 }
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 78c9d0d522..f6fd853d74 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
@@ -5658,6 +5658,7 @@ private static SqlNode measureToValue(SqlNode e) {
    */
   protected void validateGroupClause(SqlSelect select) {
     rewriteGroupByAll(select);
+    rewriteGroupingStar(select);
     SqlNodeList groupList = select.getGroup();
     if (groupList == null) {
       return;
@@ -5759,6 +5760,124 @@ private void rewriteGroupByAll(SqlSelect select) {
     select.setGroupBy(new SqlNodeList(keys, groupList.getParserPosition()));
   }
 
+  /** If the conformance allows {@code *} as a grouping element, rewrites it
+   * into a {@code ROW} of every input column. A grouping set containing all
+   * input columns does not merge any rows (except identical duplicates),
+   * yielding the non-aggregated "detail" rows.
+   *
+   * <p>A star may appear only in the well-defined positions of this syntax:
+   * as a complete grouping set ({@code GROUPING SETS (*)}), as an element of
+   * a grouping set ({@code GROUPING SETS ((deptno), (*))}), or as an argument
+   * of ROLLUP or CUBE ({@code ROLLUP (deptno, *)}), including grouping
+   * constructs nested within GROUPING SETS. It may not appear at the top
+   * level of GROUP BY, nor inside other expressions.
+   *
+   * @see SqlConformance#isGroupingSetsStarAllowed() */
+  private void rewriteGroupingStar(SqlSelect select) {
+    if (!config.conformance().isGroupingSetsStarAllowed()) {
+      return;
+    }
+    final SqlNodeList groupList = select.getGroup();
+    if (groupList == null) {
+      return;
+    }
+    boolean changed = false;
+    final List<SqlNode> newItems = new ArrayList<>();
+    for (SqlNode groupItem : groupList) {
+      final SqlNode newItem = rewriteGroupingStarNode(groupItem, select);
+      if (newItem != groupItem) {
+        changed = true;
+      }
+      newItems.add(newItem);
+    }
+    if (changed) {
+      select.setGroupBy(new SqlNodeList(newItems, 
groupList.getParserPosition()));
+    }
+  }
+
+  /** Recursively rewrites bare {@code *} grouping elements into a ROW of all
+   * input columns. Descends only into the constructs in which the grouping
+   * star syntax is defined: the operands of GROUPING SETS, ROLLUP and CUBE
+   * calls, the elements of the ROW tuples that make up a grouping set, and
+   * the grouping elements wrapped by GROUP BY DISTINCT. A star nested inside
+   * any other expression, say {@code GROUPING SETS (ABS(*))}, is not
+   * expanded; validation of that expression fails because {@code *} is not
+   * a known column. */
+  private SqlNode rewriteGroupingStarNode(SqlNode node, SqlSelect select) {
+    if (node instanceof SqlIdentifier) {
+      final SqlIdentifier id = (SqlIdentifier) node;
+      if (id.isStar() && id.names.size() == 1) {
+        return starToRow(select, id.getParserPosition());
+      }
+      return node;
+    }
+    if (node instanceof SqlNodeList) {
+      final SqlNodeList list = (SqlNodeList) node;
+      List<@Nullable SqlNode> newItems = null;
+      int i = 0;
+      for (SqlNode item : list) {
+        final SqlNode newItem = rewriteGroupingStarNode(item, select);
+        if (newItem != item) {
+          if (newItems == null) {
+            newItems = new ArrayList<@Nullable SqlNode>(list.getList());
+          }
+          newItems.set(i, newItem);
+        }
+        i++;
+      }
+      return newItems == null ? node
+          : new SqlNodeList(newItems, list.getParserPosition());
+    }
+    if (node instanceof SqlCall && isGroupingStarContainer((SqlCall) node)) {
+      final SqlCall call = (SqlCall) node;
+      final List<SqlNode> operands = call.getOperandList();
+      List<SqlNode> newOperands = null;
+      for (int i = 0; i < operands.size(); i++) {
+        final SqlNode operand = operands.get(i);
+        final SqlNode newOperand = rewriteGroupingStarNode(operand, select);
+        if (newOperand != operand) {
+          if (newOperands == null) {
+            newOperands = new ArrayList<>(operands);
+          }
+          newOperands.set(i, newOperand);
+        }
+      }
+      if (newOperands != null) {
+        return call.getOperator().createCall(
+            call.getParserPosition(), newOperands);
+      }
+    }
+    return node;
+  }
+
+  /** Returns whether a call may directly contain a bare {@code *} grouping
+   * element: a GROUPING SETS, ROLLUP or CUBE sub-clause, a ROW tuple within
+   * one of those clauses, or the wrapper that GROUP BY DISTINCT places
+   * around its grouping elements. */
+  private static boolean isGroupingStarContainer(SqlCall call) {
+    switch (call.getKind()) {
+    case GROUPING_SETS:
+    case ROLLUP:
+    case CUBE:
+    case ROW:
+    case GROUP_BY_DISTINCT:
+      return true;
+    default:
+      return false;
+    }
+  }
+
+  /** Builds a {@code ROW} of every input column of the FROM clause, expanding
+   * a bare grouping {@code *}. */
+  private SqlNode starToRow(SqlSelect select, SqlParserPos pos) {
+    final SqlIdentifier star = SqlIdentifier.star(pos);
+    final List<SqlNode> columns = expandStarForAllRewrite(select, star);
+    if (columns.isEmpty()) {
+      throw newValidationError(star, RESOURCE.selectStarRequiresFrom());
+    }
+    return SqlStdOperatorTable.ROW.createCall(pos, columns);
+  }
+
   private void validateGroupItem(SqlValidatorScope groupScope,
       @Nullable AggregatingSelectScope aggregatingScope,
       SqlNode groupItem) {
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java 
b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index 3915e5723c..1336a92029 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -8302,6 +8302,84 @@ public boolean isBangEqualAllowed() {
         + "  ()").ok();
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-6537";>[CALCITE-6537]
+   * Add syntax to allow non-aggregated rows to be used in GROUPING SETS</a>. 
*/
+  @Test void testGroupingSetsStarConformance() {
+    // Under DEFAULT conformance, "*" is not a valid grouping element.
+    sql("select deptno, ename, sum(sal)\n"
+        + "from emp\n"
+        + "group by grouping sets ((deptno), (^*^))")
+        .fails("(?s).*Encountered.*\\*.*");
+
+    // Under LENIENT conformance, "*" expands to a ROW of every input column,
+    // so the non-aggregated SELECT columns are grouped in the detail set.
+    sql("select deptno, ename, sum(sal)\n"
+        + "from emp\n"
+        + "group by grouping sets ((deptno), (*))")
+        .withConformance(SqlConformanceEnum.LENIENT).ok();
+
+    // ROLLUP and CUBE accept "*" too.
+    sql("select deptno, ename, sum(sal) from emp\n"
+        + "group by rollup(deptno, *)")
+        .withConformance(SqlConformanceEnum.LENIENT).ok();
+    sql("select deptno, ename, sum(sal) from emp\n"
+        + "group by cube(deptno, *)")
+        .withConformance(SqlConformanceEnum.LENIENT).ok();
+  }
+
+  /** More tests for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-6537";>[CALCITE-6537]
+   * Add syntax to allow non-aggregated rows to be used in GROUPING SETS</a>.
+   *
+   * <p>Under LENIENT conformance, "*" is allowed as a complete grouping
+   * set, as an element of a grouping set, and as an argument of ROLLUP or
+   * CUBE, including grouping constructs nested within GROUPING SETS. It may
+   * not appear at the top level of GROUP BY, nor inside other expressions.
+   */
+  @Test void testGroupingSetsStarNested() {
+    // "*" as a complete grouping set
+    sql("select deptno, ename, sum(sal) from emp\n"
+        + "group by grouping sets (*)")
+        .withConformance(SqlConformanceEnum.LENIENT).ok();
+
+    // "*" as an element of a grouping set
+    sql("select deptno, ename, sum(sal) from emp\n"
+        + "group by grouping sets ((deptno, *))")
+        .withConformance(SqlConformanceEnum.LENIENT).ok();
+
+    // "*" as an argument of ROLLUP nested within GROUPING SETS
+    sql("select deptno, ename, sum(sal) from emp\n"
+        + "group by grouping sets ((deptno), rollup(ename, *))")
+        .withConformance(SqlConformanceEnum.LENIENT).ok();
+
+    // "*" inside a tuple that is a ROLLUP argument
+    sql("select deptno, ename, sum(sal) from emp\n"
+        + "group by rollup((deptno, *))")
+        .withConformance(SqlConformanceEnum.LENIENT).ok();
+
+    // "*" as a grouping set within GROUP BY DISTINCT
+    sql("select deptno, ename, sum(sal) from emp\n"
+        + "group by distinct grouping sets ((deptno), (*))")
+        .withConformance(SqlConformanceEnum.LENIENT).ok();
+
+    // "*" at the top level of GROUP BY is not allowed
+    sql("select deptno, ename, sum(sal) from emp\n"
+        + "group by ^*^")
+        .withConformance(SqlConformanceEnum.LENIENT)
+        .fails("(?s).*Encountered.*\\*.*");
+
+    // "*" inside another expression is not expanded; validation fails
+    sql("select sum(sal) from emp\n"
+        + "group by grouping sets (abs(^*^))")
+        .withConformance(SqlConformanceEnum.LENIENT)
+        .fails("(?s).*Unknown identifier '\\*'.*");
+    sql("select sum(sal) from emp\n"
+        + "group by grouping sets (deptno + ^*^)")
+        .withConformance(SqlConformanceEnum.LENIENT)
+        .fails("(?s).*Unknown identifier '\\*'.*");
+  }
+
   @Test void testRollup() {
     // DEPTNO is not null in database, but rollup introduces nulls
     sql("select deptno, count(*) as c, sum(sal) as s\n"
diff --git a/core/src/test/resources/sql/agg.iq 
b/core/src/test/resources/sql/agg.iq
index 41f2436a25..55fd016f03 100644
--- a/core/src/test/resources/sql/agg.iq
+++ b/core/src/test/resources/sql/agg.iq
@@ -4750,3 +4750,183 @@ order by y;
 !ok
 
 # End agg.iq
+
+# [CALCITE-6537] Add syntax to allow non-aggregated rows to be used in 
GROUPING SETS
+# non-aggregated (detail) rows. Requires LENIENT conformance.
+
+!use scott-lenient
+
+# GROUPING SETS ((deptno), (*)): department totals (ename NULL) plus one
+# detail row per employee.
+select deptno, ename, sum(sal) as sumsal
+from emp
+group by grouping sets ((deptno), (*))
+order by deptno, ename nulls first;
++--------+--------+----------+
+| DEPTNO | ENAME  | SUMSAL   |
++--------+--------+----------+
+|     10 |        |  8750.00 |
+|     10 | CLARK  |  2450.00 |
+|     10 | KING   |  5000.00 |
+|     10 | MILLER |  1300.00 |
+|     20 |        | 10875.00 |
+|     20 | ADAMS  |  1100.00 |
+|     20 | FORD   |  3000.00 |
+|     20 | JONES  |  2975.00 |
+|     20 | SCOTT  |  3000.00 |
+|     20 | SMITH  |   800.00 |
+|     30 |        |  9400.00 |
+|     30 | ALLEN  |  1600.00 |
+|     30 | BLAKE  |  2850.00 |
+|     30 | JAMES  |   950.00 |
+|     30 | MARTIN |  1250.00 |
+|     30 | TURNER |  1500.00 |
+|     30 | WARD   |  1250.00 |
++--------+--------+----------+
+(17 rows)
+
+!ok
+
+# ROLLUP (deptno, *): detail rows, department totals and a grand total.
+select deptno, ename, sum(sal) as sumsal
+from emp
+group by rollup (deptno, *)
+order by deptno nulls last, ename nulls first;
++--------+--------+----------+
+| DEPTNO | ENAME  | SUMSAL   |
++--------+--------+----------+
+|     10 |        |  8750.00 |
+|     10 | CLARK  |  2450.00 |
+|     10 | KING   |  5000.00 |
+|     10 | MILLER |  1300.00 |
+|     20 |        | 10875.00 |
+|     20 | ADAMS  |  1100.00 |
+|     20 | FORD   |  3000.00 |
+|     20 | JONES  |  2975.00 |
+|     20 | SCOTT  |  3000.00 |
+|     20 | SMITH  |   800.00 |
+|     30 |        |  9400.00 |
+|     30 | ALLEN  |  1600.00 |
+|     30 | BLAKE  |  2850.00 |
+|     30 | JAMES  |   950.00 |
+|     30 | MARTIN |  1250.00 |
+|     30 | TURNER |  1500.00 |
+|     30 | WARD   |  1250.00 |
+|        |        | 29025.00 |
++--------+--------+----------+
+(18 rows)
+
+!ok
+
+# GROUPING distinguishes the detail set (ename grouped, g=0) from the
+# department set (ename not grouped, g=1).
+select g, count(*) as cnt
+from (
+  select grouping(ename) as g
+  from emp
+  group by grouping sets ((deptno), (*)))
+group by g
+order by g;
++---+-----+
+| G | CNT |
++---+-----+
+| 0 |  14 |
+| 1 |   3 |
++---+-----+
+(2 rows)
+
+!ok
+
+# "*" as a complete grouping set returns one detail row per employee.
+select deptno, ename, sum(sal) as sumsal
+from emp
+group by grouping sets (*)
+order by deptno, ename;
++--------+--------+---------+
+| DEPTNO | ENAME  | SUMSAL  |
++--------+--------+---------+
+|     10 | CLARK  | 2450.00 |
+|     10 | KING   | 5000.00 |
+|     10 | MILLER | 1300.00 |
+|     20 | ADAMS  | 1100.00 |
+|     20 | FORD   | 3000.00 |
+|     20 | JONES  | 2975.00 |
+|     20 | SCOTT  | 3000.00 |
+|     20 | SMITH  |  800.00 |
+|     30 | ALLEN  | 1600.00 |
+|     30 | BLAKE  | 2850.00 |
+|     30 | JAMES  |  950.00 |
+|     30 | MARTIN | 1250.00 |
+|     30 | TURNER | 1500.00 |
+|     30 | WARD   | 1250.00 |
++--------+--------+---------+
+(14 rows)
+
+!ok
+
+# "*" combined with the empty grouping set: detail rows, department
+# totals and a grand total.
+select deptno, ename, sum(sal) as sumsal
+from emp
+group by grouping sets ((deptno), (*), ())
+order by deptno nulls last, ename nulls first;
++--------+--------+----------+
+| DEPTNO | ENAME  | SUMSAL   |
++--------+--------+----------+
+|     10 |        |  8750.00 |
+|     10 | CLARK  |  2450.00 |
+|     10 | KING   |  5000.00 |
+|     10 | MILLER |  1300.00 |
+|     20 |        | 10875.00 |
+|     20 | ADAMS  |  1100.00 |
+|     20 | FORD   |  3000.00 |
+|     20 | JONES  |  2975.00 |
+|     20 | SCOTT  |  3000.00 |
+|     20 | SMITH  |   800.00 |
+|     30 |        |  9400.00 |
+|     30 | ALLEN  |  1600.00 |
+|     30 | BLAKE  |  2850.00 |
+|     30 | JAMES  |   950.00 |
+|     30 | MARTIN |  1250.00 |
+|     30 | TURNER |  1500.00 |
+|     30 | WARD   |  1250.00 |
+|        |        | 29025.00 |
++--------+--------+----------+
+(18 rows)
+
+!ok
+
+# "*" inside a tuple that is a ROLLUP argument: detail rows and a grand
+# total.
+select deptno, ename, sum(sal) as sumsal
+from emp
+group by rollup((deptno, *))
+order by deptno nulls last, ename nulls first;
++--------+--------+----------+
+| DEPTNO | ENAME  | SUMSAL   |
++--------+--------+----------+
+|     10 | CLARK  |  2450.00 |
+|     10 | KING   |  5000.00 |
+|     10 | MILLER |  1300.00 |
+|     20 | ADAMS  |  1100.00 |
+|     20 | FORD   |  3000.00 |
+|     20 | JONES  |  2975.00 |
+|     20 | SCOTT  |  3000.00 |
+|     20 | SMITH  |   800.00 |
+|     30 | ALLEN  |  1600.00 |
+|     30 | BLAKE  |  2850.00 |
+|     30 | JAMES  |   950.00 |
+|     30 | MARTIN |  1250.00 |
+|     30 | TURNER |  1500.00 |
+|     30 | WARD   |  1250.00 |
+|        |        | 29025.00 |
++--------+--------+----------+
+(15 rows)
+
+!ok
+
+# Under DEFAULT conformance, * in GROUPING SETS is a parse error;
+# see SqlValidatorTest.testGroupingSetsStarConformance.
+# Nested forms and restrictions are in
+# SqlValidatorTest.testGroupingSetsStarNested.
+!use post

Reply via email to