This is an automated email from the ASF dual-hosted git repository.
zhenchen 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 87789d949f [CALCITE-7126] The calculation result of grouping function
is wrong
87789d949f is described below
commit 87789d949ff305aa5eacc9e6bd835b4f25bcd769
Author: Zhen Chen <[email protected]>
AuthorDate: Tue Aug 26 07:28:31 2025 +0800
[CALCITE-7126] The calculation result of grouping function is wrong
---
.../java/org/apache/calcite/tools/RelBuilder.java | 199 ++++++++++++++++-----
.../org/apache/calcite/test/RelBuilderTest.java | 5 +-
.../apache/calcite/test/SqlToRelConverterTest.xml | 32 ++--
core/src/test/resources/sql/agg.iq | 179 ++++++++++++++----
4 files changed, 318 insertions(+), 97 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
index 9831e65a76..164ac0628a 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -2817,10 +2817,12 @@ private RelBuilder aggregate_(ImmutableBitSet groupSet,
*
* <p>Also see the discussion in
* <a
href="https://issues.apache.org/jira/browse/CALCITE-1824">[CALCITE-1824]
- * GROUP_ID returns wrong result</a> and
+ * GROUP_ID returns wrong result</a>,
* <a
href="https://issues.apache.org/jira/browse/CALCITE-4748">[CALCITE-4748]
* If there are duplicate GROUPING SETS, Calcite should return duplicate
- * rows</a>.
+ * rows</a> and
+ * <a
href="https://issues.apache.org/jira/browse/CALCITE-7126">[CALCITE-7126]
+ * The calculation result of grouping function is wrong</a>.
*/
private RelBuilder rewriteAggregateWithDuplicateGroupSets(
ImmutableBitSet groupSet,
@@ -2832,23 +2834,11 @@ private RelBuilder
rewriteAggregateWithDuplicateGroupSets(
aggregateCalls.stream().map(AggCallPlus::aggregateCall)
.collect(toImmutableList())).getFieldNames();
- // If n duplicates exist for a particular grouping, the {@code GROUP_ID()}
- // function produces values in the range 0 to n-1. For each value,
- // we need to figure out the corresponding group sets.
- //
- // For example, "... GROUPING SETS (a, a, b, c, c, c, c)"
- // (i) The max value of the GROUP_ID() function returns is 3
- // (ii) GROUPING SETS (a, b, c) produces value 0,
- // GROUPING SETS (a, c) produces value 1,
- // GROUPING SETS (c) produces value 2
- // GROUPING SETS (c) produces value 3
+ final Frame input = stack.pop();
+
final Map<Integer, Set<ImmutableBitSet>> groupIdToGroupSets = new
HashMap<>();
- int maxGroupId = 0;
for (Multiset.Entry<ImmutableBitSet> entry : groupSets.entrySet()) {
int groupId = entry.getCount() - 1;
- if (groupId > maxGroupId) {
- maxGroupId = groupId;
- }
for (int i = 0; i <= groupId; i++) {
groupIdToGroupSets.computeIfAbsent(i,
k -> Sets.newTreeSet(ImmutableBitSet.COMPARATOR))
@@ -2856,43 +2846,148 @@ private RelBuilder
rewriteAggregateWithDuplicateGroupSets(
}
}
- // AggregateCall list without GROUP_ID function
- final List<AggCall> aggregateCallsWithoutGroupId =
- new ArrayList<>(aggregateCalls);
- aggregateCallsWithoutGroupId.removeIf(RelBuilder::isGroupId);
-
- // For each group id value, we first construct an Aggregate without
- // GROUP_ID() function call, and then create a Project node on top of it.
- // The Project adds literal value for group id in right position.
- final Frame frame = stack.pop();
- for (int groupId = 0; groupId <= maxGroupId; groupId++) {
- // Create the Aggregate node without GROUP_ID() call
- stack.push(frame);
- aggregate(groupKey(groupSet,
castNonNull(groupIdToGroupSets.get(groupId))),
- aggregateCallsWithoutGroupId);
-
- final List<RexNode> selectList = new ArrayList<>();
- final int groupExprLength = groupSet.cardinality();
- // Project fields in group by expressions
- for (int i = 0; i < groupExprLength; i++) {
- selectList.add(field(i));
+ // Create aggregate for each GROUP_ID value
+ for (Map.Entry<Integer, Set<ImmutableBitSet>> entry :
groupIdToGroupSets.entrySet()) {
+ // If n duplicates exist for a particular grouping, the {@code
GROUP_ID()}
+ // function produces values in the range 0 to n-1. For each value,
+ // we need to figure out the corresponding group sets.
+ //
+ // For example, "... GROUPING SETS (a, a, b, c, c, c, c)"
+ // (i) The max value of the GROUP_ID() function returns is 3
+ // (ii) GROUPING SETS (a, b, c) produces value 0,
+ // GROUPING SETS (a, c) produces value 1,
+ // GROUPING SETS (c) produces value 2
+ // GROUPING SETS (c) produces value 3
+ int groupId = entry.getKey();
+ Set<ImmutableBitSet> newGroupSets = entry.getValue();
+ rewriteGroupAggCalls(newGroupSets, groupSet, aggregateCalls,
+ fieldNamesIfNoRewrite, input, groupId);
+ }
+
+ return union(true, groupIdToGroupSets.size());
+ }
+
+ private void rewriteGroupAggCalls(
+ Set<ImmutableBitSet> subGroupSets,
+ ImmutableBitSet oriGroupSet,
+ List<AggCallPlus> oriAggCalls,
+ List<String> fieldNames,
+ Frame input,
+ int groupId) {
+ stack.push(input);
+ List<AggCallPlus> subAggCalls = new ArrayList<>();
+ ImmutableBitSet subGroupSet = ImmutableBitSet.union(subGroupSets);
+ List<RexNode> subProjects = new ArrayList<>();
+
+ // 1. For GroupSet
+ RelDataType subAggregateGroupSetType =
+ Aggregate.deriveRowType(getTypeFactory(), peek().getRowType(), false,
+ subGroupSet, ImmutableList.copyOf(subGroupSets),
ImmutableList.of());
+ for (int i = 0; i < oriGroupSet.cardinality(); i++) {
+ int groupKey = oriGroupSet.nth(i);
+ if (subGroupSet.get(groupKey)) {
+ subProjects.add(
+ RexInputRef.of(
+ subGroupSet.indexOf(groupKey),
+ subAggregateGroupSetType));
+ } else {
+ // If the groupKey is not in the GroupSet, use null as a placeholder.
+
subProjects.add(getRexBuilder().makeNullLiteral(field(groupKey).getType()));
}
- // Project fields in aggregate calls
- int groupIdCount = 0;
- for (int i = 0; i < aggregateCalls.size(); i++) {
- if (isGroupId(aggregateCalls.get(i))) {
- selectList.add(
- getRexBuilder().makeExactLiteral(BigDecimal.valueOf(groupId),
- getTypeFactory().createSqlType(SqlTypeName.BIGINT)));
- groupIdCount++;
+ }
+
+ // 2. For AggregateCalls
+ int newGroupCount = subGroupSet.cardinality();
+ for (AggCallPlus oriAggCall : oriAggCalls) {
+ AggregateCall aggCall = oriAggCall.aggregateCall();
+ switch (oriAggCall.op().getKind()) {
+ case GROUPING:
+ if (!subGroupSet.contains(ImmutableBitSet.of(aggCall.getArgList()))) {
+ // If the parameters of the GROUPING function cannot be fully
covered by the GroupSet,
+ // the GROUPING function needs to be split.
+ splitGrouping(subAggCalls, subProjects, aggCall, subGroupSet);
} else {
- selectList.add(field(groupExprLength + i - groupIdCount));
+ subProjects.add(
+ new RexInputRef(
+ newGroupCount + subAggCalls.size(),
+ aggCall.getType()));
+ subAggCalls.add(oriAggCall);
}
+ break;
+ case GROUP_ID:
+ subProjects.add(
+ getRexBuilder().makeLiteral(
+ groupId,
+ aggCall.getType()));
+ break;
+ default:
+ subProjects.add(
+ new RexInputRef(
+ newGroupCount + subAggCalls.size(),
+ aggCall.getType()));
+ subAggCalls.add(oriAggCall);
+ break;
+ }
+ }
+
+ aggregate(groupKey(subGroupSet, subGroupSets), subAggCalls);
+ project(subProjects, fieldNames);
+ }
+
+ /**
+ * This method is used to expand the SQL GROUPING operator
+ * into a set of expressions. For example, it expands GROUPING(x, y, z)
+ * into 2^2 * GROUPING(x) + 2^1 * GROUPING(y) + 2^0 * GROUPING(z)
+ *
+ * <p>For example, in "GROUP BY GROUPING SETS ((a, b), (a), (), (b))":
+ * In the grouping set (a, b), GROUPING(a) = 0, GROUPING(b) = 0,
+ * GROUPING(a, b) = 2^1 * 0 + 2^0 * 0 => 0.
+ * In the grouping set (a), GROUPING(a) = 0, GROUPING(b) = 1,
+ * GROUPING(a, b) = 2^1 * 0 + 2^0 * 1 => 1.
+ * In the grouping set (), GROUPING(a) = 1, GROUPING(b) = 1,
+ * GROUPING(a, b) = 2^1 * 1 + 2^0 * 1 = 3.
+ * In the grouping set (b), GROUPING(a) = 1, GROUPING(b) = 0,
+ * GROUPING(a, b) = 2^1 * 1 + 2^0 * 0 = 2.
+ * Thus, GROUPING(a, b) produces 0, 1, 3, and 2 for each grouping set
respectively.
+ */
+ private void splitGrouping(
+ List<AggCallPlus> aggCalls,
+ List<RexNode> projects,
+ AggregateCall grouping,
+ ImmutableBitSet groupSet) {
+ List<RexNode> splitOperands = new ArrayList<>();
+ List<Integer> groupingArgs = grouping.getArgList();
+ RelDataType groupingType =
getTypeFactory().createSqlType(SqlTypeName.BIGINT);
+ for (int i = 0; i < groupingArgs.size(); i++) {
+ int groupingArg = groupingArgs.get(i);
+ if (groupSet.get(groupingArg)) {
+ RexInputRef groupingRef =
+ new RexInputRef(groupSet.cardinality() + aggCalls.size(),
groupingType);
+ splitOperands.add(
+ call(SqlStdOperatorTable.MULTIPLY,
+ literal(safeShift(groupingArgs.size() - 1 - i)),
+ groupingRef));
+ aggCalls.add((AggCallPlus) aggregateCall(SqlStdOperatorTable.GROUPING,
field(groupingArg)));
+ } else {
+ // Sets GROUPING function value to 1 for parameters not in GroupSet
and calculates offset.
+ splitOperands.add(literal(safeShift(groupingArgs.size() - 1 - i)));
}
- project(selectList, fieldNamesIfNoRewrite);
}
- return union(true, maxGroupId + 1);
+ // Plus all expanded expressions (including GROUPING functions and
constants).
+ RexNode plus = splitOperands.get(0);
+ for (int i = 1; i < splitOperands.size(); i++) {
+ plus = call(SqlStdOperatorTable.PLUS, plus, splitOperands.get(i));
+ }
+ projects.add(plus);
+ }
+
+ private static int safeShift(int shift) {
+ if (shift < 0 || shift >= Integer.SIZE) {
+ throw new IllegalArgumentException(
+ "Too many grouping keys. Maximum is " + (Integer.SIZE - 1) + " for
grouping functions.");
+ }
+ return 1 << shift;
}
private static boolean isGroupId(AggCall c) {
@@ -4447,8 +4542,14 @@ private class AggCallImpl implements AggCallPlus {
// return a call that is "approximately equivalent ... and is good for
// deriving field names", so dummy values are good enough.
final RelCollation collation = RelCollations.EMPTY;
- final RelDataType type =
- getTypeFactory().createSqlType(SqlTypeName.BOOLEAN);
+ final RelDataType type;
+ if (aggFunction.getKind() == SqlKind.GROUP_ID) {
+ // The return type of GROUP_ID function is SqlTypeName.BIGINT,
+ // see SqlGroupIdFunction.
+ type = getTypeFactory().createSqlType(SqlTypeName.BIGINT);
+ } else {
+ type = getTypeFactory().createSqlType(SqlTypeName.BOOLEAN);
+ }
return AggregateCall.create(pos, aggFunction, distinct, approximate,
ignoreNulls, preOperands, ImmutableList.of(), -1,
null, collation, type, alias);
diff --git a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
index 0e105ed784..9ca3eec4c8 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -2057,8 +2057,9 @@ private RelNode buildRelWithDuplicateAggregates(
+ "LogicalUnion(all=[true])\n"
+ " LogicalAggregate(group=[{6, 7}], groups=[[{6}, {7}]])\n"
+ " LogicalTableScan(table=[[scott, EMP]])\n"
- + " LogicalAggregate(group=[{6, 7}], groups=[[{7}]])\n"
- + " LogicalTableScan(table=[[scott, EMP]])\n";
+ + " LogicalProject(COMM=[null:DECIMAL(7, 2)], DEPTNO=[$0])\n"
+ + " LogicalAggregate(group=[{7}])\n"
+ + " LogicalTableScan(table=[[scott, EMP]])\n";
assertThat(root, hasTree(expected));
}
diff --git
a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
index 787bad3174..07292374bc 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -1866,9 +1866,10 @@ LogicalProject(EXPR$0=[$3])
LogicalAggregate(group=[{0, 1, 2}], groups=[[{0, 1, 2}, {0, 1}, {0, 2}]],
EXPR$0=[SUM($0)])
LogicalProject(SAL=[$5], DEPTNO=[$7], ENAME=[$1])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
- LogicalAggregate(group=[{0, 1, 2}], groups=[[{0, 2}]], EXPR$0=[SUM($0)])
- LogicalProject(SAL=[$5], DEPTNO=[$7], ENAME=[$1])
- LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalProject(SAL=[$0], DEPTNO=[null:INTEGER], ENAME=[$1], EXPR$0=[$2])
+ LogicalAggregate(group=[{0, 2}], EXPR$0=[SUM($0)])
+ LogicalProject(SAL=[$5], DEPTNO=[$7], ENAME=[$1])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
]]>
</Resource>
</TestCase>
@@ -2743,8 +2744,8 @@ LogicalProject(DEPTNO=[$0], EXPR$1=[$2])
LogicalAggregate(group=[{0, 1}], groups=[[{0}, {1}]])
LogicalProject(DEPTNO=[$7], JOB=[$2])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
- LogicalProject(DEPTNO=[$0], JOB=[$1], EXPR$1=[2:BIGINT])
- LogicalAggregate(group=[{0, 1}], groups=[[{0}]])
+ LogicalProject(DEPTNO=[$0], JOB=[null:VARCHAR(10)], EXPR$1=[2:BIGINT])
+ LogicalAggregate(group=[{0}])
LogicalProject(DEPTNO=[$7], JOB=[$2])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
]]>
@@ -2766,9 +2767,10 @@ LogicalUnion(all=[true])
LogicalAggregate(group=[{0, 1}], groups=[[{0}, {1}]])
LogicalProject(DEPTNO=[$7], JOB=[$2])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
- LogicalAggregate(group=[{0, 1}], groups=[[{0}]])
- LogicalProject(DEPTNO=[$7], JOB=[$2])
- LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalProject(DEPTNO=[$0], JOB=[null:VARCHAR(10)])
+ LogicalAggregate(group=[{0}])
+ LogicalProject(DEPTNO=[$7], JOB=[$2])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
]]>
</Resource>
</TestCase>
@@ -2799,9 +2801,10 @@ LogicalSort(sort0=[$1], dir0=[ASC])
LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {1}, {}]],
EXPR$2=[SUM($2)])
LogicalProject(DEPTNO=[$7], ENAME=[$1], SAL=[$5])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
- LogicalAggregate(group=[{0, 1}], groups=[[{0}]], EXPR$2=[SUM($2)])
- LogicalProject(DEPTNO=[$7], ENAME=[$1], SAL=[$5])
- LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalProject(DEPTNO=[$0], ENAME=[null:VARCHAR(20)], EXPR$2=[$1])
+ LogicalAggregate(group=[{0}], EXPR$2=[SUM($2)])
+ LogicalProject(DEPTNO=[$7], ENAME=[$1], SAL=[$5])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
]]>
</Resource>
</TestCase>
@@ -2872,9 +2875,10 @@ LogicalSort(sort0=[$1], dir0=[ASC])
LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {1}, {}]],
EXPR$2=[SUM($2)])
LogicalProject(DEPTNO=[$7], ENAME=[$1], SAL=[$5])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
- LogicalAggregate(group=[{0, 1}], groups=[[{}]], EXPR$2=[SUM($2)])
- LogicalProject(DEPTNO=[$7], ENAME=[$1], SAL=[$5])
- LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalProject(DEPTNO=[null:INTEGER], ENAME=[null:VARCHAR(20)],
EXPR$2=[$0])
+ LogicalAggregate(group=[{}], EXPR$2=[SUM($2)])
+ LogicalProject(DEPTNO=[$7], ENAME=[$1], SAL=[$5])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
]]>
</Resource>
</TestCase>
diff --git a/core/src/test/resources/sql/agg.iq
b/core/src/test/resources/sql/agg.iq
index 553047b76e..3852b29472 100644
--- a/core/src/test/resources/sql/agg.iq
+++ b/core/src/test/resources/sql/agg.iq
@@ -765,7 +765,8 @@ select count(*) as c,
grouping_id(gender, deptno) as ggd,
grouping_id(deptno, gender) as gdg
from emp
-group by rollup(deptno, gender);
+group by rollup(deptno, gender)
+order by c, g, gid, gd, gg, ggd, gdg;
+---+---+-----+----+----+-----+-----+
| C | G | GID | GD | GG | GGD | GDG |
+---+---+-----+----+----+-----+-----+
@@ -776,14 +777,14 @@ group by rollup(deptno, gender);
| 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 0 | 0 | 0 | 0 | 0 |
-| 2 | 0 | 0 | 0 | 0 | 0 | 0 |
-| 9 | 1 | 0 | 1 | 1 | 3 | 3 |
| 1 | 0 | 0 | 0 | 1 | 2 | 1 |
| 1 | 0 | 0 | 0 | 1 | 2 | 1 |
| 1 | 0 | 0 | 0 | 1 | 2 | 1 |
+| 2 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 0 | 0 | 0 | 1 | 2 | 1 |
| 2 | 0 | 0 | 0 | 1 | 2 | 1 |
| 2 | 0 | 0 | 0 | 1 | 2 | 1 |
+| 9 | 1 | 0 | 1 | 1 | 3 | 3 |
+---+---+-----+----+----+-----+-----+
(15 rows)
@@ -880,31 +881,32 @@ group by rollup(deptno);
# GROUPING, GROUPING_ID and GROUP_ID
select deptno, gender, grouping(deptno) gd, grouping(gender) gg,
- grouping_id(deptno, gender) dg, grouping_id(gender, deptno) gd,
- group_id() gid, count(*) c
+ grouping_id(deptno, gender) dg, grouping_id(gender, deptno) gid,
+ group_id() g, count(*) c
from emp
-group by cube(deptno, gender);
-+--------+--------+----+----+----+----+-----+---+
-| DEPTNO | GENDER | GD | GG | DG | GD | GID | C |
-+--------+--------+----+----+----+----+-----+---+
-| 10 | F | 0 | 0 | 0 | 0 | 0 | 1 |
-| 10 | M | 0 | 0 | 0 | 0 | 0 | 1 |
-| 20 | M | 0 | 0 | 0 | 0 | 0 | 1 |
-| 30 | F | 0 | 0 | 0 | 0 | 0 | 2 |
-| 50 | F | 0 | 0 | 0 | 0 | 0 | 1 |
-| 50 | M | 0 | 0 | 0 | 0 | 0 | 1 |
-| 60 | F | 0 | 0 | 0 | 0 | 0 | 1 |
-| | F | 0 | 0 | 0 | 0 | 0 | 1 |
-| | | 1 | 1 | 3 | 3 | 0 | 9 |
-| 10 | | 0 | 1 | 1 | 2 | 0 | 2 |
-| 20 | | 0 | 1 | 1 | 2 | 0 | 1 |
-| 30 | | 0 | 1 | 1 | 2 | 0 | 2 |
-| 50 | | 0 | 1 | 1 | 2 | 0 | 2 |
-| 60 | | 0 | 1 | 1 | 2 | 0 | 1 |
-| | F | 1 | 0 | 2 | 1 | 0 | 6 |
-| | M | 1 | 0 | 2 | 1 | 0 | 3 |
-| | | 0 | 1 | 1 | 2 | 0 | 1 |
-+--------+--------+----+----+----+----+-----+---+
+group by cube(deptno, gender)
+order by deptno, gender, gd, gg, dg, gid, g, c;
++--------+--------+----+----+----+-----+---+---+
+| DEPTNO | GENDER | GD | GG | DG | GID | G | C |
++--------+--------+----+----+----+-----+---+---+
+| 10 | F | 0 | 0 | 0 | 0 | 0 | 1 |
+| 10 | M | 0 | 0 | 0 | 0 | 0 | 1 |
+| 10 | | 0 | 1 | 1 | 2 | 0 | 2 |
+| 20 | M | 0 | 0 | 0 | 0 | 0 | 1 |
+| 20 | | 0 | 1 | 1 | 2 | 0 | 1 |
+| 30 | F | 0 | 0 | 0 | 0 | 0 | 2 |
+| 30 | | 0 | 1 | 1 | 2 | 0 | 2 |
+| 50 | F | 0 | 0 | 0 | 0 | 0 | 1 |
+| 50 | M | 0 | 0 | 0 | 0 | 0 | 1 |
+| 50 | | 0 | 1 | 1 | 2 | 0 | 2 |
+| 60 | F | 0 | 0 | 0 | 0 | 0 | 1 |
+| 60 | | 0 | 1 | 1 | 2 | 0 | 1 |
+| | F | 0 | 0 | 0 | 0 | 0 | 1 |
+| | F | 1 | 0 | 2 | 1 | 0 | 6 |
+| | M | 1 | 0 | 2 | 1 | 0 | 3 |
+| | | 0 | 1 | 1 | 2 | 0 | 1 |
+| | | 1 | 1 | 3 | 3 | 0 | 9 |
++--------+--------+----+----+----+-----+---+---+
(17 rows)
!ok
@@ -1339,11 +1341,6 @@ order by g, i, s desc;
| 1900.00 | 0 | 0 |
| 1300.00 | 0 | 0 |
| 950.00 | 0 | 0 |
-| 8275.00 | 0 | 1 |
-| 6000.00 | 0 | 1 |
-| 5600.00 | 0 | 1 |
-| 5000.00 | 0 | 1 |
-| 4150.00 | 0 | 1 |
| 6000.00 | 1 | 0 |
| 5600.00 | 1 | 0 |
| 5000.00 | 1 | 0 |
@@ -1358,6 +1355,11 @@ order by g, i, s desc;
| 5600.00 | 2 | 0 |
| 5000.00 | 2 | 0 |
| 4150.00 | 2 | 0 |
+| 8275.00 | 2 | 1 |
+| 6000.00 | 2 | 1 |
+| 5600.00 | 2 | 1 |
+| 5000.00 | 2 | 1 |
+| 4150.00 | 2 | 1 |
+---------+---+---+
(28 rows)
@@ -3897,4 +3899,117 @@ EnumerableCalc(expr#0=[{inputs}],
expr#1=[CAST($t0):BIGINT NOT NULL], M=[$t1])
EnumerableTableScan(table=[[scott, EMP]])
!plan
+# [CALCITE-7126] The calculation result of grouping function is wrong
+SELECT deptno, job, sal, SUM(comm),
+ GROUPING(deptno) AS deptno_flag,
+ GROUPING(job) AS job_flag,
+ GROUPING(sal) AS sal_flag
+FROM emp
+GROUP BY GROUPING SETS ((deptno, job), (deptno, sal), (deptno, job))
+ORDER BY deptno, job, sal;
++--------+-----------+---------+---------+-------------+----------+----------+
+| DEPTNO | JOB | SAL | EXPR$3 | DEPTNO_FLAG | JOB_FLAG | SAL_FLAG |
++--------+-----------+---------+---------+-------------+----------+----------+
+| 10 | CLERK | | | 0 | 0 | 1 |
+| 10 | CLERK | | | 0 | 0 | 1 |
+| 10 | MANAGER | | | 0 | 0 | 1 |
+| 10 | MANAGER | | | 0 | 0 | 1 |
+| 10 | PRESIDENT | | | 0 | 0 | 1 |
+| 10 | PRESIDENT | | | 0 | 0 | 1 |
+| 10 | | 1300.00 | | 0 | 1 | 0 |
+| 10 | | 2450.00 | | 0 | 1 | 0 |
+| 10 | | 5000.00 | | 0 | 1 | 0 |
+| 20 | ANALYST | | | 0 | 0 | 1 |
+| 20 | ANALYST | | | 0 | 0 | 1 |
+| 20 | CLERK | | | 0 | 0 | 1 |
+| 20 | CLERK | | | 0 | 0 | 1 |
+| 20 | MANAGER | | | 0 | 0 | 1 |
+| 20 | MANAGER | | | 0 | 0 | 1 |
+| 20 | | 800.00 | | 0 | 1 | 0 |
+| 20 | | 1100.00 | | 0 | 1 | 0 |
+| 20 | | 2975.00 | | 0 | 1 | 0 |
+| 20 | | 3000.00 | | 0 | 1 | 0 |
+| 30 | CLERK | | | 0 | 0 | 1 |
+| 30 | CLERK | | | 0 | 0 | 1 |
+| 30 | MANAGER | | | 0 | 0 | 1 |
+| 30 | MANAGER | | | 0 | 0 | 1 |
+| 30 | SALESMAN | | 2200.00 | 0 | 0 | 1 |
+| 30 | SALESMAN | | 2200.00 | 0 | 0 | 1 |
+| 30 | | 950.00 | | 0 | 1 | 0 |
+| 30 | | 1250.00 | 1900.00 | 0 | 1 | 0 |
+| 30 | | 1500.00 | 0.00 | 0 | 1 | 0 |
+| 30 | | 1600.00 | 300.00 | 0 | 1 | 0 |
+| 30 | | 2850.00 | | 0 | 1 | 0 |
++--------+-----------+---------+---------+-------------+----------+----------+
+(30 rows)
+
+!ok
+
+EnumerableMergeUnion(all=[true])
+ EnumerableSort(sort0=[$0], sort1=[$1], sort2=[$2], dir0=[ASC], dir1=[ASC],
dir2=[ASC])
+ EnumerableCalc(expr#0..6=[{inputs}], DEPTNO=[$t2], JOB=[$t0], SAL=[$t1],
EXPR$3=[$t3], DEPTNO_FLAG=[$t4], JOB_FLAG=[$t5], SAL_FLAG=[$t6])
+ EnumerableAggregate(group=[{2, 5, 7}], groups=[[{2, 7}, {5, 7}]],
EXPR$3=[SUM($6)], DEPTNO_FLAG=[GROUPING($7)], JOB_FLAG=[GROUPING($2)],
SAL_FLAG=[GROUPING($5)])
+ EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableSort(sort0=[$0], sort1=[$1], sort2=[$2], dir0=[ASC], dir1=[ASC],
dir2=[ASC])
+ EnumerableCalc(expr#0..4=[{inputs}], expr#5=[null:DECIMAL(7, 2)],
expr#6=[1], DEPTNO=[$t1], JOB=[$t0], SAL=[$t5], EXPR$3=[$t2],
DEPTNO_FLAG=[$t3], JOB_FLAG=[$t4], SAL_FLAG=[$t6])
+ EnumerableAggregate(group=[{2, 7}], EXPR$3=[SUM($6)],
DEPTNO_FLAG=[GROUPING($7)], JOB_FLAG=[GROUPING($2)])
+ EnumerableTableScan(table=[[scott, EMP]])
+!plan
+
+# The subset of GROUPING SETS cannot contain all the fields in the GROUPING
and GROUPING SETS has duplicate groupings
+SELECT deptno, job, sal,
+ SUM(comm) AS sum_comm,
+ GROUPING(deptno, job, sal) AS flag,
+ GROUP_ID() AS g
+FROM emp
+GROUP BY GROUPING SETS ((deptno, job), (deptno, sal), (deptno, job))
+ORDER BY deptno, job, sal;
++--------+-----------+---------+----------+------+---+
+| DEPTNO | JOB | SAL | SUM_COMM | FLAG | G |
++--------+-----------+---------+----------+------+---+
+| 10 | CLERK | | | 1 | 0 |
+| 10 | CLERK | | | 1 | 1 |
+| 10 | MANAGER | | | 1 | 0 |
+| 10 | MANAGER | | | 1 | 1 |
+| 10 | PRESIDENT | | | 1 | 0 |
+| 10 | PRESIDENT | | | 1 | 1 |
+| 10 | | 1300.00 | | 2 | 0 |
+| 10 | | 2450.00 | | 2 | 0 |
+| 10 | | 5000.00 | | 2 | 0 |
+| 20 | ANALYST | | | 1 | 0 |
+| 20 | ANALYST | | | 1 | 1 |
+| 20 | CLERK | | | 1 | 0 |
+| 20 | CLERK | | | 1 | 1 |
+| 20 | MANAGER | | | 1 | 0 |
+| 20 | MANAGER | | | 1 | 1 |
+| 20 | | 800.00 | | 2 | 0 |
+| 20 | | 1100.00 | | 2 | 0 |
+| 20 | | 2975.00 | | 2 | 0 |
+| 20 | | 3000.00 | | 2 | 0 |
+| 30 | CLERK | | | 1 | 0 |
+| 30 | CLERK | | | 1 | 1 |
+| 30 | MANAGER | | | 1 | 0 |
+| 30 | MANAGER | | | 1 | 1 |
+| 30 | SALESMAN | | 2200.00 | 1 | 0 |
+| 30 | SALESMAN | | 2200.00 | 1 | 1 |
+| 30 | | 950.00 | | 2 | 0 |
+| 30 | | 1250.00 | 1900.00 | 2 | 0 |
+| 30 | | 1500.00 | 0.00 | 2 | 0 |
+| 30 | | 1600.00 | 300.00 | 2 | 0 |
+| 30 | | 2850.00 | | 2 | 0 |
++--------+-----------+---------+----------+------+---+
+(30 rows)
+
+!ok
+EnumerableMergeUnion(all=[true])
+ EnumerableSort(sort0=[$0], sort1=[$1], sort2=[$2], dir0=[ASC], dir1=[ASC],
dir2=[ASC])
+ EnumerableCalc(expr#0..4=[{inputs}], expr#5=[0:BIGINT], DEPTNO=[$t2],
JOB=[$t0], SAL=[$t1], SUM_COMM=[$t3], FLAG=[$t4], G=[$t5])
+ EnumerableAggregate(group=[{2, 5, 7}], groups=[[{2, 7}, {5, 7}]],
SUM_COMM=[SUM($6)], FLAG=[GROUPING($7, $2, $5)])
+ EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableSort(sort0=[$0], sort1=[$1], sort2=[$2], dir0=[ASC], dir1=[ASC],
dir2=[ASC])
+ EnumerableCalc(expr#0..4=[{inputs}], expr#5=[null:DECIMAL(7, 2)],
expr#6=[4], expr#7=[*($t6, $t3)], expr#8=[2], expr#9=[*($t8, $t4)],
expr#10=[+($t7, $t9)], expr#11=[1], expr#12=[+($t10, $t11)],
expr#13=[1:BIGINT], DEPTNO=[$t1], JOB=[$t0], SAL=[$t5], SUM_COMM=[$t2],
FLAG=[$t12], G=[$t13])
+ EnumerableAggregate(group=[{2, 7}], SUM_COMM=[SUM($6)],
agg#1=[GROUPING($7)], agg#2=[GROUPING($2)])
+ EnumerableTableScan(table=[[scott, EMP]])
+!plan
+
# End agg.iq