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

Caideyipi pushed a commit to branch codex/jdbc-driver-info
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/codex/jdbc-driver-info by this 
push:
     new 30ca82e7b4a Reject closed JDBC connection operations
30ca82e7b4a is described below

commit 30ca82e7b4a2d367af9204070d2bba368f2873b3
Author: Caideyipi <[email protected]>
AuthorDate: Tue Jun 9 16:40:14 2026 +0800

    Reject closed JDBC connection operations
---
 .../org/apache/iotdb/jdbc/IoTDBConnection.java     | 63 +++++++++++++++-------
 .../org/apache/iotdb/jdbc/IoTDBConnectionTest.java | 63 ++++++++++++++++++++--
 2 files changed, 102 insertions(+), 24 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 2a9cd3816df..f41eec12cc2 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
@@ -154,11 +154,13 @@ public class IoTDBConnection implements Connection {
 
   @Override
   public boolean isWrapperFor(Class<?> arg0) throws SQLException {
+    checkOpen("isWrapperFor");
     return JdbcWrapperUtils.isWrapperFor(this, arg0);
   }
 
   @Override
   public <T> T unwrap(Class<T> arg0) throws SQLException {
+    checkOpen("unwrap");
     return JdbcWrapperUtils.unwrap(this, arg0);
   }
 
@@ -168,7 +170,8 @@ public class IoTDBConnection implements Connection {
   }
 
   @Override
-  public void clearWarnings() {
+  public void clearWarnings() throws SQLException {
+    checkOpen("clearWarnings");
     warningChain = null;
   }
 
@@ -192,7 +195,9 @@ public class IoTDBConnection implements Connection {
   }
 
   @Override
-  public void commit() throws SQLException {}
+  public void commit() throws SQLException {
+    checkOpen("commit");
+  }
 
   @Override
   public Array createArrayOf(String arg0, Object[] arg1) throws SQLException {
@@ -221,15 +226,14 @@ public class IoTDBConnection implements Connection {
 
   @Override
   public Statement createStatement() throws SQLException {
-    if (isClosed) {
-      throw new SQLException(JdbcMessages.CANNOT_CREATE_STATEMENT_CLOSED);
-    }
+    checkOpen("createStatement");
     return new IoTDBStatement(this, getClient(), sessionId, zoneId, charset, 
queryTimeout);
   }
 
   @Override
   public Statement createStatement(int resultSetType, int resultSetConcurrency)
       throws SQLException {
+    checkOpen("createStatement");
     if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) {
       throw new SQLException(
           String.format(
@@ -253,22 +257,26 @@ public class IoTDBConnection implements Connection {
   }
 
   @Override
-  public boolean getAutoCommit() {
+  public boolean getAutoCommit() throws SQLException {
+    checkOpen("getAutoCommit");
     return autoCommit;
   }
 
   @Override
-  public void setAutoCommit(boolean arg0) {
+  public void setAutoCommit(boolean arg0) throws SQLException {
+    checkOpen("setAutoCommit");
     autoCommit = arg0;
   }
 
   @Override
-  public String getCatalog() {
+  public String getCatalog() throws SQLException {
+    checkOpen("getCatalog");
     return APACHE_IOTDB;
   }
 
   @Override
   public void setCatalog(String arg0) throws SQLException {
+    checkOpen("setCatalog");
     if (getSqlDialect().equals(Constant.TABLE_DIALECT)) {
       if (arg0 == null) {
         throw new SQLException("catalog cannot be null");
@@ -310,7 +318,8 @@ public class IoTDBConnection implements Connection {
   }
 
   @Override
-  public int getHoldability() {
+  public int getHoldability() throws SQLException {
+    checkOpen("getHoldability");
     return ResultSet.HOLD_CURSORS_OVER_COMMIT;
   }
 
@@ -321,9 +330,7 @@ public class IoTDBConnection implements Connection {
 
   @Override
   public DatabaseMetaData getMetaData() throws SQLException {
-    if (isClosed) {
-      throw new SQLException(JdbcMessages.CANNOT_CREATE_STATEMENT_CLOSED);
-    }
+    checkOpen("getMetaData");
     if (getSqlDialect().equals(Constant.TABLE_DIALECT)) {
       return new IoTDBRelationalDatabaseMetadata(this, getClient(), sessionId, 
zoneId);
     }
@@ -331,12 +338,14 @@ public class IoTDBConnection implements Connection {
   }
 
   @Override
-  public int getNetworkTimeout() {
+  public int getNetworkTimeout() throws SQLException {
+    checkOpen("getNetworkTimeout");
     return networkTimeout;
   }
 
   @Override
   public String getSchema() throws SQLException {
+    checkOpen("getSchema");
     if (getSqlDialect().equals(Constant.TABLE_DIALECT)) {
       return getDatabase();
     }
@@ -345,6 +354,7 @@ public class IoTDBConnection implements Connection {
 
   @Override
   public void setSchema(String arg0) throws SQLException {
+    checkOpen("setSchema");
     // changeDefaultDatabase(arg0);
     if (getSqlDialect().equals(Constant.TABLE_DIALECT)) {
       if (arg0 == null) {
@@ -369,7 +379,8 @@ public class IoTDBConnection implements Connection {
   }
 
   @Override
-  public int getTransactionIsolation() {
+  public int getTransactionIsolation() throws SQLException {
+    checkOpen("getTransactionIsolation");
     return Connection.TRANSACTION_NONE;
   }
 
@@ -389,7 +400,8 @@ public class IoTDBConnection implements Connection {
   }
 
   @Override
-  public SQLWarning getWarnings() {
+  public SQLWarning getWarnings() throws SQLException {
+    checkOpen("getWarnings");
     return warningChain;
   }
 
@@ -399,12 +411,14 @@ public class IoTDBConnection implements Connection {
   }
 
   @Override
-  public boolean isReadOnly() {
+  public boolean isReadOnly() throws SQLException {
+    checkOpen("isReadOnly");
     return false;
   }
 
   @Override
   public void setReadOnly(boolean readonly) throws SQLException {
+    checkOpen("setReadOnly");
     if (readonly) {
       throw new SQLException(JdbcMessages.NOT_SUPPORT_READ_ONLY);
     }
@@ -441,6 +455,7 @@ public class IoTDBConnection implements Connection {
 
   @Override
   public PreparedStatement prepareStatement(String sql) throws SQLException {
+    checkOpen("prepareStatement");
     if (getSqlDialect().equals(Constant.TABLE_DIALECT)) {
       return new IoTDBTablePreparedStatement(this, getClient(), sessionId, 
sql, zoneId, charset);
     } else {
@@ -482,12 +497,14 @@ public class IoTDBConnection implements Connection {
   }
 
   @Override
-  public void rollback() {
+  public void rollback() throws SQLException {
+    checkOpen("rollback");
     // do nothing in rollback
   }
 
   @Override
-  public void rollback(Savepoint arg0) {
+  public void rollback(Savepoint arg0) throws SQLException {
+    checkOpen("rollback");
     // do nothing in rollback
   }
 
@@ -554,13 +571,13 @@ public class IoTDBConnection implements Connection {
           DeepCopyRpcTransportFactory.INSTANCE.getTransport(
               params.getHost(),
               params.getPort(),
-              getNetworkTimeout(),
+              networkTimeout,
               params.getTrustStore(),
               params.getTrustStorePwd());
     } else {
       transport =
           DeepCopyRpcTransportFactory.INSTANCE.getTransport(
-              params.getHost(), params.getPort(), getNetworkTimeout());
+              params.getHost(), params.getPort(), networkTimeout);
     }
     if (!transport.isOpen()) {
       transport.open();
@@ -720,4 +737,10 @@ public class IoTDBConnection implements Connection {
   public String getDatabase() {
     return params.getDb().orElse(null);
   }
+
+  private void checkOpen(String action) throws SQLException {
+    if (isClosed) {
+      throw new 
SQLException(String.format(JdbcMessages.CANNOT_AFTER_CONNECTION_CLOSED, 
action));
+    }
+  }
 }
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 2064a4027f6..8e0a77ded50 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
@@ -34,6 +34,7 @@ import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.lang.reflect.Field;
 import java.sql.Connection;
 import java.sql.ResultSet;
 import java.sql.SQLClientInfoException;
@@ -129,6 +130,7 @@ public class IoTDBConnectionTest {
             return Constant.TABLE_DIALECT;
           }
         };
+    openConnection(tableConnection);
 
     assertThrows(SQLException.class, () -> tableConnection.setCatalog(null));
     assertThrows(SQLException.class, () -> tableConnection.setSchema(null));
@@ -166,9 +168,18 @@ public class IoTDBConnectionTest {
   }
 
   @Test
-  public void testStandardConnectionStateMethods() throws SQLException {
+  public void testStandardConnectionStateMethods() throws Exception {
+    openConnection(connection);
+
+    assertFalse(connection.getAutoCommit());
+    connection.setAutoCommit(true);
+    assertTrue(connection.getAutoCommit());
+    assertEquals("Apache IoTDB", connection.getCatalog());
     assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, 
connection.getHoldability());
-    assertFalse(connection.isValid(0));
+    assertEquals(Connection.TRANSACTION_NONE, 
connection.getTransactionIsolation());
+    assertFalse(connection.isReadOnly());
+    connection.setReadOnly(false);
+    assertTrue(connection.isValid(0));
   }
 
   @Test(expected = SQLException.class)
@@ -177,7 +188,9 @@ public class IoTDBConnectionTest {
   }
 
   @Test
-  public void testWrapperMethods() throws SQLException {
+  public void testWrapperMethods() throws Exception {
+    openConnection(connection);
+
     assertTrue(connection.isWrapperFor(IoTDBConnection.class));
     assertTrue(connection.isWrapperFor(Connection.class));
     assertFalse(connection.isWrapperFor(String.class));
@@ -187,7 +200,49 @@ public class IoTDBConnectionTest {
   }
 
   @Test(expected = SQLException.class)
-  public void testUnwrapRejectsUnsupportedClass() throws SQLException {
+  public void testUnwrapRejectsUnsupportedClass() throws Exception {
+    openConnection(connection);
+
     connection.unwrap(String.class);
   }
+
+  @Test
+  public void testClosedConnectionRejectsOperations() throws SQLException {
+    assertTrue(connection.isClosed());
+    assertFalse(connection.isValid(0));
+
+    assertThrows(SQLException.class, () -> 
connection.isWrapperFor(Connection.class));
+    assertThrows(SQLException.class, () -> 
connection.unwrap(Connection.class));
+    assertThrows(SQLException.class, () -> connection.clearWarnings());
+    assertThrows(SQLException.class, () -> connection.commit());
+    assertThrows(SQLException.class, () -> connection.createStatement());
+    assertThrows(
+        SQLException.class,
+        () -> connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, 
ResultSet.CONCUR_READ_ONLY));
+    assertThrows(SQLException.class, () -> connection.prepareStatement("SELECT 
?"));
+    assertThrows(SQLException.class, () -> connection.getAutoCommit());
+    assertThrows(SQLException.class, () -> connection.setAutoCommit(true));
+    assertThrows(SQLException.class, () -> connection.getCatalog());
+    assertThrows(SQLException.class, () -> connection.setCatalog("root"));
+    assertThrows(SQLException.class, () -> connection.getHoldability());
+    assertThrows(SQLException.class, () -> connection.getMetaData());
+    assertThrows(SQLException.class, () -> connection.getNetworkTimeout());
+    assertThrows(SQLException.class, () -> connection.getSchema());
+    assertThrows(SQLException.class, () -> connection.setSchema("root"));
+    assertThrows(SQLException.class, () -> 
connection.getTransactionIsolation());
+    assertThrows(SQLException.class, () -> connection.getWarnings());
+    assertThrows(SQLException.class, () -> connection.isReadOnly());
+    assertThrows(SQLException.class, () -> connection.setReadOnly(false));
+    assertThrows(SQLException.class, () -> connection.rollback());
+  }
+
+  private void openConnection(IoTDBConnection target) {
+    try {
+      Field isClosedField = IoTDBConnection.class.getDeclaredField("isClosed");
+      isClosedField.setAccessible(true);
+      isClosedField.setBoolean(target, false);
+    } catch (ReflectiveOperationException e) {
+      throw new AssertionError(e);
+    }
+  }
 }

Reply via email to