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 e180e1ffbaf Improve JDBC standard interface behavior
e180e1ffbaf is described below

commit e180e1ffbaf69d9e655fdd0e93f29ccf3232e7e7
Author: Caideyipi <[email protected]>
AuthorDate: Mon Jun 8 18:34:28 2026 +0800

    Improve JDBC standard interface behavior
---
 .../iotdb/jdbc/IoTDBAbstractDatabaseMetadata.java  |  4 +-
 .../org/apache/iotdb/jdbc/IoTDBConnection.java     |  4 +-
 .../org/apache/iotdb/jdbc/IoTDBDataSource.java     | 64 +++++++++-------
 .../apache/iotdb/jdbc/IoTDBDataSourceFactory.java  | 11 ++-
 .../org/apache/iotdb/jdbc/IoTDBJDBCResultSet.java  |  4 +-
 .../apache/iotdb/jdbc/IoTDBPreparedStatement.java  |  6 +-
 .../org/apache/iotdb/jdbc/IoTDBResultMetadata.java |  4 +-
 .../java/org/apache/iotdb/jdbc/IoTDBStatement.java |  4 +-
 .../iotdb/jdbc/IoTDBTablePreparedStatement.java    |  6 +-
 .../org/apache/iotdb/jdbc/IoTDBURLException.java   |  4 +
 ...oTDBURLException.java => JdbcWrapperUtils.java} | 17 ++++-
 .../src/main/java/org/apache/iotdb/jdbc/Utils.java | 87 +++++++++++++++++++---
 .../org/apache/iotdb/jdbc/IoTDBConnectionTest.java | 19 +++++
 .../iotdb/jdbc/IoTDBDataSourceFactoryTest.java     | 29 ++++++++
 .../iotdb/jdbc/IoTDBDatabaseMetadataTest.java      | 18 +++++
 .../apache/iotdb/jdbc/IoTDBJDBCResultSetTest.java  |  7 ++
 .../iotdb/jdbc/IoTDBPreparedStatementTest.java     | 17 +++++
 .../apache/iotdb/jdbc/IoTDBResultMetadataTest.java | 20 +++++
 .../org/apache/iotdb/jdbc/IoTDBStatementTest.java  | 21 ++++++
 .../jdbc/IoTDBTablePreparedStatementTest.java      | 19 +++++
 .../test/java/org/apache/iotdb/jdbc/UtilsTest.java | 24 ++++++
 21 files changed, 331 insertions(+), 58 deletions(-)

diff --git 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBAbstractDatabaseMetadata.java
 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBAbstractDatabaseMetadata.java
