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

mbudiu 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 ed6c33eb1d [CALCITE-6605] Lattice SQL supports complex column 
expressions
ed6c33eb1d is described below

commit ed6c33eb1d27882b26fc16b995dde78de1709aff
Author: YiwenWu <[email protected]>
AuthorDate: Mon Sep 30 17:46:29 2024 +0800

    [CALCITE-6605] Lattice SQL supports complex column expressions
---
 .../org/apache/calcite/materialize/Lattice.java    | 23 +++++-
 .../calcite/materialize/LatticeSuggesterTest.java  | 95 ++++++++++++++++++++++
 2 files changed, 115 insertions(+), 3 deletions(-)

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 2f9b1c6eff..7204073150 100644
--- a/core/src/main/java/org/apache/calcite/materialize/Lattice.java
+++ b/core/src/main/java/org/apache/calcite/materialize/Lattice.java
@@ -39,6 +39,7 @@ import org.apache.calcite.schema.impl.MaterializedViewTable;
 import org.apache.calcite.schema.impl.StarTable;
 import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlDialect;
+import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlJoin;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlNode;
@@ -88,6 +89,7 @@ import java.util.stream.Collectors;
 import static com.google.common.base.Preconditions.checkArgument;
 
 import static org.apache.calcite.linq4j.Nullness.castNonNull;
+import static org.apache.calcite.rel.rel2sql.SqlImplementor.POS;
 
 import static java.util.Objects.requireNonNull;
 
