This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch branch-4.0
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.0 by this push:
     new 29957aa43c4 branch-4.0: [fix](jdbc) catch session terminate signal and 
cancel job #59836 (#59987)
29957aa43c4 is described below

commit 29957aa43c4b3a20f651f469b99a5f6534ec5612
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Sat Jan 17 16:33:20 2026 +0800

    branch-4.0: [fix](jdbc) catch session terminate signal and cancel job 
#59836 (#59987)
    
    Cherry-picked from #59836
    
    Co-authored-by: Mingyu Chen (Rayner) <[email protected]>
---
 .../org/apache/doris/jdbc/BaseJdbcExecutor.java    | 92 ++++++++++++++++++++--
 .../test_remote_doris_variant_select.out           |  4 +-
 2 files changed, 89 insertions(+), 7 deletions(-)

diff --git 
a/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java
 
b/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java
index 3160ff6fd0f..83113f66dcd 100644
--- 
a/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java
+++ 
b/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java
@@ -233,7 +233,7 @@ public abstract class BaseJdbcExecutor implements 
JdbcExecutor {
 
             if (isNullableString == null || replaceString == null) {
                 throw new IllegalArgumentException(
-                    "Output parameters 'is_nullable' and 'replace_string' are 
required.");
+                        "Output parameters 'is_nullable' and 'replace_string' 
are required.");
             }
 
             String[] nullableList = isNullableString.split(",");
@@ -253,19 +253,63 @@ public abstract class BaseJdbcExecutor implements 
JdbcExecutor {
                 }
             }
 
-            do {
+            // Validate connection and resultSet once at the start of the 
batch (not for every row)
+            if (resultSet == null) {
+                throw new SQLException("ResultSet is null");
+            }
+            if (conn != null && conn.isClosed()) {
+                throw new SQLException("Connection has been closed");
+            }
+            if (resultSet.isClosed()) {
+                throw new SQLException("ResultSet has been closed");
+            }
+
+            // Contract with caller:
+            // - Caller has already called hasNext(), and only calls 
getBlockAddress() if hasNext() returned true.
+            // - So when entering this method, the ResultSet cursor is already 
positioned on a valid current row.
+            while (curBlockRows < batchSize) {
+                // Read the current row data
                 for (int i = 0; i < outputColumnCount; ++i) {
                     String outputColumnName = outputTable.getFields()[i];
                     int columnIndex = getRealColumnIndex(outputColumnName, i);
                     if (columnIndex > -1) {
                         ColumnType type = convertTypeIfNecessary(i, 
outputTable.getColumnType(i), replaceStringList);
-                        block.get(i)[curBlockRows] = 
getColumnValue(columnIndex, type, replaceStringList);
+                        try {
+                            block.get(i)[curBlockRows] = 
getColumnValue(columnIndex, type, replaceStringList);
+                        } catch (SQLException e) {
+                            // Add context and re-throw
+                            // Connection validity will be checked in the 
outer catch block
+                            throw new SQLException(
+                                    String.format("Error reading column '%s' 
(index %d): %s",
+                                            outputColumnName, columnIndex, 
e.getMessage()), e);
+                        }
                     } else {
                         throw new RuntimeException("Column not found in 
resultSetColumnMap: " + outputColumnName);
                     }
                 }
                 curBlockRows++;
-            } while (curBlockRows < batchSize && resultSet.next());
+
+                // Check if we've filled the batch before advancing cursor
+                if (curBlockRows >= batchSize) {
+                    break;
+                }
+
+                // Advance to next row for the next iteration / next block.
+                boolean hasNext;
+                try {
+                    hasNext = resultSet.next();
+                } catch (SQLException e) {
+                    // Add context about how many rows were successfully read
+                    // Connection validity will be checked in the outer catch 
block
+                    throw new SQLException(
+                            String.format("Error calling resultSet.next() 
after reading %d rows: %s",
+                                    curBlockRows, e.getMessage()), e);
+                }
+
+                if (!hasNext) {
+                    break;
+                }
+            }
 
             for (int i = 0; i < outputColumnCount; ++i) {
                 String outputColumnName = outputTable.getFields()[i];
@@ -287,11 +331,19 @@ public abstract class BaseJdbcExecutor implements 
JdbcExecutor {
                     throw new RuntimeException("Column not found in 
resultSetColumnMap: " + outputColumnName);
                 }
             }
+        } catch (SQLException e) {
+            // Enhanced error handling for SQL exceptions
+            // Only check connection status when exception occurs (not in hot 
loop)
+            String errorMsg = "JDBC get block address failed" + 
buildConnectionStatusInfo();
+            LOG.warn(errorMsg + ": " + e.getMessage(), e);
+            throw new JdbcExecutorException(errorMsg + ": " + e.getMessage(), 
e);
         } catch (Exception e) {
             LOG.warn("jdbc get block address exception: ", e);
             throw new JdbcExecutorException("jdbc get block address: ", e);
         } finally {
-            block.clear();
+            if (block != null) {
+                block.clear();
+            }
         }
         return outputTable.getMetaAddress();
     }
