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()

Reply via email to