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