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]