raminqaf commented on code in PR #28277:
URL: https://github.com/apache/flink/pull/28277#discussion_r3354420135


##########
flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/operations/converters/materializedtable/AbstractCreateMaterializedTableConverter.java:
##########
@@ -141,10 +142,17 @@ protected final RefreshMode 
getDerivedRefreshMode(LogicalRefreshMode logicalRefr
         return 
MaterializedTableUtils.fromLogicalRefreshModeToRefreshMode(logicalRefreshMode);
     }
 
+    /**
+     * Returns the user's original {@code AS} query text, sliced verbatim from 
the statement so
+     * formatting and identifier casing are preserved (e.g. {@code int} is not 
normalized to {@code
+     * INTEGER}). A comment placed between {@code AS} and the query is kept; 
the {@code AS} keyword
+     * itself is excluded.
+     */
     protected final String getDerivedOriginalQuery(
             T sqlCreateMaterializedTable, ConvertContext context) {
-        SqlNode selectQuery = sqlCreateMaterializedTable.getAsQuery();
-        return context.toQuotedSqlString(selectQuery);
+        return SqlNodeConvertUtils.rawAsQueryText(

Review Comment:
   Renamed to `originalAsQueryText`. I agree with you that the `As...` in the 
method name makes it harder to read. In order to keep it consistent with the 
other variable like the `asQuery`, I would keep the `As...` in the method name.



##########
flink-table/flink-sql-parser/src/main/codegen/includes/parserImpls.ftl:
##########
@@ -2062,24 +2063,27 @@ SqlCreate SqlCreateOrAlterMaterializedTable(Span s, 
boolean replace, boolean isT
             }
         )
     ]
-    <AS>
+    <AS> { asKeywordPos = getPos(); }

Review Comment:
   `getPos()` returns the position of the token that was just consumed.
   ```sql
     CREATE MATERIALIZED TABLE m AS SELECT 1                                    
                                                             
                                 ^^                                             
                                                             
                            cols 29–30  →  getPos() = pos(line 1, col 29 → line 
1, col 30) 
   ```
   
   `startPos.plus(getPos())` the position captured at the start of the 
statement (the CREATE keyword, col 1)
   
   ```sql
     CREATE MATERIALIZED TABLE m AS SELECT 1                                    
                                                             
     ^---------------------------^                                              
                                                             
     cols 1 .. 30  =  the whole statement so far (CREATE … AS)   
   ```
   
   so `getPos()` here is correct, since we want just the position of the `AS` 
keyword.



##########
flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/operations/converters/SqlNodeConvertUtils.java:
##########
@@ -46,14 +48,74 @@
 import javax.annotation.Nullable;
 
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Collectors;
 
 /** Utilities for SqlNode conversions. */
