This is an automated email from the ASF dual-hosted git repository. Caideyipi pushed a commit to branch codex/fix-jdbc-protocol-diagnostic-match in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 54dc422a67461690d7ceb1a7425a4891e3cc0485 Author: Caideyipi <[email protected]> AuthorDate: Tue Nov 3 12:17:07 2026 +0800 Preserve JDBC legacy-server diagnostics across locales --- .../org/apache/iotdb/jdbc/IoTDBConnection.java | 7 ++- .../org/apache/iotdb/jdbc/IoTDBConnectionTest.java | 68 ++++++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java index d81f15acdf6..7eabe4e4add 100644 --- a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java +++ b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java @@ -73,6 +73,9 @@ public class IoTDBConnection implements Connection { private static final Logger logger = LoggerFactory.getLogger(IoTDBConnection.class); private static final TSProtocolVersion protocolVersion = TSProtocolVersion.IOTDB_SERVICE_PROTOCOL_V3; + // Match Thrift's fixed protocol text independently of the localized SQLException message. + private static final String MISSING_CLIENT_PROTOCOL_DIAGNOSTIC = + "Required field 'client_protocol' was not present!"; private static final String NOT_SUPPORT_PREPARE_CALL = JdbcMessages.EXCEPTION_DOES_NOT_SUPPORT_PREPARECALL_2E958060; private static final String NOT_SUPPORT_PREPARE_STATEMENT = @@ -619,9 +622,7 @@ public class IoTDBConnection implements Connection { } } catch (TException e) { transport.close(); - if (e.getMessage() - .contains( - JdbcMessages.EXCEPTION_REQUIRED_FIELD_CLIENT_PROTOCOL_WAS_NOT_PRESENT_2059BC1E)) { + if (e.getMessage().contains(MISSING_CLIENT_PROTOCOL_DIAGNOSTIC)) { // the server is an old version (less than 0.10) throw new SQLException( String.format( diff --git a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBConnectionTest.java b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBConnectionTest.java index be3c7de929e..c31726e605c 100644 --- a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBConnectionTest.java +++ b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBConnectionTest.java @@ -20,13 +20,16 @@ package org.apache.iotdb.jdbc; import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.jdbc.i18n.JdbcMessages; import org.apache.iotdb.rpc.RpcUtils; import org.apache.iotdb.service.rpc.thrift.IClientRPCService; import org.apache.iotdb.service.rpc.thrift.ServerProperties; import org.apache.iotdb.service.rpc.thrift.TSGetTimeZoneResp; +import org.apache.iotdb.service.rpc.thrift.TSOpenSessionReq; import org.apache.iotdb.service.rpc.thrift.TSSetTimeZoneReq; import org.apache.thrift.TException; +import org.apache.thrift.transport.TTransport; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -34,17 +37,25 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.sql.SQLClientInfoException; import java.sql.SQLException; import java.time.ZoneId; import java.util.ArrayList; import java.util.List; +import java.util.Properties; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -158,4 +169,61 @@ public class IoTDBConnectionTest { verify(tableConnection, never()).prepareStatement(anyString()); } + + @Test + public void testOpenSessionRecognizesLegacyProtocolDiagnostic() throws Exception { + TException cause = + new TException( + "Required field 'client_protocol' was not present! Struct: TSOpenSessionReq(...)"); + + SQLException exception = failOpenSession(cause); + + assertEquals( + String.format( + JdbcMessages + .EXCEPTION_CAN_NOT_ESTABLISH_CONNECTION_ARG_YOU_MAY_TRY_CONNECT_OLD_8FC3703E, + connection.getParams().getJdbcUriString(), + cause.getMessage()), + exception.getMessage()); + } + + @Test + public void testOpenSessionPreservesOtherMissingFieldDiagnostic() throws Exception { + TException cause = + new TException("Required field 'username' was not present! Struct: TSOpenSessionReq(...)"); + + SQLException exception = failOpenSession(cause); + + assertEquals( + String.format( + JdbcMessages.EXCEPTION_CAN_NOT_ESTABLISH_CONNECTION_ARG_ARG_D7246055, + connection.getParams().getJdbcUriString(), + cause.getMessage()), + exception.getMessage()); + } + + private SQLException failOpenSession(TException cause) throws Exception { + IoTDBConnectionParams params = + Utils.parseUrl("jdbc:iotdb://127.0.0.1:6667/", new Properties()); + Field paramsField = IoTDBConnection.class.getDeclaredField("params"); + paramsField.setAccessible(true); + paramsField.set(connection, params); + TTransport transport = mock(TTransport.class); + Field transportField = IoTDBConnection.class.getDeclaredField("transport"); + transportField.setAccessible(true); + transportField.set(connection, transport); + connection.setClient(client); + when(client.openSession(any(TSOpenSessionReq.class))).thenThrow(cause); + Method openSession = IoTDBConnection.class.getDeclaredMethod("openSession"); + openSession.setAccessible(true); + + InvocationTargetException invocationException = + assertThrows(InvocationTargetException.class, () -> openSession.invoke(connection)); + + assertTrue(invocationException.getCause() instanceof SQLException); + SQLException exception = (SQLException) invocationException.getCause(); + assertSame(cause, exception.getCause()); + verify(transport).close(); + return exception; + } }
