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 28231eaf52 [CALCITE-7558] Lattice.Measure.compareTo() collapses
distinct aggregates that share the same name
28231eaf52 is described below
commit 28231eaf52577c75f14e14f82354164c622378de
Author: 1fanwang <[email protected]>
AuthorDate: Tue Aug 25 03:12:58 2026 -0400
[CALCITE-7558] Lattice.Measure.compareTo() collapses distinct aggregates
that share the same name
Two unequal measures can share their argument list, aggregate name, and
distinct flag. The builder stores measures in a TreeSet, so the natural-order
tie silently drops one aggregate definition.
Signed-off-by: 1fanwang <[email protected]>
---
.../org/apache/calcite/materialize/Lattice.java | 11 +++++++
.../calcite/materialize/LatticeSuggesterTest.java | 38 ++++++++++++++++++++++
2 files changed, 49 insertions(+)
diff --git a/core/src/main/java/org/apache/calcite/materialize/Lattice.java
b/core/src/main/java/org/apache/calcite/materialize/Lattice.java
index 7204073150..7ec17ea52f 100644
--- a/core/src/main/java/org/apache/calcite/materialize/Lattice.java
+++ b/core/src/main/java/org/apache/calcite/materialize/Lattice.java
@@ -43,6 +43,7 @@
import org.apache.calcite.sql.SqlJoin;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.SqlSelect;
import org.apache.calcite.sql.SqlUtil;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
@@ -72,6 +73,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Comparator;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
@@ -577,6 +579,12 @@ private Vertex(LatticeTable table, @Nullable String alias)
{
* COUNT(DISTINCT customer.id).
*/
public static class Measure implements Comparable<Measure> {
+ /** Distinguishes aggregate functions that have the same name, using the
+ * other properties that {@link SqlOperator#equals(Object)} compares. */
+ private static final Comparator<SqlOperator> AGG_TIE_BREAKER =
+ Comparator.comparing((SqlOperator op) -> op.getKind().name())
+ .thenComparing((SqlOperator op) -> op.getClass().getName());
+
public final SqlAggFunction agg;
public final boolean distinct;
public final @Nullable String name;
@@ -615,6 +623,9 @@ public Measure(SqlAggFunction agg, boolean distinct,
@Nullable String name,
c = agg.getName().compareTo(measure.agg.getName());
if (c == 0) {
c = Boolean.compare(distinct, measure.distinct);
+ if (c == 0) {
+ c = AGG_TIE_BREAKER.compare(agg, measure.agg);
+ }
}
}
return c;
diff --git
a/core/src/test/java/org/apache/calcite/materialize/LatticeSuggesterTest.java
b/core/src/test/java/org/apache/calcite/materialize/LatticeSuggesterTest.java
index 8cefa4c205..3147d17402 100644
---
a/core/src/test/java/org/apache/calcite/materialize/LatticeSuggesterTest.java
+++
b/core/src/test/java/org/apache/calcite/materialize/LatticeSuggesterTest.java
@@ -20,13 +20,19 @@
import org.apache.calcite.prepare.PlannerImpl;
import org.apache.calcite.rel.RelRoot;
import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.sql.SqlAggFunction;
import org.apache.calcite.sql.SqlDialect;
+import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlOperatorTable;
+import org.apache.calcite.sql.fun.SqlBasicAggFunction;
import org.apache.calcite.sql.fun.SqlLibrary;
import org.apache.calcite.sql.fun.SqlLibraryOperatorTableFactory;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.calcite.sql.parser.SqlParser;
+import org.apache.calcite.sql.type.OperandTypes;
+import org.apache.calcite.sql.type.ReturnTypes;
import org.apache.calcite.sql2rel.SqlToRelConverter;
import org.apache.calcite.statistic.MapSqlStatisticProvider;
import org.apache.calcite.statistic.QuerySqlStatisticProvider;
@@ -56,6 +62,7 @@
import java.util.Comparator;
import java.util.EnumSet;
import java.util.List;
+import java.util.TreeSet;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
@@ -69,6 +76,7 @@
import static org.hamcrest.Matchers.aMapWithSize;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.hasToString;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
/**
* Unit tests for {@link LatticeSuggester}.
@@ -848,6 +856,36 @@ private void checkDerivedColumn(Lattice lattice,
List<String> tables,
is(sql));
}
+ /** Test case for
+ * <a
href="https://issues.apache.org/jira/browse/CALCITE-7558">[CALCITE-7558]
+ * Lattice.Measure.compareTo() collapses distinct aggregates that share the
+ * same name</a>. */
+ @Test void testMeasureNaturalOrderingKeepsDistinctAggregatorsWithSameName() {
+ final SqlAggFunction builtInSum = SqlStdOperatorTable.SUM;
+ final SqlAggFunction sameKindSum =
+ SqlBasicAggFunction.create("SUM", SqlKind.SUM,
+ ReturnTypes.ARG0_NULLABLE, OperandTypes.NUMERIC);
+ final SqlAggFunction otherKindSum =
+ SqlBasicAggFunction.create("SUM", SqlKind.OTHER_FUNCTION,
+ ReturnTypes.ARG0_NULLABLE, OperandTypes.NUMERIC);
+
+ final Measure builtInMeasure =
+ new Measure(builtInSum, false, "SUM", ImmutableList.of());
+ final Measure sameKindMeasure =
+ new Measure(sameKindSum, false, "SUM", ImmutableList.of());
+ final Measure otherKindMeasure =
+ new Measure(otherKindSum, false, "SUM", ImmutableList.of());
+ assertNotEquals(builtInMeasure, sameKindMeasure);
+ assertNotEquals(builtInMeasure, otherKindMeasure);
+ assertNotEquals(sameKindMeasure, otherKindMeasure);
+
+ final TreeSet<Measure> measures = new TreeSet<>();
+ measures.add(builtInMeasure);
+ measures.add(sameKindMeasure);
+ measures.add(otherKindMeasure);
+ assertThat(measures, hasSize(3));
+ }
+
private void checkFoodmartSimpleJoin(CalciteAssert.SchemaSpec schemaSpec)
throws Exception {
final FrameworkConfig config = Frameworks.newConfigBuilder()