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

mihaibudiu 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 2b794ff5a9 [CALCITE-7687] Aggregate selectivity estimation uses 
incorrect column references
2b794ff5a9 is described below

commit 2b794ff5a9e4874905a91d475a2136ce5107aeb0
Author: npaincomplet <[email protected]>
AuthorDate: Wed Sep 16 14:59:58 2026 +0200

    [CALCITE-7687] Aggregate selectivity estimation uses incorrect column 
references
---
 .../calcite/rel/metadata/RelMdSelectivity.java     | 17 +++++++++-
 .../apache/calcite/test/RelMdSelectivityTest.java  | 32 +++++++++++++++++++
 core/src/test/resources/sql/hep.iq                 | 36 ++++++++++++++++++++++
 .../org/apache/calcite/test/DruidAdapter2IT.java   |  4 +--
 .../org/apache/calcite/test/DruidAdapterIT.java    |  4 +--
 5 files changed, 88 insertions(+), 5 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java 
b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java
index 5faaeaa85d..d4d3897e9d 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java
@@ -180,7 +180,7 @@ protected RelMdSelectivity() {
     final List<RexNode> notPushable = new ArrayList<>();
     final List<RexNode> pushable = new ArrayList<>();
     RelOptUtil.splitFilters(
-        rel.getGroupSet(),
+        ImmutableBitSet.range(rel.getGroupCount()),
         predicate,
         pushable,
         notPushable);
@@ -188,6 +188,21 @@ protected RelMdSelectivity() {
     RexNode childPred =
         RexUtil.composeConjunction(rexBuilder, pushable, true);
 
+    if (childPred != null) {
+      // Convert aggregate-output references to the corresponding input fields.
+      final int[] adjustments = new int[rel.getGroupCount()];
+      int j = 0;
+      for (int i : rel.getGroupSet()) {
+        adjustments[j] = i - j;
+        j++;
+      }
+      childPred =
+          childPred.accept(
+              new RelOptUtil.RexInputConverter(rexBuilder,
+              rel.getRowType().getFieldList(),
+              rel.getInput().getRowType().getFieldList(), adjustments));
+    }
+
     Double selectivity = mq.getSelectivity(rel.getInput(), childPred);
     if (selectivity == null) {
       return null;
diff --git 
a/core/src/test/java/org/apache/calcite/test/RelMdSelectivityTest.java 
b/core/src/test/java/org/apache/calcite/test/RelMdSelectivityTest.java
index a086022bed..38c9f1cbc8 100644
--- a/core/src/test/java/org/apache/calcite/test/RelMdSelectivityTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelMdSelectivityTest.java
@@ -20,16 +20,48 @@
 import org.apache.calcite.plan.hep.HepProgram;
 import org.apache.calcite.plan.hep.HepProgramBuilder;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.rules.CoreRules;
+import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.tools.RelBuilder;
 
 import org.junit.jupiter.api.Test;
 
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
 /**
  * Test cases for {@link org.apache.calcite.rel.metadata.RelMdSelectivity}.
  */
 class RelMdSelectivityTest {
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-7687";>[CALCITE-7687]
+   * Aggregate selectivity estimation uses incorrect column references</a>. */
+  @Test void testAggregateSelectivityWithPredicate() {
+    final RelBuilder builder = 
RelBuilder.create(RelBuilderTest.config().build())
+        .transform(c -> c.withPruneInputOfAggregate(false));
+    final Aggregate aggregate = (Aggregate) builder
+        .scan("EMP")
+        .project(
+            builder.field("EMPNO"),
+            builder.field("DEPTNO"))
+        .filter(
+            builder.equals(
+                builder.field("DEPTNO"),
+                builder.literal(10)))
+        .aggregate(
+            builder.groupKey("DEPTNO"),
+            builder.countStar("C"))
+        .peek();
+
+    final RexNode predicate =
+        builder.equals(builder.field("DEPTNO"), builder.literal(10));
+
+    assertThat(aggregate.getCluster().getMetadataQuery()
+        .getSelectivity(aggregate, predicate), is(1D));
+  }
+
   /** Test case for
    * <a 
href="https://issues.apache.org/jira/browse/CALCITE-4414";>[CALCITE-4414]
    * RelMdSelectivity#getSelectivity for Calc can propagate a predicate with 
wrong reference</a>. */
diff --git a/core/src/test/resources/sql/hep.iq 
b/core/src/test/resources/sql/hep.iq
index b9aee8e1f4..3498fdea19 100644
--- a/core/src/test/resources/sql/hep.iq
+++ b/core/src/test/resources/sql/hep.iq
@@ -375,4 +375,40 @@ having loc is null;
 !ok
 !set hep-rules original
 
+# [CALCITE-7687] Aggregate selectivity estimation uses incorrect column 
references
+!set hep-rules "
++CoreRules.AGGREGATE_PROJECT_MERGE"
+
+# Display the result of the query explained below.
+with t(n, a, r) as (
+  values (0, 'a', cast(row(10) as row(d integer))),
+         (1, 'b', cast(row(20) as row(d integer)))
+)
+select a, r, sum(n) as s
+from t
+group by a, r
+having (r).d = 10;
++---+------+---+
+| A | R    | S |
++---+------+---+
+| a | {10} | 0 |
++---+------+---+
+(1 row)
+
+!ok
+
+# Verify aggregate selectivity estimation during EXPLAIN preparation does not 
fail.
+explain plan including all attributes for
+with t(n, a, r) as (
+  values (0, 'a', cast(row(10) as row(d integer))),
+         (1, 'b', cast(row(20) as row(d integer)))
+)
+select a, r, sum(n) as s
+from t
+group by a, r
+having (r).d = 10;
+PLAN VARCHAR NOT NULL
+!type
+!set hep-rules original
+
 # End hep.iq
diff --git a/druid/src/test/java/org/apache/calcite/test/DruidAdapter2IT.java 
b/druid/src/test/java/org/apache/calcite/test/DruidAdapter2IT.java
index eec575e331..e12069cdca 100644
--- a/druid/src/test/java/org/apache/calcite/test/DruidAdapter2IT.java
+++ b/druid/src/test/java/org/apache/calcite/test/DruidAdapter2IT.java
@@ -3663,8 +3663,8 @@ private void testCountWithApproxDistinct(boolean approx, 
String sql,
     CalciteAssert.AssertQuery q = sql(sql)
         .explainContains("PLAN=EnumerableInterpreter\n"
             + "  DruidQuery(table=[[foodmart, foodmart]], 
intervals=[[1900-01-09T00:00:00.000Z/"
-            + "2992-01-10T00:00:00.000Z]], filter=[>($1, '10')], 
projects=[[$1, $90]], groups=[{0}],"
-            + " aggs=[[SUM($1)]], filter=[>($1, 220.0E0)], sort0=[0], 
dir0=[ASC], fetch=[2])\n")
+            + "2992-01-10T00:00:00.000Z]], filter=[>($1, '10')], groups=[{1}],"
+            + " aggs=[[SUM($90)]], filter=[>($1, 220.0E0)], sort0=[0], 
dir0=[ASC], fetch=[2])\n")
         .queryContains(
             new 
DruidChecker("{'queryType':'groupBy','dataSource':'foodmart','granularity':'all'"));
     q.returnsOrdered("P=100; S=343.2", "P=1000; S=532.62");
diff --git a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java 
b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
index 87f2c65f4c..501063ee6b 100644
--- a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
+++ b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
@@ -4377,8 +4377,8 @@ private void testCountWithApproxDistinct(boolean approx, 
String sql, String expe
     CalciteAssert.AssertQuery q = sql(sql, FOODMART)
         .explainContains("PLAN=EnumerableInterpreter\n"
             + "  DruidQuery(table=[[foodmart, foodmart]], 
intervals=[[1900-01-09T00:00:00.000Z/"
-            + "2992-01-10T00:00:00.000Z]], filter=[>($1, '10')], 
projects=[[$1, $90]], groups=[{0}],"
-            + " aggs=[[SUM($1)]], filter=[>($1, 220.0E0)], sort0=[0], 
dir0=[ASC], fetch=[2])\n")
+            + "2992-01-10T00:00:00.000Z]], filter=[>($1, '10')], groups=[{1}],"
+            + " aggs=[[SUM($90)]], filter=[>($1, 220.0E0)], sort0=[0], 
dir0=[ASC], fetch=[2])\n")
         .queryContains(
             new 
DruidChecker("{'queryType':'groupBy','dataSource':'foodmart','granularity':'all'"));
     q.returnsOrdered("P=100; S=343.2", "P=1000; S=532.62");

Reply via email to