[
https://issues.apache.org/jira/browse/CALCITE-4401?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17512750#comment-17512750
]
Abhishek Dasgupta edited comment on CALCITE-4401 at 3/26/22, 4:16 PM:
----------------------------------------------------------------------
I'm trying to solve this ticket. As [~julianhyde] wrote in the last comment on
CALCITE-3526, I've implemented this idea. I want to discuss it first before
raising a PR (Also I don't have access to create a PR)
The challenge is "SELECT *" wrapper is not needed for all types of Sqls like
UPDATE, DELETE etc.{} Hence in order to figure out when to *wrap a SqlNode
before calling unparse method or stripping the buffer in
SqlPrettryWriter#toString. I've introduced a new property in
SqlWriterConfig#needExtraSelectWrap which is a boolean.
After introducing the above property, the SqlPrettyWriter#toString will look
like:
{code:java}
@Override public String toString() {
return config.needExtraSelectWrap() ? stripSelectWrapper() : buf.toString();
}{code}
and SqlNode#toString method of will look like:
{code:java}
public SqlString toSqlString(UnaryOperator<SqlWriterConfig> transform) {
final SqlWriterConfig config = transform.apply(SqlPrettyWriter.config());
SqlPrettyWriter writer = new SqlPrettyWriter(config);
if (config.needExtraSelectWrap()) {
SqlNode selectWrapper = new SqlSelect(SqlParserPos.ZERO, SqlNodeList.EMPTY,
SqlNodeList.SINGLETON_STAR, this, null, null, null,
SqlNodeList.EMPTY, null, null, null, SqlNodeList.EMPTY);
selectWrapper.unparse(writer, 0, 0);
} else {
this.unparse(writer, 0, 0);
}
return writer.toSqlString();
}{code}
In order to set SqlWriterConfig#needExtraSelectWrap, I've introduced a static
method in SqlPrettyWriter (didn't know where to put it, maybe SqlUtils) called
SqlPrettyWriter#needSelectWrapper(SqlNode node)
{code:java}
public static boolean needSelectWrapper(SqlNode node) {
return node instanceof SqlSelect;
}{code}
I've introduced this property in SqlWriterConfig because otherwise every SQL
were wrapped in "SELECT *" and some SQL present in the buffer were wrong. Also
they all need different type of string manipulation during the phase of
stripping the buffer.
Let me know if you want further understanding. I can also raise a PR so that
anyone can take a quick glance but first I need access for that.
Thanks!
was (Author: abhishek.dasgupta):
I'm trying to solve this ticket. As [~julianhyde] wrote in the last comment on
CALCITE-3526, I've implemented this idea. I want to discuss it first before
raising a PR (Also I don't have access to create a PR)
The challenge is "SELECT *" ** wrapper is not needed for all types of Sqls like
UPDATE, DELETE etc.{} Hence in order to figure out when to *wrap a SqlNode
before calling unparse method* or *stripping the buffer in
SqlPrettryWriter#toString* . I've introduced a new property in
SqlWriterConfig#needExtraSelectWrap which is a boolean.
After introducing the above property, the SqlPrettyWriter#toString will look
like:
{code:java}
@Override public String toString() {
return config.needExtraSelectWrap() ? stripSelectWrapper() : buf.toString();
}{code}
and SqlNode#toString method of will look like:
{code:java}
public SqlString toSqlString(UnaryOperator<SqlWriterConfig> transform) {
final SqlWriterConfig config = transform.apply(SqlPrettyWriter.config());
SqlPrettyWriter writer = new SqlPrettyWriter(config);
if (config.needExtraSelectWrap()) {
SqlNode selectWrapper = new SqlSelect(SqlParserPos.ZERO, SqlNodeList.EMPTY,
SqlNodeList.SINGLETON_STAR, this, null, null, null,
SqlNodeList.EMPTY, null, null, null, SqlNodeList.EMPTY);
selectWrapper.unparse(writer, 0, 0);
} else {
this.unparse(writer, 0, 0);
}
return writer.toSqlString();
}{code}
In order to set SqlWriterConfig#needExtraSelectWrap, I've introduced a static
method in SqlPrettyWriter (didn't know where to put it, maybe SqlUtils) called
SqlPrettyWriter#needSelectWrapper(SqlNode node)
{code:java}
public static boolean needSelectWrapper(SqlNode node) {
return node instanceof SqlSelect;
}{code}
I've introduced this property in SqlWriterConfig because otherwise every SQL
were wrapped in "SELECT *" and some SQL present in the buffer were wrong. Also
they all need different type of string manipulation during the phase of
stripping the buffer.
Let me know if you want further understanding. I can also raise a PR so that
anyone can take a quick glance but first I need access for that.
Thanks!
> 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
> Priority: Minor
>
> 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)