index 3928657b933..5ffaea704c9 100644
--- 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBAbstractDatabaseMetadata.java
+++ 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBAbstractDatabaseMetadata.java
@@ -2858,11 +2858,11 @@ public abstract class IoTDBAbstractDatabaseMetadata 
implements DatabaseMetaData
 
   @Override
   public <T> T unwrap(Class<T> arg0) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    return JdbcWrapperUtils.unwrap(this, arg0);
   }
 
   @Override
   public boolean isWrapperFor(Class<?> arg0) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    return JdbcWrapperUtils.isWrapperFor(this, arg0);
   }
 }
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 c0f239c2625..66d17d43d79 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
@@ -157,12 +157,12 @@ public class IoTDBConnection implements Connection {
 
   @Override
   public boolean isWrapperFor(Class<?> arg0) throws SQLException {
-    throw new SQLException(JdbcMessages.NOT_SUPPORT_IS_WRAPPER_FOR);
+    return JdbcWrapperUtils.isWrapperFor(this, arg0);
   }
 
   @Override
   public <T> T unwrap(Class<T> arg0) throws SQLException {
-    throw new SQLException(JdbcMessages.NOT_SUPPORT_UNWRAP);
+    return JdbcWrapperUtils.unwrap(this, arg0);
   }
 
   @Override
diff --git 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDataSource.java 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDataSource.java
index c3f880565a3..34645c78c49 100644
--- a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDataSource.java
+++ b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDataSource.java
@@ -40,6 +40,8 @@ public class IoTDBDataSource implements DataSource {
   private String password;
   private Properties properties;
   private Integer port = 6667;
+  private PrintWriter logWriter;
+  private int loginTimeout;
 
   public IoTDBDataSource() {
     properties = new Properties();
@@ -91,45 +93,38 @@ public class IoTDBDataSource implements DataSource {
 
   @Override
   public Connection getConnection() throws SQLException {
-    try {
-      return new IoTDBConnection(url, properties);
-    } catch (TTransportException e) {
-      LOGGER.error(JdbcMessages.GET_CONNECTION_ERROR, e);
-    }
-    return null;
+    return createConnection((Properties) properties.clone());
   }
 
   @Override
   public Connection getConnection(String username, String password) throws 
SQLException {
-    try {
-      Properties newProp = new Properties();
-      setProperty(newProp, Config.AUTH_USER, username);
-      setProperty(newProp, Config.AUTH_PASSWORD, password);
-      return new IoTDBConnection(url, newProp);
-    } catch (TTransportException e) {
-      LOGGER.error(JdbcMessages.GET_CONNECTION_ERROR, e);
-    }
-    return null;
+    Properties newProp = (Properties) properties.clone();
+    setProperty(newProp, Config.AUTH_USER, username);
+    setProperty(newProp, Config.AUTH_PASSWORD, password);
+    return createConnection(newProp);
   }
 
   @Override
   public PrintWriter getLogWriter() {
-    return null;
+    return logWriter;
   }
 
   @Override
   public void setLogWriter(PrintWriter printWriter) {
-    // Do nothing
+    this.logWriter = printWriter;
   }
 
   @Override
-  public void setLoginTimeout(int i) {
-    // Do nothing
+  public void setLoginTimeout(int i) throws SQLException {
+    if (i < 0) {
+      throw new SQLException("loginTimeout must be >= 0");
+    }
+    this.loginTimeout = i;
   }
 
   @Override
   public int getLoginTimeout() {
-    return 0;
+    return loginTimeout;
   }
 
   @Override
@@ -139,15 +134,34 @@ public class IoTDBDataSource implements DataSource {
 
   @Override
   public <T> T unwrap(Class<T> aClass) throws SQLException {
-    if (isWrapperFor(aClass)) {
-      return aClass.cast(this);
-    }
-    throw new SQLException(JdbcMessages.CANNOT_UNWRAP_TO + aClass);
+    return JdbcWrapperUtils.unwrap(this, aClass);
   }
 
   @Override
   public boolean isWrapperFor(Class<?> aClass) {
-    return aClass != null && aClass.isInstance(this);
+    return JdbcWrapperUtils.isWrapperFor(this, aClass);
+  }
+
+  private Connection createConnection(Properties connectionProperties) throws 
SQLException {
+    applyLoginTimeout(connectionProperties);
+    try {
+      return new IoTDBConnection(url, connectionProperties);
+    } catch (TTransportException e) {
+      LOGGER.error(JdbcMessages.GET_CONNECTION_ERROR, e);
+      throw new SQLException(
+          "Connection Error, please check whether the network is available or 
the server"
+              + " has started.",
+          e);
+    }
+  }
+
+  private void applyLoginTimeout(Properties connectionProperties) {
+    if (loginTimeout <= 0 || 
connectionProperties.containsKey(Config.NETWORK_TIMEOUT)) {
+      return;
+    }
+    long timeoutInMs = (long) loginTimeout * 1000;
+    connectionProperties.setProperty(
+        Config.NETWORK_TIMEOUT, String.valueOf(Math.min(timeoutInMs, 
Integer.MAX_VALUE)));
   }
 
   private void setProperty(String key, String value) {
diff --git 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDataSourceFactory.java
 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDataSourceFactory.java
index f81245d16b8..228ad925af5 100644
--- 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDataSourceFactory.java
+++ 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDataSourceFactory.java
@@ -29,6 +29,8 @@ import javax.sql.DataSource;
 import javax.sql.XADataSource;
 
 import java.sql.Driver;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
 import java.util.Properties;
 
 public class IoTDBDataSourceFactory implements DataSourceFactory {
@@ -67,13 +69,14 @@ public class IoTDBDataSourceFactory implements 
DataSourceFactory {
   }
 
   @Override
-  public ConnectionPoolDataSource createConnectionPoolDataSource(Properties 
properties) {
-    return null;
+  public ConnectionPoolDataSource createConnectionPoolDataSource(Properties 
properties)
+      throws SQLException {
+    throw new 
SQLFeatureNotSupportedException(JdbcMessages.METHOD_NOT_SUPPORTED);
   }
 
   @Override
-  public XADataSource createXADataSource(Properties properties) {
-    return null;
+  public XADataSource createXADataSource(Properties properties) throws 
SQLException {
+    throw new 
SQLFeatureNotSupportedException(JdbcMessages.METHOD_NOT_SUPPORTED);
   }
 
   @Override
diff --git 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBJDBCResultSet.java 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBJDBCResultSet.java
index 3ea3c52320d..9ed67182ce8 100644
--- 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBJDBCResultSet.java
+++ 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBJDBCResultSet.java
@@ -182,12 +182,12 @@ public class IoTDBJDBCResultSet implements ResultSet {
 
   @Override
   public boolean isWrapperFor(Class<?> iface) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+    return JdbcWrapperUtils.isWrapperFor(this, iface);
   }
 
   @Override
   public <T> T unwrap(Class<T> iface) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+    return JdbcWrapperUtils.unwrap(this, iface);
   }
 
   @Override
diff --git 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBPreparedStatement.java
 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBPreparedStatement.java
index 80f6530c18a..647b74a9e1a 100644
--- 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBPreparedStatement.java
+++ 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBPreparedStatement.java
@@ -195,13 +195,13 @@ public class IoTDBPreparedStatement extends 
IoTDBStatement implements PreparedSt
       }
 
       @Override
-      public <T> T unwrap(Class<T> iface) {
-        return null;
+      public <T> T unwrap(Class<T> iface) throws SQLException {
+        return JdbcWrapperUtils.unwrap(this, iface);
       }
 
       @Override
       public boolean isWrapperFor(Class<?> iface) {
-        return false;
+        return JdbcWrapperUtils.isWrapperFor(this, iface);
       }
     };
   }
diff --git 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBResultMetadata.java
 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBResultMetadata.java
index 59279d88465..4fba689c3e5 100644
--- 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBResultMetadata.java
+++ 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBResultMetadata.java
@@ -70,12 +70,12 @@ public class IoTDBResultMetadata implements 
ResultSetMetaData {
 
   @Override
   public boolean isWrapperFor(Class<?> arg0) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+    return JdbcWrapperUtils.isWrapperFor(this, arg0);
   }
 
   @Override
   public <T> T unwrap(Class<T> arg0) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+    return JdbcWrapperUtils.unwrap(this, arg0);
   }
 
   @SuppressWarnings({
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 1c6ce8c0e9b..49818558b59 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
@@ -182,12 +182,12 @@ public class IoTDBStatement implements Statement {
 
   @Override
   public boolean isWrapperFor(Class<?> iface) {
-    return false;
+    return JdbcWrapperUtils.isWrapperFor(this, iface);
   }
 
   @Override
   public <T> T unwrap(Class<T> iface) throws SQLException {
-    throw new SQLException(JdbcMessages.CANNOT_UNWRAP_TO + iface);
+    return JdbcWrapperUtils.unwrap(this, iface);
   }
 
   @Override
diff --git 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBTablePreparedStatement.java
 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBTablePreparedStatement.java
index 674ec164691..79312bc5f84 100644
--- 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBTablePreparedStatement.java
+++ 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBTablePreparedStatement.java
@@ -322,13 +322,13 @@ public class IoTDBTablePreparedStatement extends 
IoTDBStatement implements Prepa
       }
 
       @Override
-      public <T> T unwrap(Class<T> iface) {
-        return null;
+      public <T> T unwrap(Class<T> iface) throws SQLException {
+        return JdbcWrapperUtils.unwrap(this, iface);
       }
 
       @Override
       public boolean isWrapperFor(Class<?> iface) {
-        return false;
+        return JdbcWrapperUtils.isWrapperFor(this, iface);
       }
     };
   }
diff --git 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBURLException.java 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBURLException.java
index 81b12077e8c..a704218eb46 100644
--- 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBURLException.java
+++ 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBURLException.java
@@ -28,4 +28,8 @@ public class IoTDBURLException extends SQLException {
   public IoTDBURLException(String reason) {
     super(reason);
   }
+
+  public IoTDBURLException(String reason, Throwable cause) {
+    super(reason, cause);
+  }
 }
diff --git 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBURLException.java 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/JdbcWrapperUtils.java
similarity index 65%
copy from 
iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBURLException.java
copy to 
iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/JdbcWrapperUtils.java
index 81b12077e8c..8f9148d0e1e 100644
--- 
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBURLException.java
+++ 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/JdbcWrapperUtils.java
@@ -19,13 +19,22 @@
 
 package org.apache.iotdb.jdbc;
 
+import org.apache.iotdb.jdbc.i18n.JdbcMessages;
+
 import java.sql.SQLException;
 
-public class IoTDBURLException extends SQLException {
+final class JdbcWrapperUtils {
 
-  private static final long serialVersionUID = -5071922897222027267L;
+  static boolean isWrapperFor(Object wrapper, Class<?> iface) {
+    return iface != null && iface.isInstance(wrapper);
+  }
 
-  public IoTDBURLException(String reason) {
-    super(reason);
+  static <T> T unwrap(Object wrapper, Class<T> iface) throws SQLException {
+    if (isWrapperFor(wrapper, iface)) {
+      return iface.cast(wrapper);
+    }
+    throw new SQLException(JdbcMessages.CANNOT_UNWRAP_TO + iface);
   }
+
+  private JdbcWrapperUtils() {}
 }
diff --git a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/Utils.java 
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/Utils.java
index 39b72df9a59..873e01e7d21 100644
--- a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/Utils.java
+++ b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/Utils.java
@@ -115,26 +115,25 @@ public class Utils {
     }
     if (properties.containsKey(Config.DEFAULT_BUFFER_CAPACITY)) {
       params.setThriftDefaultBufferSize(
-          
Integer.parseInt(properties.getProperty(Config.DEFAULT_BUFFER_CAPACITY)));
+          parseIntegerProperty(properties, Config.DEFAULT_BUFFER_CAPACITY));
     }
     if (properties.containsKey(Config.THRIFT_FRAME_MAX_SIZE)) {
-      params.setThriftMaxFrameSize(
-          
Integer.parseInt(properties.getProperty(Config.THRIFT_FRAME_MAX_SIZE)));
+      params.setThriftMaxFrameSize(parseIntegerProperty(properties, 
Config.THRIFT_FRAME_MAX_SIZE));
     }
     if (properties.containsKey(Config.VERSION)) {
-      
params.setVersion(Constant.Version.valueOf(properties.getProperty(Config.VERSION)));
+      params.setVersion(parseVersionProperty(properties));
     }
     if (properties.containsKey(Config.NETWORK_TIMEOUT)) {
-      
params.setNetworkTimeout(Integer.parseInt(properties.getProperty(Config.NETWORK_TIMEOUT)));
+      params.setNetworkTimeout(parseIntegerProperty(properties, 
Config.NETWORK_TIMEOUT));
     }
     if (properties.containsKey(Config.TIME_ZONE)) {
-      params.setTimeZone(properties.getProperty(Config.TIME_ZONE));
+      params.setTimeZone(validateTimeZoneProperty(properties));
     }
     if (properties.containsKey(Config.CHARSET)) {
-      params.setCharset(properties.getProperty(Config.CHARSET));
+      params.setCharset(validateCharsetProperty(properties));
     }
     if (properties.containsKey(Config.USE_SSL)) {
-      
params.setUseSSL(Boolean.parseBoolean(properties.getProperty(Config.USE_SSL)));
+      params.setUseSSL(parseBooleanProperty(properties));
     }
     if (properties.containsKey(Config.TRUST_STORE)) {
       params.setTrustStore(properties.getProperty(Config.TRUST_STORE));
@@ -143,7 +142,7 @@ public class Utils {
       params.setTrustStorePwd(properties.getProperty(Config.TRUST_STORE_PWD));
     }
     if (properties.containsKey(Config.SQL_DIALECT)) {
-      params.setSqlDialect(properties.getProperty(Config.SQL_DIALECT));
+      params.setSqlDialect(validateSqlDialectProperty(properties));
     }
 
     return params;
@@ -238,5 +237,75 @@ public class Utils {
     return "true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value);
   }
 
+  private static int parseIntegerProperty(Properties properties, String key)
+      throws IoTDBURLException {
+    String value = getPropertyValue(properties, key);
+    try {
+      return Integer.parseInt(value);
+    } catch (NumberFormatException e) {
+      throw invalidPropertyValue(key, value, e);
+    }
+  }
+
+  private static Constant.Version parseVersionProperty(Properties properties)
+      throws IoTDBURLException {
+    String value = getPropertyValue(properties, Config.VERSION);
+    try {
+      return Constant.Version.valueOf(value);
+    } catch (IllegalArgumentException e) {
+      throw invalidPropertyValue(Config.VERSION, value, e);
+    }
+  }
+
+  private static boolean parseBooleanProperty(Properties properties) throws 
IoTDBURLException {
+    String value = getPropertyValue(properties, Config.USE_SSL);
+    if (!isBoolean(value)) {
+      throw invalidPropertyValue(Config.USE_SSL, value, null);
+    }
+    return Boolean.parseBoolean(value);
+  }
+
+  private static String validateTimeZoneProperty(Properties properties) throws 
IoTDBURLException {
+    String value = getPropertyValue(properties, Config.TIME_ZONE);
+    try {
+      ZoneId.of(value);
+    } catch (DateTimeException e) {
+      throw invalidPropertyValue(Config.TIME_ZONE, value, e);
+    }
+    return value;
+  }
+
+  private static String validateCharsetProperty(Properties properties) throws 
IoTDBURLException {
+    String value = getPropertyValue(properties, Config.CHARSET);
+    try {
+      Charset.forName(value);
+    } catch (Exception e) {
+      throw invalidPropertyValue(Config.CHARSET, value, e);
+    }
+    return value;
+  }
+
+  private static String validateSqlDialectProperty(Properties properties) 
throws IoTDBURLException {
+    String value = getPropertyValue(properties, Config.SQL_DIALECT);
+    if (!Constant.TREE.equals(value) && !Constant.TABLE.equals(value)) {
+      throw invalidPropertyValue(Config.SQL_DIALECT, value, null);
+    }
+    return value;
+  }
+
+  private static String getPropertyValue(Properties properties, String key)
+      throws IoTDBURLException {
+    String value = properties.getProperty(key);
+    if (value == null) {
+      throw invalidPropertyValue(key, null, null);
+    }
+    return value;
+  }
+
+  private static IoTDBURLException invalidPropertyValue(String key, String 
value, Throwable cause) {
+    return new IoTDBURLException(
+        "Invalid value for JDBC connection property " + key + ": " + value, 
cause);
+  }
+
   private Utils() {}
 }
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 2919e51d265..b1668dda5b2 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.sql.Connection;
 import java.sql.SQLClientInfoException;
 import java.sql.SQLException;
 import java.time.ZoneId;
@@ -41,7 +42,10 @@ import java.util.ArrayList;
 import java.util.List;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.when;
 
@@ -119,4 +123,19 @@ public class IoTDBConnectionTest {
     connection.setQueryTimeout(60);
     Assert.assertEquals(60, connection.getQueryTimeout());
   }
+
+  @Test
+  public void testWrapperMethods() throws SQLException {
+    assertTrue(connection.isWrapperFor(IoTDBConnection.class));
+    assertTrue(connection.isWrapperFor(Connection.class));
+    assertFalse(connection.isWrapperFor(String.class));
+    assertFalse(connection.isWrapperFor(null));
+    assertSame(connection, connection.unwrap(IoTDBConnection.class));
+    assertSame(connection, connection.unwrap(Connection.class));
+  }
+
+  @Test(expected = SQLException.class)
+  public void testUnwrapRejectsUnsupportedClass() throws SQLException {
+    connection.unwrap(String.class);
+  }
 }
diff --git 
a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDataSourceFactoryTest.java
 
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDataSourceFactoryTest.java
index f4073b24003..b2f3ad4926f 100644
--- 
a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDataSourceFactoryTest.java
+++ 
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDataSourceFactoryTest.java
@@ -24,6 +24,8 @@ import org.osgi.service.jdbc.DataSourceFactory;
 
 import javax.sql.DataSource;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.sql.SQLException;
 import java.sql.SQLFeatureNotSupportedException;
 import java.util.Properties;
@@ -105,6 +107,33 @@ public class IoTDBDataSourceFactoryTest {
     new IoTDBDataSource().getParentLogger();
   }
 
+  @Test(expected = SQLFeatureNotSupportedException.class)
+  public void testConnectionPoolDataSourceIsUnsupported() throws SQLException {
+    new IoTDBDataSourceFactory().createConnectionPoolDataSource(null);
+  }
+
+  @Test(expected = SQLFeatureNotSupportedException.class)
+  public void testXADataSourceIsUnsupported() throws SQLException {
+    new IoTDBDataSourceFactory().createXADataSource(null);
+  }
+
+  @Test
+  public void testDataSourceStoresLogWriterAndLoginTimeout() throws 
SQLException {
+    IoTDBDataSource dataSource = new IoTDBDataSource();
+    PrintWriter logWriter = new PrintWriter(new StringWriter());
+
+    dataSource.setLogWriter(logWriter);
+    dataSource.setLoginTimeout(10);
+
+    assertSame(logWriter, dataSource.getLogWriter());
+    assertEquals(10, dataSource.getLoginTimeout());
+  }
+
+  @Test(expected = SQLException.class)
+  public void testDataSourceRejectsNegativeLoginTimeout() throws SQLException {
+    new IoTDBDataSource().setLoginTimeout(-1);
+  }
+
   @Test(expected = SQLException.class)
   public void testDataSourceConnectionWithCredentialsThrowsInvalidUrl() throws 
SQLException {
     IoTDBDataSource dataSource = new IoTDBDataSource();
diff --git 
a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadataTest.java
 
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadataTest.java
index ab29a141399..804f3f89d6b 100644
--- 
a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadataTest.java
+++ 
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadataTest.java
@@ -48,6 +48,9 @@ import java.util.List;
 import java.util.Map;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.when;
 
@@ -86,6 +89,21 @@ public class IoTDBDatabaseMetadataTest {
     Assert.assertEquals("PKTABLE_CAT", 
resultSet.getMetaData().getColumnName(2));
   }
 
+  @Test
+  public void testWrapperMethods() throws SQLException {
+    assertTrue(databaseMetaData.isWrapperFor(IoTDBDatabaseMetadata.class));
+    assertTrue(databaseMetaData.isWrapperFor(DatabaseMetaData.class));
+    assertFalse(databaseMetaData.isWrapperFor(String.class));
+    assertFalse(databaseMetaData.isWrapperFor(null));
+    assertSame(databaseMetaData, 
databaseMetaData.unwrap(IoTDBDatabaseMetadata.class));
+    assertSame(databaseMetaData, 
databaseMetaData.unwrap(DatabaseMetaData.class));
+  }
+
+  @Test(expected = SQLException.class)
+  public void testUnwrapRejectsUnsupportedClass() throws SQLException {
+    databaseMetaData.unwrap(String.class);
+  }
+
   @Test
   public void testGetBestRowIdentifier() throws SQLException {
     ResultSet resultSet = databaseMetaData.getBestRowIdentifier(null, null, 
null, 0, true);
diff --git 
a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBJDBCResultSetTest.java
 
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBJDBCResultSetTest.java
index 3fb60b8760d..854709fddbb 100644
--- 
a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBJDBCResultSetTest.java
+++ 
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBJDBCResultSetTest.java
@@ -201,6 +201,13 @@ public class IoTDBJDBCResultSetTest {
     fetchResultsResp.hasResultSet = true; // at the first time to fetch
 
     try (ResultSet resultSet = statement.getResultSet()) {
+      Assert.assertTrue(resultSet.isWrapperFor(IoTDBJDBCResultSet.class));
+      Assert.assertTrue(resultSet.isWrapperFor(ResultSet.class));
+      Assert.assertFalse(resultSet.isWrapperFor(String.class));
+      Assert.assertFalse(resultSet.isWrapperFor(null));
+      Assert.assertSame(resultSet, resultSet.unwrap(IoTDBJDBCResultSet.class));
+      Assert.assertSame(resultSet, resultSet.unwrap(ResultSet.class));
+
       // check columnInfoMap
       Assert.assertEquals(1, resultSet.findColumn("Time"));
       Assert.assertEquals(2, resultSet.findColumn("root.vehicle.d0.s2"));
diff --git 
a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBPreparedStatementTest.java
 
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBPreparedStatementTest.java
index f80b8a83936..acc6b523b5e 100644
--- 
a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBPreparedStatementTest.java
+++ 
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBPreparedStatementTest.java
@@ -31,6 +31,7 @@ import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.sql.ParameterMetaData;
 import java.sql.SQLException;
 import java.sql.Timestamp;
 import java.sql.Types;
@@ -38,7 +39,9 @@ import java.time.ZoneId;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+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.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -81,6 +84,20 @@ public class IoTDBPreparedStatementTest {
         argument.getValue().getStatement());
   }
 
+  @SuppressWarnings("resource")
+  @Test
+  public void testParameterMetadataWrapperMethods() throws Exception {
+    IoTDBPreparedStatement ps =
+        new IoTDBPreparedStatement(connection, client, sessionId, "SELECT ?", 
zoneId);
+    ParameterMetaData metadata = ps.getParameterMetaData();
+
+    assertTrue(metadata.isWrapperFor(ParameterMetaData.class));
+    assertFalse(metadata.isWrapperFor(String.class));
+    assertFalse(metadata.isWrapperFor(null));
+    assertSame(metadata, metadata.unwrap(ParameterMetaData.class));
+    assertThrows(SQLException.class, () -> metadata.unwrap(String.class));
+  }
+
   @SuppressWarnings("resource")
   @Test
   public void unusedArgument() throws SQLException {
diff --git 
a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBResultMetadataTest.java
 
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBResultMetadataTest.java
index dc9869bddda..b9e5b3dfedb 100644
--- 
a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBResultMetadataTest.java
+++ 
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBResultMetadataTest.java
@@ -23,6 +23,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
 import java.sql.Types;
 import java.util.ArrayList;
@@ -32,6 +33,7 @@ import java.util.List;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
 public class IoTDBResultMetadataTest {
@@ -173,4 +175,22 @@ public class IoTDBResultMetadataTest {
       assertEquals(metadata.getColumnType(i + 1), types[i - 1]);
     }
   }
+
+  @Test
+  public void testWrapperMethods() throws SQLException {
+    metadata = new IoTDBResultMetadata(false, null, "QUERY", null, null, 
false);
+
+    assertTrue(metadata.isWrapperFor(IoTDBResultMetadata.class));
+    assertTrue(metadata.isWrapperFor(ResultSetMetaData.class));
+    assertFalse(metadata.isWrapperFor(String.class));
+    assertFalse(metadata.isWrapperFor(null));
+    assertSame(metadata, metadata.unwrap(IoTDBResultMetadata.class));
+    assertSame(metadata, metadata.unwrap(ResultSetMetaData.class));
+  }
+
+  @Test(expected = SQLException.class)
+  public void testUnwrapRejectsUnsupportedClass() throws SQLException {
+    metadata = new IoTDBResultMetadata(false, null, "QUERY", null, null, 
false);
+    metadata.unwrap(String.class);
+  }
 }
diff --git 
a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBStatementTest.java 
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBStatementTest.java
index 5cfd5342e05..95973222498 100644
--- 
a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBStatementTest.java
+++ 
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBStatementTest.java
@@ -33,9 +33,13 @@ import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 import java.sql.SQLException;
+import java.sql.Statement;
 import java.time.ZoneId;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.when;
 
@@ -106,4 +110,21 @@ public class IoTDBStatementTest {
     statement.setQueryTimeout(100);
     Assert.assertEquals(100, statement.getQueryTimeout());
   }
+
+  @Test
+  public void testWrapperMethods() throws SQLException {
+    IoTDBStatement statement = new IoTDBStatement(connection, client, 
sessionId, zoneID);
+
+    assertTrue(statement.isWrapperFor(IoTDBStatement.class));
+    assertTrue(statement.isWrapperFor(Statement.class));
+    assertFalse(statement.isWrapperFor(String.class));
+    assertFalse(statement.isWrapperFor(null));
+    assertSame(statement, statement.unwrap(IoTDBStatement.class));
+    assertSame(statement, statement.unwrap(Statement.class));
+  }
+
+  @Test(expected = SQLException.class)
+  public void testUnwrapRejectsUnsupportedClass() throws SQLException {
+    new IoTDBStatement(connection, client, sessionId, 
zoneID).unwrap(String.class);
+  }
 }
diff --git 
a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBTablePreparedStatementTest.java
 
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBTablePreparedStatementTest.java
index dd1c7ecbcb2..80aa9fa32af 100644
--- 
a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBTablePreparedStatementTest.java
+++ 
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBTablePreparedStatementTest.java
@@ -35,8 +35,13 @@ import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
+import java.sql.ParameterMetaData;
+import java.sql.SQLException;
 import java.time.ZoneId;
 
+import static org.junit.Assert.assertFalse;
+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.Mockito.verify;
@@ -111,6 +116,20 @@ public class IoTDBTablePreparedStatementTest {
 
   // ========== Table Model SQL Injection Prevention Tests ==========
 
+  @SuppressWarnings("resource")
+  @Test
+  public void testParameterMetadataWrapperMethods() throws Exception {
+    IoTDBTablePreparedStatement ps =
+        new IoTDBTablePreparedStatement(connection, client, sessionId, "SELECT 
?", zoneId);
+    ParameterMetaData metadata = ps.getParameterMetaData();
+
+    assertTrue(metadata.isWrapperFor(ParameterMetaData.class));
+    assertFalse(metadata.isWrapperFor(String.class));
+    assertFalse(metadata.isWrapperFor(null));
+    assertSame(metadata, metadata.unwrap(ParameterMetaData.class));
+    assertThrows(SQLException.class, () -> metadata.unwrap(String.class));
+  }
+
   @SuppressWarnings("resource")
   @Test
   public void testTableModelLoginInjectionWithComment() throws Exception {
diff --git 
a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/UtilsTest.java 
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/UtilsTest.java
index e8241dd6aa2..9927d050cb9 100644
--- a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/UtilsTest.java
+++ b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/UtilsTest.java
@@ -213,4 +213,28 @@ public class UtilsTest {
   public void testParseUrlParamRejectsInvalidSqlDialectValue() throws 
IoTDBURLException {
     Utils.parseUrl("jdbc:iotdb://127.0.0.1:6667?sql_dialect=bad", new 
Properties());
   }
+
+  @Test
+  public void testParseUrlRejectsInvalidConnectionProperties() {
+    assertInvalidProperty(Config.DEFAULT_BUFFER_CAPACITY, "bad");
+    assertInvalidProperty(Config.THRIFT_FRAME_MAX_SIZE, "bad");
+    assertInvalidProperty(Config.VERSION, "bad");
+    assertInvalidProperty(Config.NETWORK_TIMEOUT, "bad");
+    assertInvalidProperty(Config.TIME_ZONE, "bad-time-zone");
+    assertInvalidProperty(Config.CHARSET, "bad-charset");
+    assertInvalidProperty(Config.USE_SSL, "bad");
+    assertInvalidProperty(Config.SQL_DIALECT, "bad");
+  }
+
+  private static void assertInvalidProperty(String key, String value) {
+    Properties properties = new Properties();
+    properties.setProperty(key, value);
+    try {
+      Utils.parseUrl("jdbc:iotdb://127.0.0.1:6667", properties);
+    } catch (IoTDBURLException e) {
+      assertTrue(e.getMessage().contains(key));
+      return;
+    }
+    fail("Expected IoTDBURLException for invalid property " + key);
+  }
 }


Reply via email to