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

jhyde pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/master by this push:
     new 10a3b1a3f [CALCITE-4401] SqlJoin.toString throws RuntimeException, "No 
list started"
10a3b1a3f is described below

commit 10a3b1a3f5399851bc31ff665a999411edffbcc8
Author: onTheQT <[email protected]>
AuthorDate: Tue Mar 29 22:32:18 2022 +0530

    [CALCITE-4401] SqlJoin.toString throws RuntimeException, "No list started"
    
    To resolve the RuntimeException seen in SqlJoin#toString, add
    a "SELECT *" wrap over SqlJoin in SqlJoin#toSqlString. This
    prevents SqlJoin#unparse method from calling
    SqlPrettyWriter#sep with a null frame, and is a less fragile
    fix than to mutate internal frame state.
    
    Extend SqlPrettyWriterFixture with a method
    `checkTransformedNode(UnaryOperator<SqlNode> transform)`
    that does do the same as `check()` but applies a transform
    function that maps from the root to another node in the tree.
    
    Close apache/calcite#2757
---
 .../main/java/org/apache/calcite/sql/SqlJoin.java  | 10 +++++++
 .../calcite/sql/test/SqlPrettyWriterFixture.java   | 20 +++++++++++--
 .../calcite/sql/test/SqlPrettyWriterTest.java      | 34 ++++++++++++++++++++++
 .../calcite/sql/test/SqlPrettyWriterTest.xml       |  9 ++++++
 4 files changed, 70 insertions(+), 3 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/sql/SqlJoin.java 
b/core/src/main/java/org/apache/calcite/sql/SqlJoin.java
index 4baf3fc72..a609cb9d4 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlJoin.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlJoin.java
@@ -18,6 +18,7 @@ package org.apache.calcite.sql;
 
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql.util.SqlString;
 import org.apache.calcite.util.ImmutableNullableList;
 import org.apache.calcite.util.Util;
 
@@ -26,6 +27,7 @@ import com.google.common.base.Preconditions;
 import org.checkerframework.checker.nullness.qual.Nullable;
 
 import java.util.List;
+import java.util.function.UnaryOperator;
 
 import static java.util.Objects.requireNonNull;
 
@@ -259,4 +261,12 @@ public class SqlJoin extends SqlCall {
       }
     }
   }
+
+  @Override public SqlString toSqlString(UnaryOperator<SqlWriterConfig> 
transform) {
+    SqlNode selectWrapper =
+        new SqlSelect(SqlParserPos.ZERO, SqlNodeList.EMPTY,
+            SqlNodeList.SINGLETON_STAR, this, null, null, null,
+            SqlNodeList.EMPTY, null, null, null, SqlNodeList.EMPTY);
+    return selectWrapper.toSqlString(transform);
+  }
 }
diff --git 
a/core/src/test/java/org/apache/calcite/sql/test/SqlPrettyWriterFixture.java 
b/core/src/test/java/org/apache/calcite/sql/test/SqlPrettyWriterFixture.java
index 537a90f38..d92eef1ba 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlPrettyWriterFixture.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlPrettyWriterFixture.java
@@ -138,17 +138,31 @@ class SqlPrettyWriterFixture {
   }
 
   SqlPrettyWriterFixture check() {
+    return checkTransformedNode(n -> n);
+  }
+
+  /** As {@link #check()}, but operates on a transformed node
+   * (say the 2nd child of the 1st child) rather than the root. */
+  SqlPrettyWriterFixture checkTransformedNode(
+      UnaryOperator<SqlNode> nodeTransformer) {
+    return check_(nodeTransformer);
+  }
+
+  private SqlPrettyWriterFixture check_(UnaryOperator<SqlNode> 
nodeTransformer) {
     final SqlWriterConfig config =
         transform.apply(SqlPrettyWriter.config()
             .withDialect(AnsiSqlDialect.DEFAULT));
     final SqlPrettyWriter prettyWriter = new SqlPrettyWriter(config);
     final SqlNode node;
+    final SqlNode node1;
     if (expression) {
       final SqlCall valuesCall = (SqlCall) parseQuery("VALUES (" + sql + ")");
       final SqlCall rowCall = valuesCall.operand(0);
       node = rowCall.operand(0);
+      node1 = node;
     } else {
       node = parseQuery(sql);
+      node1 = nodeTransformer.apply(node);
     }
 
     // Describe settings
@@ -175,11 +189,11 @@ class SqlPrettyWriterFixture {
       final SqlCall rowCall = valuesCall.operand(0);
       node2 = rowCall.operand(0);
     } else {
-      node2 = parseQuery(actual2);
+      SqlNode node2a = parseQuery(actual2);
+      node2 = nodeTransformer.apply(node2a);
     }
-    assertTrue(node.equalsDeep(node2, Litmus.THROW));
+    assertTrue(node1.equalsDeep(node2, Litmus.THROW));
 
     return this;
   }
