From a27a8de278d06f0fa5875df4dc1bbbedc6a2213a Mon Sep 17 00:00:00 2001 From: Ruben Quesada Lopez Date: Tue, 16 Jul 2024 17:26:24 +0100 Subject: [PATCH] [CALCITE-6474] Aggregate with constant key can get a RowCount greater than its MaxRowCount --- .../calcite/rel/metadata/RelMdMaxRowCount.java | 2 +- .../calcite/rel/metadata/RelMdRowCount.java | 12 ++++++++++++ .../apache/calcite/test/RelMetadataTest.java | 17 +++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMaxRowCount.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMaxRowCount.java index 0d9a61ebe94..2858fd908be 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMaxRowCount.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMaxRowCount.java @@ -159,7 +159,7 @@ && allGroupKeysAreConstant(rel, predicateList)) { return rowCount * rel.getGroupSets().size(); } - private static boolean allGroupKeysAreConstant(Aggregate aggregate, + static boolean allGroupKeysAreConstant(Aggregate aggregate, RelOptPredicateList predicateList) { final RexBuilder rexBuilder = aggregate.getCluster().getRexBuilder(); for (int key : aggregate.getGroupSet()) { diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java index b7393823ba5..8da6caa8943 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java @@ -17,6 +17,7 @@ package org.apache.calcite.rel.metadata; import org.apache.calcite.adapter.enumerable.EnumerableLimit; +import org.apache.calcite.plan.RelOptPredicateList; import org.apache.calcite.plan.volcano.RelSubset; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.SingleRel; @@ -191,6 +192,17 @@ public Double getRowCount(Aggregate rel, RelMetadataQuery mq) { // Aggregate with no GROUP BY always returns 1 row (even on empty table). return 1D; } + + // Aggregate with constant GROUP BY always returns 1 row + if (rel.getGroupType() == Aggregate.Group.SIMPLE) { + final RelOptPredicateList predicateList = + mq.getPulledUpPredicates(rel.getInput()); + if (!RelOptPredicateList.isEmpty(predicateList) + && RelMdMaxRowCount.allGroupKeysAreConstant(rel, predicateList)) { + return 1D; + } + } + // rowCount is the cardinality of the group by columns Double distinctRowCount = mq.getDistinctRowCount(rel.getInput(), groupKey, null); diff --git a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java index d9733486bd6..5db8ec64a36 100644 --- a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java +++ b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java @@ -788,6 +788,23 @@ final RelMetadataFixture sql(String sql) { sql(sql).assertThatRowCount(is(1D), is(0D), is(1D)); } + /** Test case for + * [CALCITE-6474] + * Aggregate with constant key can get a RowCount greater than its MaxRowCount . */ + @Test void testRowCountAggregateConstantKeysOnBigInput() { + final String sql = "" + + "select distinct deptno from (" + + "select deptno from emp e1 union all " + + "select deptno from emp e2 union all " + + "select deptno from emp e3 union all " + + "select deptno from emp e4 union all " + + "select deptno from emp e5 union all " + + "select deptno from emp e6 union all " + + "select deptno from emp e7" + + ") where deptno=4"; + sql(sql).assertThatRowCount(is(1D), is(0D), is(1D)); + } + @Test void testRowCountFilterAggregateEmptyKey() { final String sql = "select count(*) from emp where 1 = 0"; sql(sql).assertThatRowCount(is(1D), is(1D), is(1D));