@@ -332,6 +384,33 @@ public abstract class BaseJdbcExecutor implements 
JdbcExecutor {
         }
     }
 
+    /**
+     * Build connection and resultSet status information for error messages.
+     * Only called when an exception occurs to avoid performance overhead.
+     */
+    private String buildConnectionStatusInfo() {
+        StringBuilder sb = new StringBuilder();
+        if (conn != null) {
+            try {
+                boolean isClosed = conn.isClosed();
+                boolean isValid = !isClosed && conn.isValid(1);
+                sb.append(String.format(" (Connection closed: %s, valid: %s)", 
isClosed, isValid));
+            } catch (SQLException e) {
+                sb.append(" (Failed to check connection: 
").append(e.getMessage()).append(")");
+            }
+        }
+        if (resultSet != null) {
+            try {
+                boolean isClosed = resultSet.isClosed();
+                sb.append(String.format(" (ResultSet closed: %s)", isClosed));
+            } catch (SQLException e) {
+                // ResultSet.isClosed() may throw SQLException if connection 
is invalid
+                sb.append(" (ResultSet status unknown)");
+            }
+        }
+        return sb.toString();
+    }
+
     public void commitTrans() throws JdbcExecutorException {
         try {
             if (conn != null) {
@@ -361,6 +440,9 @@ public abstract class BaseJdbcExecutor implements 
JdbcExecutor {
             if (resultSet == null) {
                 return false;
             }
+            // Move the cursor forward and report whether there is a row to 
read.
+            // Caller should only call getBlockAddress() when this returns 
true,
+            // so getBlockAddress() can safely start reading from the current 
row.
             return resultSet.next();
         } catch (SQLException e) {
             throw new JdbcExecutorException("resultSet to get next error: ", 
e);
diff --git 
a/regression-test/data/external_table_p0/remote_doris/test_remote_doris_variant_select.out
 
b/regression-test/data/external_table_p0/remote_doris/test_remote_doris_variant_select.out
index 8c1e03b0996..438583116fb 100644
--- 
a/regression-test/data/external_table_p0/remote_doris/test_remote_doris_variant_select.out
+++ 
b/regression-test/data/external_table_p0/remote_doris/test_remote_doris_variant_select.out
@@ -2,12 +2,12 @@
 -- !sql --
 1      {}
 2      \N
-3      1
+3      true
 4      -17
 5      123.12
 6      1.912
 7      "A quote"
-8      [-1,12,0]
+8      [-1,12,false]
 9      {"x":"abc","y":0,"z":10}
 10     "2021-01-01"
 11     {"a":"a","b":"0.1","c":{"c1":"c1","c2":"1"}}


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

Reply via email to