@@ -289,9 +291,7 @@ public class Lattice {
     final StringBuilder groupBuf = new StringBuilder("\nGROUP BY ");
     int k = 0;
     final Set<String> columnNames = new HashSet<>();
-    final SqlWriter w = createSqlWriter(dialect, buf, f -> {
-      throw new UnsupportedOperationException();
-    });
+    final SqlWriter w = createSqlWriter(dialect, buf, resolveField(dialect));
     if (groupSet != null) {
       for (int i : groupSet) {
         if (k++ > 0) {
@@ -377,6 +377,23 @@ public class Lattice {
     return buf.toString();
   }
 
+  /** Resolves a field index to a corresponding SqlNode based on the column 
type. */
+  private IntFunction<SqlNode> resolveField(SqlDialect dialect) {
+    final IntFunction<SqlNode>[] fieldFuncRef = new IntFunction[1];
+    fieldFuncRef[0] = f -> {
+      Column column = columns.get(f);
+      if (column instanceof BaseColumn) {
+        return new SqlIdentifier(ImmutableList.of(((BaseColumn) 
column).column), POS);
+      }
+      if (column instanceof DerivedColumn) {
+        return new SqlImplementor.SimpleContext(dialect, fieldFuncRef[0])
+            .toSql(null, ((DerivedColumn) column).e);
+      }
+      throw new UnsupportedOperationException();
+    };
+    return fieldFuncRef[0];
+  }
+
   /** Creates a context to which SQL can be generated. */
   public SqlWriter createSqlWriter(SqlDialect dialect, StringBuilder buf,
       IntFunction<SqlNode> field) {
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 2154f1aafa..4203a1b7fe 100644
--- 
a/core/src/test/java/org/apache/calcite/materialize/LatticeSuggesterTest.java
+++ 
b/core/src/test/java/org/apache/calcite/materialize/LatticeSuggesterTest.java
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 package org.apache.calcite.materialize;
+
+import org.apache.calcite.materialize.Lattice.Measure;
 import org.apache.calcite.prepare.PlannerImpl;
 import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.schema.SchemaPlus;
@@ -35,6 +37,8 @@ import org.apache.calcite.tools.Frameworks;
 import org.apache.calcite.tools.Planner;
 import org.apache.calcite.tools.RelConversionException;
 import org.apache.calcite.tools.ValidationException;
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.ImmutableBitSet.Builder;
 import org.apache.calcite.util.Util;
 
 import com.google.common.collect.ImmutableList;
@@ -752,6 +756,97 @@ class LatticeSuggesterTest {
     checkDerivedColumn(lattice, tables, derivedColumns, 3, "n11", false);
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-6605";>[CALCITE-6605]
+   * Lattice SQL supports complex column expressions </a>. */
+  @Test void testExpressionLatticeSql() throws Exception {
+    final Tester t = new Tester().foodmart().withEvolve(true);
+    final String q0 = "select\n"
+        + "  \"num_children_at_home\" + 12 as \"n12\",\n"
+        + "  sum(\"num_children_at_home\") as \"n10\",\n"
+        + "  count(*) as c\n"
+        + "from \"customer\"\n"
+        + "group by \"num_children_at_home\" + 12";
+    t.addQuery(q0);
+    assertThat(t.s.latticeMap, aMapWithSize(1));
+    final Lattice lattice = Iterables.getOnlyElement(t.s.latticeMap.values());
+    final String l0 = "customer:[COUNT(), SUM(customer.num_children_at_home)]";
+    assertThat(Iterables.getOnlyElement(t.s.latticeMap.keySet()), is(l0));
+    ImmutableList<Measure> measures = lattice.defaultMeasures;
+    assert measures.size() == 2;
+    Builder groupSetBuilder = ImmutableBitSet.builder();
+    measures.forEach(measure -> groupSetBuilder.addAll(measure.argBitSet()));
+    ImmutableBitSet groupSet = groupSetBuilder.build();
+    String sql = "SELECT \"customer\".\"num_children_at_home\", COUNT(*) AS 
\"m0\", "
+        + "SUM(\"customer\".\"num_children_at_home\") AS \"m1\"\n"
+        + "FROM \"foodmart\".\"customer\" AS \"customer\"\n"
+        + "GROUP BY \"customer\".\"num_children_at_home\"";
+    assertThat(lattice.sql(groupSet, true, measures),
+        is(sql));
+  }
+
+  /** Test case for measure field involving a complex column operation,
+   * for example sum("num_children_at_home" + 10). */
+  @Test void testExpressionLatticeSql2() throws Exception {
+    final Tester t = new Tester().foodmart().withEvolve(true);
+    final String q0 = "select\n"
+        + "  \"num_children_at_home\" + 12 as \"n12\",\n"
+        + "  sum(\"num_children_at_home\" + 10) as \"n10\",\n"
+        + "  sum(\"num_children_at_home\" + 11) as \"n11\",\n"
+        + "  count(*) as c\n"
+        + "from \"customer\"\n"
+        + "group by \"num_children_at_home\" + 12";
+    t.addQuery(q0);
+    assertThat(t.s.latticeMap, aMapWithSize(1));
+    final Lattice lattice = Iterables.getOnlyElement(t.s.latticeMap.values());
+    final String l0 = "customer:[COUNT(), SUM(n10), SUM(n11)]";
+    assertThat(Iterables.getOnlyElement(t.s.latticeMap.keySet()), is(l0));
+    ImmutableList<Measure> measures = lattice.defaultMeasures;
+    assert measures.size() == 3;
+    Builder groupSetBuilder = ImmutableBitSet.builder();
+    measures.forEach(measure -> groupSetBuilder.addAll(measure.argBitSet()));
+    ImmutableBitSet groupSet = groupSetBuilder.build();
+    String sql = "SELECT \"num_children_at_home\" + 10 AS \"n10\", "
+        + "\"num_children_at_home\" + 11 AS \"n11\", COUNT(*) AS \"m0\", "
+        + "SUM(\"num_children_at_home\" + 10) AS \"m1\", "
+        + "SUM(\"num_children_at_home\" + 11) AS \"m2\"\n"
+        + "FROM \"foodmart\".\"customer\" AS \"customer\"\n"
+        + "GROUP BY \"num_children_at_home\" + 10, \"num_children_at_home\" + 
11";
+    assertThat(lattice.sql(groupSet, true, measures),
+        is(sql));
+  }
+
+  /** Test case for measure field involving a complex column operation with 
functions,
+   * for example sum(cast("num_children_at_home" as double) + 11). */
+  @Test void testExpressionLatticeSql3() throws Exception {
+    final Tester t = new Tester().foodmart().withEvolve(true);
+    final String q0 = "select\n"
+        + "  \"num_children_at_home\" + 12 as \"n12\",\n"
+        + "  sum(\"num_children_at_home\" + 10) as \"n10\",\n"
+        + "  sum(cast(\"num_children_at_home\" as double) + 11) as \"n11\",\n"
+        + "  count(*) as c\n"
+        + "from \"customer\"\n"
+        + "group by \"num_children_at_home\" + 12";
+    t.addQuery(q0);
+    assertThat(t.s.latticeMap, aMapWithSize(1));
+    final Lattice lattice = Iterables.getOnlyElement(t.s.latticeMap.values());
+    final String l0 = "customer:[COUNT(), SUM(n10), SUM(n11)]";
+    assertThat(Iterables.getOnlyElement(t.s.latticeMap.keySet()), is(l0));
+    ImmutableList<Measure> measures = lattice.defaultMeasures;
+    assert measures.size() == 3;
+    Builder groupSetBuilder = ImmutableBitSet.builder();
+    measures.forEach(measure -> groupSetBuilder.addAll(measure.argBitSet()));
+    ImmutableBitSet groupSet = groupSetBuilder.build();
+    String sql = "SELECT \"num_children_at_home\" + 10 AS \"n10\", "
+        + "CAST(\"num_children_at_home\" AS DOUBLE) + 11 AS \"n11\", "
+        + "COUNT(*) AS \"m0\", SUM(\"num_children_at_home\" + 10) AS \"m1\", "
+        + "SUM(CAST(\"num_children_at_home\" AS DOUBLE) + 11) AS \"m2\"\n"
+        + "FROM \"foodmart\".\"customer\" AS \"customer\"\n"
+        + "GROUP BY \"num_children_at_home\" + 10, 
CAST(\"num_children_at_home\" AS DOUBLE) + 11";
+    assertThat(lattice.sql(groupSet, true, measures),
+        is(sql));
+  }
+
   private void checkFoodmartSimpleJoin(CalciteAssert.SchemaSpec schemaSpec)
       throws Exception {
     final FrameworkConfig config = Frameworks.newConfigBuilder()

Reply via email to