[FLINK-39799][table] Preserve user-typed query text for materialized table and view definitions#28277
[FLINK-39799][table] Preserve user-typed query text for materialized table and view definitions#28277raminqaf wants to merge 6 commits into
Conversation
…table and view definitions
| TableChange.add(Column.physical("f", DataTypes.VARCHAR(Integer.MAX_VALUE))), | ||
| TableChange.modifyDefinitionQuery( | ||
| "SELECT `a`, `b`, `c`, `d`, `d` AS `e`, CAST('123' AS STRING) AS `f`\nFROM `t1`", | ||
| "SELECT a, b, c, d, d as e, cast('123' as string) as f FROM t1", |
There was a problem hiding this comment.
can we have tests for queries containing different comments?
There was a problem hiding this comment.
Thanks for pointing this out. I have adde a parasitized test with for comments at different locations of the asQuery
|
|
||
| public String getDefinitionQuery() { | ||
| return definitionQuery; | ||
| public String getExpandedQuery() { |
There was a problem hiding this comment.
this is a @PublicEvolving interface, such change usually requires a FLIP
There was a problem hiding this comment.
IMO we should tolerate these type of changes after a minor release. For now reverted it get things unblocked.
There was a problem hiding this comment.
there is a doc telling about this
in case we revert it, then should revert everywhere the change definitionQuery -> expandedQuery
otherwise in some places it is expanded, in other it is definition
| } | ||
|
|
||
| @Override | ||
| public Optional<String> toRawSqlString(SqlNode node) { |
There was a problem hiding this comment.
is the implementation consistent?
what happen if
final String outerStatement = "CREATE TABLE x AS SELECT a FROM t1";
final FlinkPlannerImpl planner = getPlannerBySqlDialect(SqlDialect.DEFAULT);
final CalciteParser parser = getParserBySqlDialect(SqlDialect.DEFAULT);
final SqlNode innerAsQuery =
((SqlCreateTableAs) parser.parse(outerStatement)).getAsQuery();
new SqlNodeConvertContext(planner, catalogManager, outerStatement)
.toRawSqlString(innerAsQuery));
// AND
new SqlNodeConvertContext(planner, catalogManager, "SELECT a FROM t1")
.toRawSqlString(innerAsQuery));will they have same result?
There was a problem hiding this comment.
No, and that's expected. I ran your exact snippet:
outer statement "CREATE TABLE x AS SELECT a FROM t1"
innerAsQuery.getParserPosition() -> line 1, column 19
new SqlNodeConvertContext(planner, catalogManager, outerStatement).toRawSqlString(innerAsQuery)
-> Optional[SELECT a FROM t1]
new SqlNodeConvertContext(planner, catalogManager, "SELECT a FROM t1").toRawSqlString(innerAsQuery)
-> Optional.empty
the method has a precondition: the statement passed to the context must be the same text the node was parsed from. When that holds, the slice is correct. It fails safe. It never returns a wrong substring and never throws.
I will update the javaDocs with better explanation of this case.
|
|
||
| return (PlannerQueryOperation) | ||
| SqlNodeToOperationConversion.convert(flinkPlanner, catalogManager, newSelect) | ||
| SqlNodeToOperationConversion.convert(flinkPlanner, catalogManager, newSelect, null) |
There was a problem hiding this comment.
why is it null here?
could it be potentially in the future same issue as with CTAS/RTAS?
There was a problem hiding this comment.
The conversion path here never calls toRawString here. So it is safe. Even if it gets fired the newSelect is synthesized by rewriteCall, so the slicing would produce wrong values here. So the correct behavior would be to pass null to get an optional#empty
| SqlNode asQuerySqlNode = sqlCreateTableAs.getAsQuery(); | ||
| SqlNode validatedAsQuery = flinkPlanner.validate(asQuerySqlNode); | ||
|
|
||
| final String rawSqlString = |
There was a problem hiding this comment.
is there a reason to have one var final while others are not?
can we make all final or all not final?
There was a problem hiding this comment.
Made everything final in this method
What is the purpose of the change
CREATE/ALTER MATERIALIZED TABLE … AS …andCREATE VIEW … AS …currently persistoriginalQueryby re-rendering the parsedSqlNodeviaSqlNode#toSqlString(). This normalizes identifier casing, expands type aliases (int→INTEGER), reflows whitespace, and rewrites quoting, soSHOW CREATE MATERIALIZED TABLE/SHOW CREATE VIEWno longer reflect what the user typed.This PR makes
originalQuerythe verbatim substring of the user's input statement, sliced viaSqlParserPosof the AS-query subtree.expandedQuerycontinues to hold the planner-normalized form.Example
Input:
Before:
after:
Brief Changelog
ParserImplthroughSqlNodeToOperationConversion.convert(...)into SqlNodeConvertContext.ConvertContext#toRawSqlString(SqlNode) returning the substring of the original statement matchingSqlParserPos. Counterpart to existing toQuotedSqlString(SqlNode). Falls back totoQuotedSqlStringif raw statement text is unavailable.AbstractCreateMaterializedTableConverter#getDerivedOriginalQuery,SqlAlterMaterializedTableAsQueryConverter, andSqlNodeConvertUtils#toCatalogView(coversCREATE VIEWandALTER VIEW … AS) to the new method.SqlNodeToOperationConversion.convert(...)signature as an overload that delegates with null raw text for backward compatibility.Verifying this Change
SqlNodeConvertContextTest fortoRawSqlStringcovering nested AS-query nodes, comments inside the query, and statements spanning multiple lines.originalQueryequals the input substring across mixed casing, type aliases (int/varchar), whitespace, and quoting styles. ExistingexpandedQueryassertions retained unchanged.Does this pull request potentially affect one of the following parts:
@Public(Evolving): no (signature change on SqlNodeToOperationConversion is@Internal; backward-compatible overload kept)Documentation
Was generative AI tooling used to co-author this PR?