You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@calcite.apache.org by "Abhishek Dasgupta (Jira)" <ji...@apache.org> on 2022/04/01 09:27:00 UTC
[jira] [Commented] (CALCITE-4401) SqlJoin toString throws RuntimeException
[ https://issues.apache.org/jira/browse/CALCITE-4401?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17515823#comment-17515823 ]
Abhishek Dasgupta commented on CALCITE-4401:
--------------------------------------------
Going off on a tangent, I wanted to discuss the review that I was given on the PR before commiting. Kindly see it if you haven't already.
According to me, here is the logic of how to extend fixture:
{code:java}
/**
* Method to check a subtree of SqlNode tree
* */
SqlPrettyWriterFixture check(final SqlNode node) {
diffRepos().assertEquals("formatted", this.formatted, node.toString());
return this;
} {code}
I took reference from SqlPrettyWriterFixture#check. There are basically 4 parts of code present in it:
# Create a writer from config.
# Parse the sql
# format the sql using writer.format() and assert on the expected string in SqlPrettyWriterTest.xml
# reparse the toString from writer.format() and now assert on the structural equivalence b/w formatted SqlNode and re-parsed SqlNode.
I tried to code according to these 4 parts only but they were not working with the current use case. Here are the reasons:
# No parsing of sql is required since I want to check a particular subtree i.e. SqlJoin in the complete tree. Hence I exactly need to know beforehand what I want to check. Hence the subtree is passed as an argument.
# writer.format() will result in a runtime exception since it will directly call `node.unparse` on SqlJoin without wrapping into SqlSelect. Hence I removed the "formatting" part as well.
# reparse of node.toString() will result in a SqlSelect instead of SqlJoin. Hence assertion on structural equivalence will fail.
The test case will like so :
{code:java}
@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 SqlNode node = fixture().parseQuery(sql);
final SqlSelect select = (SqlSelect) node;
fixture()
.check(select.getFrom());
} {code}
Please let me know your thoughts.
> SqlJoin toString throws RuntimeException
> ----------------------------------------
>
> Key: CALCITE-4401
> URL: https://issues.apache.org/jira/browse/CALCITE-4401
> Project: Calcite
> Issue Type: Bug
> Components: core
> Affects Versions: 1.25.0, 1.26.0
> Reporter: Dominik Labuda
> Assignee: Abhishek Dasgupta
> Priority: Minor
> Labels: pull-request-available
> Fix For: 1.31.0
>
> Time Spent: 1h 10m
> Remaining Estimate: 0h
>
> Hi,
> In our project we use Kotlin along with [Strikt assertion library|https://strikt.io/] in tests. The thing is that Strikt calls `.toString()` method on failing asserted objects to provide users with a nicely formatted output.
> Lets say the test looks like this:
> {code:java}
> @Test
> fun `test correct type of JOIN in the root of generated SQL without neighboring JOINs`() {
> // Generates SqlSelect that fails one of the conditions below
> val rootSelect: SqlSelect = generateRootSql()
>
> expectThat(rootSelect.from) {
> // Passes - from is a SqlJoin
> val join = isA<SqlJoin>()
> // Passes - joinType is FULL
> join.get { joinType }.isEqualTo(JoinType.FULL)
> // Fails - left is a SqlJoin, calls .toString() on rootSelect.from to provide output info
> join.get { left }.isNotA<SqlJoin>()
> join.get { right }.isNotA<SqlJoin>()
> }
> }
> {code}
> This can be inherently reduced to this example:
> {code:java}
> fun main() {
> val frameworkConfig = initSchema()
> val relBuilder: RelBuilder = RelBuilder.create(frameworkConfig)
> val rootRelationalNode = relBuilder
> .scan("tpch", "out_tpch_vw__customer")
> .project(
> relBuilder.field("c_custkey"),
> relBuilder.field("region_name")
> )
> .scan("tpch", "out_tpch_vw__orders")
> .project(
> relBuilder.field("o_custkey"),
> relBuilder.field("o_totalprice")
> )
> .join(
> JoinRelType.INNER,
> relBuilder.call(
> SqlStdOperatorTable.EQUALS,
> relBuilder.field(2, 0, "c_custkey"),
> relBuilder.field(2, 1, "o_custkey")
> )
> )
> .build()
> val sqlNode = RelToSqlConverter(PostgresqlSqlDialect.DEFAULT)
> .visitRoot(rootRelationalNode)
> .asStatement()
> println("SQL:")
> println(sqlNode)
> println()
> println("sqlNode root is SqlSelect: ${sqlNode is SqlSelect}")
> // Treat sqlNode as SqlSelect
> sqlNode as SqlSelect
> println("sqlNode.from field is a SqlJoin: ${sqlNode.from is SqlJoin}")
> println("Printing out the SqlJoin: ${sqlNode.from}")
> }
> {code}
> Which results in:
> {code:java}
> SQL:
> SELECT *
> 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`
> sqlNode root is SqlSelect: true
> sqlNode.from field is a SqlJoin: true
> Exception in thread "main" java.lang.RuntimeException: No list started
> at org.apache.calcite.sql.pretty.SqlPrettyWriter.sep(SqlPrettyWriter.java:1079)
> at org.apache.calcite.sql.pretty.SqlPrettyWriter.sep(SqlPrettyWriter.java:1074)
> at org.apache.calcite.sql.SqlJoin$SqlJoinOperator.unparse(SqlJoin.java:214)
> at org.apache.calcite.sql.SqlDialect.unparseCall(SqlDialect.java:453)
> at org.apache.calcite.sql.SqlCall.unparse(SqlCall.java:104)
> at org.apache.calcite.sql.SqlNode.toSqlString(SqlNode.java:154)
> at org.apache.calcite.sql.SqlNode.toString(SqlNode.java:129)
> at java.base/java.lang.String.valueOf(String.java:2951)
> at java.base/java.lang.StringBuilder.append(StringBuilder.java:168)
> ...{code}
>
--
This message was sent by Atlassian Jira
(v8.20.1#820001)