github-actions[bot] commented on code in PR #68786:
URL: https://github.com/apache/doris/pull/68786#discussion_r4228357016


##########
fe/fe-connector/fe-connector-jdbc/src/main/java/org/apache/doris/connector/jdbc/JdbcQueryBuilder.java:
##########
@@ -190,6 +191,161 @@ public String buildQuery(String remoteDbName, String 
remoteTableName,
         return sql.toString();
     }
 
+    private String timestampProjection(String expression, 
org.apache.doris.connector.spi.ConnectorType type,
+            int depth) {
+        if ("TIMESTAMPTZ".equals(type.getTypeName())) {
+            if (dbType == JdbcDbType.MYSQL || dbType == JdbcDbType.OCEANBASE) {
+                // MySQL drivers can apply a cached timezone even in 
getString() for binary results.
+                // A server-side text projection preserves the UTC session 
fields and microseconds.
+                return "CAST(" + expression + " AS CHAR)";
+            }
+            if (dbType == JdbcDbType.CLICKHOUSE) {
+                return "toUnixTimestamp64Micro(toDateTime64(" + expression + 
", 6))";
+            }
+            if (dbType == JdbcDbType.TRINO || dbType == JdbcDbType.PRESTO) {
+                return "(" + expression + " AT TIME ZONE 'UTC')";
+            }
+        }
+        if ("ARRAY".equals(type.getTypeName()) && containsInstant(type)) {
+            String element = "doris_ts_" + depth;
+            String converted = timestampProjection(element, 
type.getChildren().get(0), depth + 1);
+            if (dbType == JdbcDbType.CLICKHOUSE) {
+                return "arrayMap(" + element + " -> " + converted + ", " + 
expression + ")";
+            }
+            if (dbType == JdbcDbType.TRINO || dbType == JdbcDbType.PRESTO) {
+                return "transform(" + expression + ", " + element + " -> " + 
converted + ")";
+            }
+        }
+        return expression;
+    }
+
+    private static boolean 
containsInstant(org.apache.doris.connector.spi.ConnectorType type) {
+        return "TIMESTAMPTZ".equals(type.getTypeName()) || 
type.getChildren().stream().anyMatch(
+                JdbcQueryBuilder::containsInstant);
+    }
+
+    public String wrapPassthroughQuery(String query, 
List<ConnectorColumnHandle> columns) {
+        if (columns.stream().noneMatch(c -> c instanceof JdbcColumnHandle
+                && containsInstant(((JdbcColumnHandle) c).getType()))
+                || (dbType != JdbcDbType.CLICKHOUSE && dbType != 
JdbcDbType.TRINO && dbType != JdbcDbType.PRESTO
+                        && dbType != JdbcDbType.MYSQL && dbType != 
JdbcDbType.OCEANBASE)) {
+            return query;
+        }
+        // Project before driver decoding: a named-zone DST fold has already 
lost its offset afterward.
+        StringJoiner projections = new StringJoiner(", ");
+        for (ConnectorColumnHandle column : columns) {
+            JdbcColumnHandle jdbcColumn = (JdbcColumnHandle) column;
+            String name = JdbcIdentifierQuoter.quoteRemoteIdentifier(dbType, 
jdbcColumn.getRemoteName());
+            projections.add(timestampProjection(name, jdbcColumn.getType(), 0) 
+ " AS " + name);
+        }
+        String inner = query.trim().replaceAll(";+$", "");

Review Comment:
   [P2] Handle a semicolon before a trailing TVF comment. With 
`enable.mapping.timestamp_tz=true`, a MySQL query TVF such as `SELECT ts FROM 
t; -- label` can pass `getColumnsFromQuery` on the original SQL, but this trim 
leaves `;` before the comment. The projection then sends `FROM (SELECT ts FROM 
t; -- label\n)`, which MySQL cannot parse as a derived table, so the scan fails 
after schema discovery. Strip the terminal statement delimiter while preserving 
trailing comments before nesting, and cover the combined shape. This is 
distinct from the repaired Trino `WITH SESSION` case.



##########
fe/be-java-extensions/paimon-scanner/src/main/java/org/apache/doris/paimon/PaimonJniScanner.java:
##########
@@ -447,9 +461,24 @@ private int readAndProcessNextBatch() throws IOException {
                     rows++;
                     columnValue.setOffsetRow(record);
                     for (int i = 0; i < fields.length; i++) {
-                        columnValue.setIdx(
-                                i, types[i], paimonDataTypeList.get(i), 
variantProjections.get(i));
-                        appendData(i, columnValue);
+                        int readIndex = outputToReadIndex[i];
+                        if (readIndex < 0) {
+                            // Physical positions come from the SDK, so 
filtering/deletion vectors cannot
+                            // turn a returned-row counter into an incorrect 
file row index.
+                            if (!(recordIterator instanceof 
FileRecordIterator)) {

Review Comment:
   [P2] Guard metadata reads for legacy primary-key merge iterators. A Paimon 
1.4.2 primary-key ORC file with no historical `deleteRowCount` is marked 
raw-convertible, so FE permits a selected legacy LTZ field plus 
`__paimon_file_path` or `__paimon_row_index` through the JNI fallback. Paimon's 
raw reader rejects that file and its merge reader returns 
`ValueContentRowDataRecordIterator`; this check then throws on the first row. 
Match Paimon's actual raw-reader eligibility before admitting metadata columns, 
and cover an upgraded primary-key file. The existing mixed-projection thread 
concerns the append-only raw-file path, which now works.



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