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 5edac100ac1..e274ace1998 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
@@ -32,6 +32,7 @@
import org.apache.calcite.tools.RelBuilder;
import org.apache.calcite.tools.RelBuilderFactory;
import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.mapping.Mappings;
import com.google.common.collect.ImmutableList;
@@ -149,8 +150,13 @@ private static boolean canPush(Aggregate aggregate, ImmutableBitSet rCols) {
// If grouping sets are used, the filter can be pushed if
// the columns referenced in the predicate are present in
// all the grouping sets.
+ final Mappings.TargetMapping aggregateInputToOutput =
+ Mappings.target(aggregate.getGroupSet().asList(),
+ aggregate.getInput().getRowType().getFieldCount());
for (ImmutableBitSet groupingSet : aggregate.getGroupSets()) {
- if (!groupingSet.contains(rCols)) {
+ final ImmutableBitSet groupingSetOutputRefs =
+ groupingSet.permute(aggregateInputToOutput);
+ if (!groupingSetOutputRefs.contains(rCols)) {
return false;
}
}
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 7eae22b17ec..a7945606bc9 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -1364,6 +1364,32 @@ private RelOptFixture basePushFilterPastAggWithGroupingSets() {
basePushFilterPastAggWithGroupingSets().check();
}
+ private RelOptFixture pushFilterPastAggWithNonLeadingGroupingKeys(String condition) {
+ final String sql = "select a, b\n"
+ + "from (values (0, 1, 2)) as t(unused, a, b)\n"
+ + "group by grouping sets ((a), (a, b))\n"
+ + "having " + condition;
+ return sql(sql)
+ .withPreRule(CoreRules.AGGREGATE_PROJECT_MERGE)
+ .withRule(CoreRules.FILTER_AGGREGATE_TRANSPOSE);
+ }
+
+ /** Test case for
+ * [CALCITE-7779]
+ * Optimization rule FilterAggregateTransposeRule rewrites queries to
+ * semantically non-equivalent ones. */
+ @Test void testPushFilterPastAggWithGroupingSetsNonLeadingKeysIsNull() {
+ pushFilterPastAggWithNonLeadingGroupingKeys("b is null").checkUnchanged();
+ }
+
+ @Test void testPushFilterPastAggWithGroupingSetsNonLeadingKeysEquals() {
+ pushFilterPastAggWithNonLeadingGroupingKeys("b = 2").checkUnchanged();
+ }
+
+ @Test void testPushFilterPastAggWithGroupingSetsNonLeadingKeys() {
+ pushFilterPastAggWithNonLeadingGroupingKeys("a = 1").check();
+ }
+
/** Test case for
* [CALCITE-434]
* FilterAggregateTransposeRule loses conditions that cannot be pushed. */
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index 88c80246ad6..97e54f5c7c4 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -15104,6 +15104,58 @@ LogicalProject(DNAME=[$0], DDEPTNO=[$1], C=[$2])
LogicalFilter(condition=[=($0, 'Charlie')])
LogicalProject(DNAME=[$1], DDEPTNO=[$0])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core/src/test/resources/sql/hep.iq b/core/src/test/resources/sql/hep.iq
index 812663177a8..b9aee8e1f41 100644
--- a/core/src/test/resources/sql/hep.iq
+++ b/core/src/test/resources/sql/hep.iq
@@ -353,4 +353,26 @@ EnumerableAggregate(group=[{0}], EXPR$1=[COUNT()])
!set hep-rules original
+# [CALCITE-7779] Optimization rule FilterAggregateTransposeRule rewrites queries to semantically non-equivalent ones
+!set hep-rules "
++CoreRules.AGGREGATE_PROJECT_MERGE,
++CoreRules.FILTER_AGGREGATE_TRANSPOSE"
+
+select dname, loc
+from dept
+group by grouping sets ((dname), (dname, loc))
+having loc is null;
++------------+-----+
+| DNAME | LOC |
++------------+-----+
+| ACCOUNTING | |
+| OPERATIONS | |
+| RESEARCH | |
+| SALES | |
++------------+-----+
+(4 rows)
+
+!ok
+!set hep-rules original
+
# End hep.iq