-class SqlNodeConvertUtils {
+public class SqlNodeConvertUtils {
+
+    /**
+     * Returns the user's original {@code AS}-query text: the verbatim 
substring of the statement
+     * from immediately after the {@code AS} keyword to the end of the 
statement, trimmed of
+     * surrounding whitespace.
+     *
+     * <p>The {@code AS}-query is the final clause of {@code CREATE/ALTER 
MATERIALIZED TABLE} and
+     * {@code CREATE/ALTER VIEW}, so everything after {@code AS} is the query: 
comments around it
+     * are kept, the {@code AS} keyword is excluded. Slicing to the statement 
end (rather than the
+     * query node's parser position) keeps the whole query for node types 
whose position does not
+     * span their full text, e.g. {@code WITH ... SELECT}, where {@code 
SqlWith} ends at the
+     * with-list and would otherwise drop the trailing {@code SELECT}. Slicing 
from the source also
+     * preserves the user's wording (case, formatting, type aliases) that 
re-rendering the parsed
+     * tree would normalize.
+     *
+     * <p>Returns {@link Optional#empty()} when the statement text is 
unavailable (e.g. a
+     * synthesized node with no source text); callers decide the fallback.
+     *
+     * @param asKeywordPos parser position of the {@code AS} keyword
+     * @return the verbatim AS-query text, or empty when the statement text is 
unavailable
+     */
+    public static Optional<String> rawAsQueryText(
+            ConvertContext context, @Nullable SqlParserPos asKeywordPos) {
+        if (asKeywordPos == null) {
+            return Optional.empty();
+        }
+        final String statementText = context.getStatementText();
+        if (statementText != null) {
+            final int start = offsetAfterAs(statementText, asKeywordPos);
+            if (start >= 0) {
+                return Optional.of(statementText.substring(start).strip());
+            }
+        }
+        return Optional.empty();
+    }
+
+    /**
+     * Returns the offset of the first character after the {@code AS} keyword, 
or {@code -1} if the
+     * keyword position falls outside {@code statement}.
+     */
+    private static int offsetAfterAs(String statement, SqlParserPos 
asKeywordPos) {

Review Comment:
   Use `OptionalInt` now



##########
flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/operations/SqlNodeConvertContext.java:
##########
@@ -110,6 +123,19 @@ public String toQuotedSqlString(SqlNode sqlNode) {
         return sqlNode.toSqlString(getSqlDialect()).getSql();
     }
 
+    @Override
+    @Nullable
+    public String getStatementText() {
+        return this.statement;
+    }
+
+    @Override
+    public String expandSqlIdentifiers(String originalSql) {

Review Comment:
   Just wanted to have all the Overrides in the correct order. It is unrelated 
so I moved it back.



##########
flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/operations/converters/SqlNodeConvertUtils.java:
##########
@@ -46,14 +48,74 @@
 import javax.annotation.Nullable;
 
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Collectors;
 
 /** Utilities for SqlNode conversions. */
-class SqlNodeConvertUtils {
+public class SqlNodeConvertUtils {
+
+    /**

Review Comment:
   The wall of text is gone now



##########
flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/operations/converters/SqlNodeConvertUtils.java:
##########
@@ -46,14 +48,74 @@
 import javax.annotation.Nullable;
 
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Collectors;
 
 /** Utilities for SqlNode conversions. */
-class SqlNodeConvertUtils {
+public class SqlNodeConvertUtils {
+
+    /**
+     * Returns the user's original {@code AS}-query text: the verbatim 
substring of the statement
+     * from immediately after the {@code AS} keyword to the end of the 
statement, trimmed of
+     * surrounding whitespace.
+     *
+     * <p>The {@code AS}-query is the final clause of {@code CREATE/ALTER 
MATERIALIZED TABLE} and
+     * {@code CREATE/ALTER VIEW}, so everything after {@code AS} is the query: 
comments around it
+     * are kept, the {@code AS} keyword is excluded. Slicing to the statement 
end (rather than the
+     * query node's parser position) keeps the whole query for node types 
whose position does not
+     * span their full text, e.g. {@code WITH ... SELECT}, where {@code 
SqlWith} ends at the
+     * with-list and would otherwise drop the trailing {@code SELECT}. Slicing 
from the source also
+     * preserves the user's wording (case, formatting, type aliases) that 
re-rendering the parsed
+     * tree would normalize.
+     *
+     * <p>Returns {@link Optional#empty()} when the statement text is 
unavailable (e.g. a
+     * synthesized node with no source text); callers decide the fallback.
+     *
+     * @param asKeywordPos parser position of the {@code AS} keyword
+     * @return the verbatim AS-query text, or empty when the statement text is 
unavailable
+     */
+    public static Optional<String> rawAsQueryText(
+            ConvertContext context, @Nullable SqlParserPos asKeywordPos) {
+        if (asKeywordPos == null) {
+            return Optional.empty();
+        }
+        final String statementText = context.getStatementText();
+        if (statementText != null) {
+            final int start = offsetAfterAs(statementText, asKeywordPos);
+            if (start >= 0) {
+                return Optional.of(statementText.substring(start).strip());
+            }
+        }
+        return Optional.empty();
+    }
+
+    /**
+     * Returns the offset of the first character after the {@code AS} keyword, 
or {@code -1} if the
+     * keyword position falls outside {@code statement}.
+     */
+    private static int offsetAfterAs(String statement, SqlParserPos 
asKeywordPos) {

Review Comment:
   Made the method more general now



##########
flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/operations/converters/SqlNodeConvertUtils.java:
##########
@@ -110,6 +166,13 @@ static CatalogView toCatalogView(
             schema = ResolvedSchema.physical(aliasFieldNames, 
schema.getColumnDataTypes());
         }
 
+        // Capture the user's original wording (case, formatting, type 
aliases) by slicing the

Review Comment:
   Removed the comments



##########
flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/operations/converters/SqlNodeConvertUtils.java:
##########
@@ -46,14 +48,74 @@
 import javax.annotation.Nullable;
 
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Collectors;
 
 /** Utilities for SqlNode conversions. */
-class SqlNodeConvertUtils {
+public class SqlNodeConvertUtils {
+
+    /**
+     * Returns the user's original {@code AS}-query text: the verbatim 
substring of the statement
+     * from immediately after the {@code AS} keyword to the end of the 
statement, trimmed of
+     * surrounding whitespace.
+     *
+     * <p>The {@code AS}-query is the final clause of {@code CREATE/ALTER 
MATERIALIZED TABLE} and
+     * {@code CREATE/ALTER VIEW}, so everything after {@code AS} is the query: 
comments around it
+     * are kept, the {@code AS} keyword is excluded. Slicing to the statement 
end (rather than the
+     * query node's parser position) keeps the whole query for node types 
whose position does not
+     * span their full text, e.g. {@code WITH ... SELECT}, where {@code 
SqlWith} ends at the
+     * with-list and would otherwise drop the trailing {@code SELECT}. Slicing 
from the source also
+     * preserves the user's wording (case, formatting, type aliases) that 
re-rendering the parsed
+     * tree would normalize.
+     *
+     * <p>Returns {@link Optional#empty()} when the statement text is 
unavailable (e.g. a
+     * synthesized node with no source text); callers decide the fallback.
+     *
+     * @param asKeywordPos parser position of the {@code AS} keyword
+     * @return the verbatim AS-query text, or empty when the statement text is 
unavailable
+     */
+    public static Optional<String> rawAsQueryText(
+            ConvertContext context, @Nullable SqlParserPos asKeywordPos) {
+        if (asKeywordPos == null) {
+            return Optional.empty();
+        }
+        final String statementText = context.getStatementText();
+        if (statementText != null) {

Review Comment:
   Inverted and refactored the method



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to