Gabriel39 commented on code in PR #68873:
URL: https://github.com/apache/doris/pull/68873#discussion_r4237170604


##########
fe/be-java-extensions/jdbc-scanner/pom.xml:
##########
@@ -35,6 +35,12 @@ under the License.
     </properties>
 
     <dependencies>
+        <dependency>
+            <groupId>com.oracle.database.jdbc</groupId>
+            <artifactId>ojdbc11</artifactId>
+            <version>23.26.2.0.0</version>

Review Comment:
   Fixed in 873b1547a2. Oracle integration drivers are now loaded with the JDBC 
API classloader as parent, excluding the Oracle mock dependency. The helper 
checks the actual source JAR before connecting. Added a regression test that 
fails with the old parent-first setup; also verified isolated loading and 
instantiation of Oracle JDBC 11.2 and 23.26 from their respective configured 
JARs. No driver compatibility changes are included.



##########
fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/source/JdbcScanNode.java:
##########
@@ -213,13 +219,151 @@ private String getTvfQuery() {
         if (!projectsTimestamps) {
             return query;
         }
-        String source = query.trim();
-        if (source.endsWith(";")) {
-            source = source.substring(0, source.length() - 1);
+        boolean mysql = jdbcType == TOdbcTableType.MYSQL || jdbcType == 
TOdbcTableType.OCEANBASE;
+        if (mysql && mysqlSqlMode == null) {
+            // Resolve only for wrapped MySQL queries and reuse the result for 
EXPLAIN and scan serialization.
+            org.apache.doris.datasource.jdbc.JdbcExternalCatalog catalog =
+                    (org.apache.doris.datasource.jdbc.JdbcExternalCatalog) 
org.apache.doris.catalog.Env
+                            
.getCurrentEnv().getCatalogMgr().getCatalog(catalogId);
+            mysqlSqlMode = catalog.getJdbcClient().getSessionSqlMode();
+        }
+        String source = stripTerminalDelimiter(query.trim(),
+                mysql && mysqlSqlMode.contains("NO_BACKSLASH_ESCAPES"), mysql 
&& mysqlSqlMode.contains("ANSI_QUOTES"));
+        // WITH SESSION must stay outside the derived table; terminate 
trailing line comments with a newline.
+        int start = jdbcType == TOdbcTableType.TRINO ? 
trinoSessionQueryStart(source) : 0;
+        return source.substring(0, start) + "SELECT " + Joiner.on(", 
").join(columns)
+                + " FROM (" + source.substring(start) + "\n) 
doris_jdbc_source";
+    }
+
+    private String stripTerminalDelimiter(String sql, boolean 
noBackslashEscapes, boolean ansiQuotes) {
+        boolean mysql = jdbcType == TOdbcTableType.MYSQL || jdbcType == 
TOdbcTableType.OCEANBASE;
+        List<Integer> delimiters = new java.util.ArrayList<>();
+        for (int i = 0; i < sql.length();) {
+            char c = sql.charAt(i);
+            if (Character.isWhitespace(c)) {
+                i++;
+            // MySQL's second dash needs a following whitespace/control 
character; --1 is arithmetic.
+            } else if ((sql.startsWith("--", i) && (!mysql || (i + 2 < 
sql.length()
+                    && (Character.isWhitespace(sql.charAt(i + 2)) || 
Character.isISOControl(sql.charAt(i + 2))))))
+                    || (c == '#'
+                    && (jdbcType == TOdbcTableType.MYSQL || jdbcType == 
TOdbcTableType.OCEANBASE))) {
+                while (i < sql.length() && sql.charAt(i) != '\n' && 
sql.charAt(i) != '\r') {
+                    i++;
+                }
+            } else if (sql.startsWith("/*", i)) {
+                i = skipBlockComment(sql, i, jdbcType == 
TOdbcTableType.CLICKHOUSE);
+            } else if (c == '\'' || c == '"' || c == '`') {
+                char quote = c;
+                for (i++; i < sql.length(); i++) {
+                    // ANSI_QUOTES makes double quotes identifiers, where 
backslashes never escape the closing quote.
+                    // Both quoting modes belong to the remote session.
+                    if (sql.charAt(i) == '\\' && !(mysql && noBackslashEscapes)
+                            && !(mysql && ansiQuotes && quote == '"') && quote 
!= '`'

Review Comment:
   Fixed in 873b1547a2. ClickHouse backtick identifiers now honor backslash 
escapes. Regression cases cover an escaped backtick and a semicolon inside the 
identifier. Generated queries were executed successfully with ClickHouse 23.8.



##########
fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/source/JdbcScanNode.java:
##########
@@ -213,13 +219,151 @@ private String getTvfQuery() {
         if (!projectsTimestamps) {
             return query;
         }
-        String source = query.trim();
-        if (source.endsWith(";")) {
-            source = source.substring(0, source.length() - 1);
+        boolean mysql = jdbcType == TOdbcTableType.MYSQL || jdbcType == 
TOdbcTableType.OCEANBASE;
+        if (mysql && mysqlSqlMode == null) {
+            // Resolve only for wrapped MySQL queries and reuse the result for 
EXPLAIN and scan serialization.
+            org.apache.doris.datasource.jdbc.JdbcExternalCatalog catalog =
+                    (org.apache.doris.datasource.jdbc.JdbcExternalCatalog) 
org.apache.doris.catalog.Env
+                            
.getCurrentEnv().getCatalogMgr().getCatalog(catalogId);
+            mysqlSqlMode = catalog.getJdbcClient().getSessionSqlMode();
+        }
+        String source = stripTerminalDelimiter(query.trim(),
+                mysql && mysqlSqlMode.contains("NO_BACKSLASH_ESCAPES"), mysql 
&& mysqlSqlMode.contains("ANSI_QUOTES"));
+        // WITH SESSION must stay outside the derived table; terminate 
trailing line comments with a newline.
+        int start = jdbcType == TOdbcTableType.TRINO ? 
trinoSessionQueryStart(source) : 0;
+        return source.substring(0, start) + "SELECT " + Joiner.on(", 
").join(columns)
+                + " FROM (" + source.substring(start) + "\n) 
doris_jdbc_source";
+    }
+
+    private String stripTerminalDelimiter(String sql, boolean 
noBackslashEscapes, boolean ansiQuotes) {
+        boolean mysql = jdbcType == TOdbcTableType.MYSQL || jdbcType == 
TOdbcTableType.OCEANBASE;
+        List<Integer> delimiters = new java.util.ArrayList<>();
+        for (int i = 0; i < sql.length();) {
+            char c = sql.charAt(i);
+            if (Character.isWhitespace(c)) {
+                i++;
+            // MySQL's second dash needs a following whitespace/control 
character; --1 is arithmetic.
+            } else if ((sql.startsWith("--", i) && (!mysql || (i + 2 < 
sql.length()
+                    && (Character.isWhitespace(sql.charAt(i + 2)) || 
Character.isISOControl(sql.charAt(i + 2))))))

Review Comment:
   Fixed in 873b1547a2. The wrapper skips ClickHouse //, #!, and # space 
comments before interpreting their contents. Tests cover unmatched quotes, 
LF/CRLF, and terminal delimiters. Actual ClickHouse execution also covers 
comments after the terminal delimiter.



##########
fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/source/JdbcScanNode.java:
##########
@@ -213,13 +219,151 @@ private String getTvfQuery() {
         if (!projectsTimestamps) {
             return query;
         }
-        String source = query.trim();
-        if (source.endsWith(";")) {
-            source = source.substring(0, source.length() - 1);
+        boolean mysql = jdbcType == TOdbcTableType.MYSQL || jdbcType == 
TOdbcTableType.OCEANBASE;
+        if (mysql && mysqlSqlMode == null) {
+            // Resolve only for wrapped MySQL queries and reuse the result for 
EXPLAIN and scan serialization.
+            org.apache.doris.datasource.jdbc.JdbcExternalCatalog catalog =
+                    (org.apache.doris.datasource.jdbc.JdbcExternalCatalog) 
org.apache.doris.catalog.Env
+                            
.getCurrentEnv().getCatalogMgr().getCatalog(catalogId);
+            mysqlSqlMode = catalog.getJdbcClient().getSessionSqlMode();
+        }
+        String source = stripTerminalDelimiter(query.trim(),
+                mysql && mysqlSqlMode.contains("NO_BACKSLASH_ESCAPES"), mysql 
&& mysqlSqlMode.contains("ANSI_QUOTES"));
+        // WITH SESSION must stay outside the derived table; terminate 
trailing line comments with a newline.
+        int start = jdbcType == TOdbcTableType.TRINO ? 
trinoSessionQueryStart(source) : 0;
+        return source.substring(0, start) + "SELECT " + Joiner.on(", 
").join(columns)
+                + " FROM (" + source.substring(start) + "\n) 
doris_jdbc_source";
+    }
+
+    private String stripTerminalDelimiter(String sql, boolean 
noBackslashEscapes, boolean ansiQuotes) {
+        boolean mysql = jdbcType == TOdbcTableType.MYSQL || jdbcType == 
TOdbcTableType.OCEANBASE;
+        List<Integer> delimiters = new java.util.ArrayList<>();
+        for (int i = 0; i < sql.length();) {
+            char c = sql.charAt(i);
+            if (Character.isWhitespace(c)) {
+                i++;
+            // MySQL's second dash needs a following whitespace/control 
character; --1 is arithmetic.
+            } else if ((sql.startsWith("--", i) && (!mysql || (i + 2 < 
sql.length()
+                    && (Character.isWhitespace(sql.charAt(i + 2)) || 
Character.isISOControl(sql.charAt(i + 2))))))
+                    || (c == '#'
+                    && (jdbcType == TOdbcTableType.MYSQL || jdbcType == 
TOdbcTableType.OCEANBASE))) {
+                while (i < sql.length() && sql.charAt(i) != '\n' && 
sql.charAt(i) != '\r') {
+                    i++;
+                }
+            } else if (sql.startsWith("/*", i)) {
+                i = skipBlockComment(sql, i, jdbcType == 
TOdbcTableType.CLICKHOUSE);
+            } else if (c == '\'' || c == '"' || c == '`') {
+                char quote = c;

Review Comment:
   Fixed in 873b1547a2. The wrapper skips matched ClickHouse heredoc tags as 
raw literals, preserving embedded quotes, comment markers and semicolons. Tests 
cover named/empty tags, empty payloads, and preservation of interior statement 
delimiters. Generated queries passed actual ClickHouse execution.



-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to