From a76f4f7ac098753ecfa811c91284869f1e8231c1 Mon Sep 17 00:00:00 2001 From: JackieTien97 Date: Wed, 1 Jul 2026 11:31:02 +0800 Subject: [PATCH] Fix JDBC reusing stale statement id after reconnect After reConnect() refreshes this.sessionId/this.stmtId, the retry lambda in executeSQL/executeQuerySQL/executeUpdateSQL still sends the original TSExecuteStatementReq carrying the OLD ids. The server resolves the session by the current RPC connection (NEW session) but takes the statementId from the request body (OLD), so ClientSession.addQueryId throws "StatementId ... doesn't exist in this session", surfaced as INTERNAL_SERVER_ERROR(305) -- the root cause of recurring query-restart-datanode JDBC test failures. Refresh sessionId and statementId inside each retry lambda, mirroring SessionConnection in the Session SDK, which already does this correctly. executeBatchSQL is refreshed for sessionId for consistency (no statement id). --- .../org/apache/iotdb/jdbc/IoTDBStatement.java | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBStatement.java b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBStatement.java index 1c6ce8c0e9b14..17fe5ef3617fe 100644 --- a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBStatement.java +++ b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBStatement.java @@ -363,7 +363,14 @@ private boolean executeSQL(String sql) throws TException, SQLException { execReq.setTimeout((long) queryTimeout * 1000); TSExecuteStatementResp execResp = callWithRetryAndReconnect( - () -> client.executeStatementV2(execReq), TSExecuteStatementResp::getStatus); + () -> { + // reConnect() may have replaced the session/statement id, so refresh them on every + // attempt; otherwise the server reports "StatementId doesn't exist in this session". + execReq.setSessionId(sessionId); + execReq.setStatementId(stmtId); + return client.executeStatementV2(execReq); + }, + TSExecuteStatementResp::getStatus); if (execResp.isSetOperationType() && execResp.getOperationType().equals("dropDB")) { connection.changeDefaultDatabase(null); @@ -430,7 +437,13 @@ private int[] executeBatchSQL() throws TException, BatchUpdateException, SQLExce isCancelled = false; TSExecuteBatchStatementReq execReq = new TSExecuteBatchStatementReq(sessionId, batchSQLList); TSStatus execResp = - callWithRetryAndReconnect(() -> client.executeBatchStatement(execReq), status -> status); + callWithRetryAndReconnect( + () -> { + // reConnect() may have replaced the session id, so refresh it on every attempt. + execReq.setSessionId(sessionId); + return client.executeBatchStatement(execReq); + }, + status -> status); int[] result = new int[batchSQLList.size()]; boolean allSuccess = true; StringBuilder message = new StringBuilder(System.lineSeparator()); @@ -500,7 +513,14 @@ private ResultSet executeQuerySQL(String sql, long timeoutInMS) throws TExceptio execReq.setJdbcQuery(true); TSExecuteStatementResp execResp = callWithRetryAndReconnect( - () -> client.executeQueryStatementV2(execReq), TSExecuteStatementResp::getStatus); + () -> { + // reConnect() may have replaced the session/statement id, so refresh them on every + // attempt; otherwise the server reports "StatementId doesn't exist in this session". + execReq.setSessionId(sessionId); + execReq.setStatementId(stmtId); + return client.executeQueryStatementV2(execReq); + }, + TSExecuteStatementResp::getStatus); queryId = execResp.getQueryId(); try { RpcUtils.verifySuccess(execResp.getStatus()); @@ -575,7 +595,14 @@ private int executeUpdateSQL(final String sql) final TSExecuteStatementReq execReq = new TSExecuteStatementReq(sessionId, sql, stmtId); final TSExecuteStatementResp execResp = callWithRetryAndReconnect( - () -> client.executeUpdateStatement(execReq), TSExecuteStatementResp::getStatus); + () -> { + // reConnect() may have replaced the session/statement id, so refresh them on every + // attempt; otherwise the server reports "StatementId doesn't exist in this session". + execReq.setSessionId(sessionId); + execReq.setStatementId(stmtId); + return client.executeUpdateStatement(execReq); + }, + TSExecuteStatementResp::getStatus); if (execResp.isSetQueryId()) { queryId = execResp.getQueryId(); }