-
 }
diff --git 
a/core/src/test/java/org/apache/calcite/sql/test/SqlPrettyWriterTest.java 
b/core/src/test/java/org/apache/calcite/sql/test/SqlPrettyWriterTest.java
index fe2ae3a68..4891edd70 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlPrettyWriterTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlPrettyWriterTest.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.sql.test;
 
 import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlSelect;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.SqlWriterConfig;
 import org.apache.calcite.sql.parser.SqlParseException;
@@ -27,6 +28,12 @@ import org.apache.calcite.test.DiffRepository;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
+import static org.apache.calcite.test.Matchers.isLinux;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.notNullValue;
+
 /**
  * Unit test for {@link SqlPrettyWriter}.
  *
@@ -369,6 +376,33 @@ class SqlPrettyWriterTest {
         .check();
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-4401";>[CALCITE-4401]
+   * SqlJoin toString throws RuntimeException</a>. */
+  @Test void testJoinClauseToString() {
+    final String sql = "SELECT t.region_name, t0.o_totalprice\n"
+        + "FROM (SELECT c_custkey, region_name\n"
+        + "FROM tpch.out_tpch_vw__customer) AS t\n"
+        + "INNER JOIN (SELECT o_custkey, o_totalprice\n"
+        + "FROM tpch.out_tpch_vw__orders) AS t0 ON t.c_custkey = t0.o_custkey";
+
+    final String expectedJoinString = "SELECT *\n"
+        + "FROM (SELECT `C_CUSTKEY`, `REGION_NAME`\n"
+        + "FROM `TPCH`.`OUT_TPCH_VW__CUSTOMER`) AS `T`\n"
+        + "INNER JOIN (SELECT `O_CUSTKEY`, `O_TOTALPRICE`\n"
+        + "FROM `TPCH`.`OUT_TPCH_VW__ORDERS`) AS `T0`"
+        + " ON `T`.`C_CUSTKEY` = `T0`.`O_CUSTKEY`";
+
+    sql(sql)
+        .checkTransformedNode(root -> {
+          assertThat(root, instanceOf(SqlSelect.class));
+          SqlNode from = ((SqlSelect) root).getFrom();
+          assertThat(from, notNullValue());
+          assertThat(from.toString(), isLinux(expectedJoinString));
+          return from;
+        });
+  }
+
   @Test void testWhereListItemsOnSeparateLinesOr() {
     final String sql = "select x"
         + " from y"
diff --git 
a/core/src/test/resources/org/apache/calcite/sql/test/SqlPrettyWriterTest.xml 
b/core/src/test/resources/org/apache/calcite/sql/test/SqlPrettyWriterTest.xml
index 713668b49..965712f04 100644
--- 
a/core/src/test/resources/org/apache/calcite/sql/test/SqlPrettyWriterTest.xml
+++ 
b/core/src/test/resources/org/apache/calcite/sql/test/SqlPrettyWriterTest.xml
@@ -225,6 +225,15 @@ FROM `X`
     INNER JOIN `Y` ON `X`.`K` = `Y`.`K`]]>
     </Resource>
   </TestCase>
+  <TestCase name="testJoinClauseToString">
+    <Resource name="formatted">
+      <![CDATA[SELECT `T`.`REGION_NAME`, `T0`.`O_TOTALPRICE`
+FROM (SELECT `C_CUSTKEY`, `REGION_NAME`
+        FROM `TPCH`.`OUT_TPCH_VW__CUSTOMER`) AS `T`
+    INNER JOIN (SELECT `O_CUSTKEY`, `O_TOTALPRICE`
+        FROM `TPCH`.`OUT_TPCH_VW__ORDERS`) AS `T0` ON `T`.`C_CUSTKEY` = 
`T0`.`O_CUSTKEY`]]>
+    </Resource>
+  </TestCase>
   <TestCase name="testJoinComma">
     <Resource name="formatted">
       <![CDATA[SELECT *

Reply via email to