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 66e88f2dfc8 Fix JDBC URL and DataSource edge cases
66e88f2dfc8 is described below
commit 66e88f2dfc83eeae523eb49f73b8b1d92da6bdc1
Author: Caideyipi <[email protected]>
AuthorDate: Tue Jun 9 10:18:21 2026 +0800
Fix JDBC URL and DataSource edge cases
---
.../org/apache/iotdb/jdbc/IoTDBConnection.java | 27 ++---
.../apache/iotdb/jdbc/IoTDBConnectionParams.java | 9 ++
.../org/apache/iotdb/jdbc/IoTDBDataSource.java | 86 ++++++++++++++--
.../apache/iotdb/jdbc/IoTDBDataSourceFactory.java | 80 ++++++++++++++-
.../java/org/apache/iotdb/jdbc/IoTDBDriver.java | 13 ++-
.../org/apache/iotdb/jdbc/IoTDBJDBCResultSet.java | 2 +-
.../java/org/apache/iotdb/jdbc/IoTDBStatement.java | 6 +-
.../src/main/java/org/apache/iotdb/jdbc/Utils.java | 109 +++++++++++++++------
.../org/apache/iotdb/jdbc/IoTDBConnectionTest.java | 12 +++
.../iotdb/jdbc/IoTDBDataSourceFactoryTest.java | 63 +++++++++++-
.../org/apache/iotdb/jdbc/IoTDBDriverTest.java | 40 +++++++-
.../apache/iotdb/jdbc/IoTDBJDBCResultSetTest.java | 1 +
.../org/apache/iotdb/jdbc/IoTDBStatementTest.java | 14 +++
.../test/java/org/apache/iotdb/jdbc/UtilsTest.java | 63 +++++++++++-
14 files changed, 462 insertions(+), 63 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 66d17d43d79..ee94386fe54 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
@@ -135,11 +135,7 @@ public class IoTDBConnection implements Connection {
this.zoneId = ZoneId.of(params.getTimeZone());
this.charset = params.getCharset();
openTransport();
- if (Config.rpcThriftCompressionEnable) {
- setClient(new IClientRPCService.Client(new TCompactProtocol(transport)));
- } else {
- setClient(new IClientRPCService.Client(new TBinaryProtocol(transport)));
- }
+ openClient();
// open client session
openSession();
// Wrap the client with a thread-safe proxy to serialize the RPC calls
@@ -311,7 +307,7 @@ public class IoTDBConnection implements Connection {
@Override
public int getHoldability() {
- return 0;
+ return ResultSet.HOLD_CURSORS_OVER_COMMIT;
}
@Override
@@ -408,7 +404,10 @@ public class IoTDBConnection implements Connection {
}
@Override
- public boolean isValid(int arg0) {
+ public boolean isValid(int arg0) throws SQLException {
+ if (arg0 < 0) {
+ throw new SQLException("timeout must be >= 0");
+ }
return !isClosed;
}
@@ -561,6 +560,14 @@ public class IoTDBConnection implements Connection {
}
}
+ private void openClient() {
+ if (params.isRpcThriftCompressionEnabled()) {
+ setClient(new IClientRPCService.Client(new TCompactProtocol(transport)));
+ } else {
+ setClient(new IClientRPCService.Client(new TBinaryProtocol(transport)));
+ }
+ }
+
private void openSession() throws SQLException {
TSOpenSessionReq openReq = new TSOpenSessionReq();
@@ -636,11 +643,7 @@ public class IoTDBConnection implements Connection {
if (transport != null) {
transport.close();
openTransport();
- if (Config.rpcThriftCompressionEnable) {
- setClient(new IClientRPCService.Client(new
TCompactProtocol(transport)));
- } else {
- setClient(new IClientRPCService.Client(new
TBinaryProtocol(transport)));
- }
+ openClient();
openSession();
setClient(RpcUtils.newSynchronizedClient(getClient()));
flag = true;
diff --git
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnectionParams.java
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnectionParams.java
index 1112caabd4e..1a8c4866bb7 100644
---
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnectionParams.java
+++
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnectionParams.java
@@ -51,6 +51,7 @@ public class IoTDBConnectionParams {
private boolean useSSL = false;
private String trustStore;
private String trustStorePwd;
+ private boolean rpcThriftCompressionEnabled =
Config.rpcThriftCompressionEnable;
private String sqlDialect = TREE;
@@ -184,6 +185,14 @@ public class IoTDBConnectionParams {
this.trustStorePwd = trustStorePwd;
}
+ public boolean isRpcThriftCompressionEnabled() {
+ return rpcThriftCompressionEnabled;
+ }
+
+ public void setRpcThriftCompressionEnabled(boolean
rpcThriftCompressionEnabled) {
+ this.rpcThriftCompressionEnabled = rpcThriftCompressionEnabled;
+ }
+
public String getSqlDialect() {
return sqlDialect;
}
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 34645c78c49..689b08a45dd 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
@@ -38,8 +38,14 @@ public class IoTDBDataSource implements DataSource {
private String url;
private String user;
private String password;
+ private String serverName = Config.IOTDB_DEFAULT_HOST;
+ private String databaseName;
+ private String dataSourceName;
+ private String description;
+ private String networkProtocol;
+ private String roleName;
private Properties properties;
- private Integer port = 6667;
+ private Integer port = Config.IOTDB_DEFAULT_PORT;
private PrintWriter logWriter;
private int loginTimeout;
@@ -52,9 +58,7 @@ public class IoTDBDataSource implements DataSource {
this.properties = new Properties();
setUser(user);
setPassword(password);
- if (port != null && port != 0) {
- this.port = port;
- }
+ setPort(port);
}
public String getUser() {
@@ -80,7 +84,63 @@ public class IoTDBDataSource implements DataSource {
}
public void setPort(Integer port) {
- this.port = port;
+ this.port = port == null || port == 0 ? Config.IOTDB_DEFAULT_PORT : port;
+ }
+
+ public Integer getPortNumber() {
+ return getPort();
+ }
+
+ public void setPortNumber(Integer portNumber) {
+ setPort(portNumber);
+ }
+
+ public String getServerName() {
+ return serverName;
+ }
+
+ public void setServerName(String serverName) {
+ this.serverName = serverName;
+ }
+
+ public String getDatabaseName() {
+ return databaseName;
+ }
+
+ public void setDatabaseName(String databaseName) {
+ this.databaseName = databaseName;
+ }
+
+ public String getDataSourceName() {
+ return dataSourceName;
+ }
+
+ public void setDataSourceName(String dataSourceName) {
+ this.dataSourceName = dataSourceName;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getNetworkProtocol() {
+ return networkProtocol;
+ }
+
+ public void setNetworkProtocol(String networkProtocol) {
+ this.networkProtocol = networkProtocol;
+ }
+
+ public String getRoleName() {
+ return roleName;
+ }
+
+ public void setRoleName(String roleName) {
+ this.roleName = roleName;
}
public String getUrl() {
@@ -145,7 +205,7 @@ public class IoTDBDataSource implements DataSource {
private Connection createConnection(Properties connectionProperties) throws
SQLException {
applyLoginTimeout(connectionProperties);
try {
- return new IoTDBConnection(url, connectionProperties);
+ return new IoTDBConnection(getConnectionUrl(), connectionProperties);
} catch (TTransportException e) {
LOGGER.error(JdbcMessages.GET_CONNECTION_ERROR, e);
throw new SQLException(
@@ -155,6 +215,20 @@ public class IoTDBDataSource implements DataSource {
}
}
+ String getConnectionUrl() {
+ if (url != null) {
+ return url;
+ }
+ String host =
+ serverName == null || serverName.trim().isEmpty() ?
Config.IOTDB_DEFAULT_HOST : serverName;
+ StringBuilder builder = new StringBuilder(Config.IOTDB_URL_PREFIX);
+ builder.append(host).append(':').append(port);
+ if (databaseName != null && !databaseName.isEmpty()) {
+ builder.append('/').append(databaseName);
+ }
+ return builder.toString();
+ }
+
private void applyLoginTimeout(Properties connectionProperties) {
if (loginTimeout <= 0 ||
connectionProperties.containsKey(Config.NETWORK_TIMEOUT)) {
return;
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 228ad925af5..98d6bfb777c 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
@@ -38,29 +38,68 @@ public class IoTDBDataSourceFactory implements
DataSourceFactory {
private final Logger logger =
LoggerFactory.getLogger(IoTDBDataSourceFactory.class);
@Override
- public DataSource createDataSource(Properties properties) {
+ public DataSource createDataSource(Properties properties) throws
SQLException {
IoTDBDataSource ds = new IoTDBDataSource();
setProperties(ds, properties);
return ds;
}
- public void setProperties(IoTDBDataSource ds, Properties prop) {
+ public void setProperties(IoTDBDataSource ds, Properties prop) throws
SQLException {
Properties properties = prop == null ? new Properties() : (Properties)
prop.clone();
- String url = (String) properties.remove(DataSourceFactory.JDBC_URL);
+ String url = removeStringProperty(properties, DataSourceFactory.JDBC_URL);
if (url != null) {
ds.setUrl(url);
}
- String user = (String) properties.remove(DataSourceFactory.JDBC_USER);
+ String user = removeStringProperty(properties,
DataSourceFactory.JDBC_USER);
if (user != null) {
ds.setUser(user);
}
- String password = (String)
properties.remove(DataSourceFactory.JDBC_PASSWORD);
+ String password = removeStringProperty(properties,
DataSourceFactory.JDBC_PASSWORD);
if (password != null) {
ds.setPassword(password);
}
+ String serverName = removeStringProperty(properties,
DataSourceFactory.JDBC_SERVER_NAME);
+ if (serverName != null) {
+ ds.setServerName(serverName);
+ }
+
+ Integer portNumber = removeIntegerProperty(properties,
DataSourceFactory.JDBC_PORT_NUMBER);
+ if (portNumber != null) {
+ ds.setPortNumber(portNumber);
+ }
+
+ String databaseName = removeStringProperty(properties,
DataSourceFactory.JDBC_DATABASE_NAME);
+ if (databaseName != null) {
+ ds.setDatabaseName(databaseName);
+ }
+
+ String dataSourceName =
+ removeStringProperty(properties,
DataSourceFactory.JDBC_DATASOURCE_NAME);
+ if (dataSourceName != null) {
+ ds.setDataSourceName(dataSourceName);
+ }
+
+ String description = removeStringProperty(properties,
DataSourceFactory.JDBC_DESCRIPTION);
+ if (description != null) {
+ ds.setDescription(description);
+ }
+
+ String networkProtocol =
+ removeStringProperty(properties,
DataSourceFactory.JDBC_NETWORK_PROTOCOL);
+ if (networkProtocol != null) {
+ ds.setNetworkProtocol(networkProtocol);
+ }
+
+ String roleName = removeStringProperty(properties,
DataSourceFactory.JDBC_ROLE_NAME);
+ if (roleName != null) {
+ ds.setRoleName(roleName);
+ }
+
+ removeUnsupportedPoolProperties(properties);
+
logger.info(JdbcMessages.REMAINING_PROPERTIES, properties.size());
if (!properties.isEmpty()) {
@@ -83,4 +122,35 @@ public class IoTDBDataSourceFactory implements
DataSourceFactory {
public Driver createDriver(Properties properties) {
return new IoTDBDriver();
}
+
+ private static String removeStringProperty(Properties properties, String
key) {
+ Object value = properties.remove(key);
+ return value == null ? null : value.toString();
+ }
+
+ private static Integer removeIntegerProperty(Properties properties, String
key)
+ throws SQLException {
+ Object value = properties.remove(key);
+ if (value == null) {
+ return null;
+ }
+ try {
+ int integerValue = Integer.parseInt(value.toString());
+ if (integerValue < 0 || integerValue > 65535) {
+ throw new NumberFormatException(value.toString());
+ }
+ return integerValue;
+ } catch (NumberFormatException e) {
+ throw new SQLException("Invalid JDBC property " + key + ": " + value, e);
+ }
+ }
+
+ private static void removeUnsupportedPoolProperties(Properties properties) {
+ properties.remove(DataSourceFactory.JDBC_INITIAL_POOL_SIZE);
+ properties.remove(DataSourceFactory.JDBC_MAX_IDLE_TIME);
+ properties.remove(DataSourceFactory.JDBC_MAX_POOL_SIZE);
+ properties.remove(DataSourceFactory.JDBC_MAX_STATEMENTS);
+ properties.remove(DataSourceFactory.JDBC_MIN_POOL_SIZE);
+ properties.remove(DataSourceFactory.JDBC_PROPERTY_CYCLE);
+ }
}
diff --git
a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDriver.java
b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDriver.java
index 71d69d0eb3c..3dcbd4fecb8 100644
--- a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDriver.java
+++ b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDriver.java
@@ -98,8 +98,11 @@ public class IoTDBDriver implements Driver {
}
@Override
- public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) {
- Properties properties = info == null ? new Properties() : info;
+ public DriverPropertyInfo[] getPropertyInfo(String url, Properties info)
throws SQLException {
+ Properties properties = info == null ? new Properties() : (Properties)
info.clone();
+ if (url != null && acceptsURL(url)) {
+ Utils.parseUrl(url, properties);
+ }
return new DriverPropertyInfo[] {
createProperty(
Config.AUTH_USER, Config.DEFAULT_USER, "User name for
authentication.", properties),
@@ -131,6 +134,12 @@ public class IoTDBDriver implements Driver {
Config.CHARSET, TSFileConfig.STRING_CHARSET.name(), "Connection
charset.", properties),
createProperty(
Config.USE_SSL, "false", BOOLEAN_CHOICES, "Whether to enable SSL.",
properties),
+ createProperty(
+ Utils.RPC_COMPRESS,
+ String.valueOf(Config.rpcThriftCompressionEnable),
+ BOOLEAN_CHOICES,
+ "Whether to enable RPC thrift compression.",
+ properties),
createProperty(Config.TRUST_STORE, null, "SSL trust store path.",
properties),
createSensitiveProperty(Config.TRUST_STORE_PWD, "SSL trust store
password."),
createProperty(
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 9ed67182ce8..fa615a2f2ab 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
@@ -530,7 +530,7 @@ public class IoTDBJDBCResultSet implements ResultSet {
@Override
public int getHoldability() throws SQLException {
- throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+ return ResultSet.HOLD_CURSORS_OVER_COMMIT;
}
@Override
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 49818558b59..5952bb56e9b 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
@@ -669,6 +669,10 @@ public class IoTDBStatement implements Statement {
@Override
public void setQueryTimeout(int seconds) throws SQLException {
checkConnection("setQueryTimeout");
+ if (seconds < 0) {
+ throw new SQLException(
+ String.format(JdbcMessages.QUERY_TIMEOUT_MUST_BE_NON_NEGATIVE,
seconds));
+ }
this.queryTimeout = seconds;
}
@@ -685,7 +689,7 @@ public class IoTDBStatement implements Statement {
@Override
public int getResultSetHoldability() throws SQLException {
- throw new
SQLException(JdbcMessages.NOT_SUPPORT_GET_RESULT_SET_HOLDABILITY);
+ return ResultSet.HOLD_CURSORS_OVER_COMMIT;
}
@Override
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 873e01e7d21..d5eb1d720a4 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
@@ -48,49 +48,45 @@ public class Utils {
static IoTDBConnectionParams parseUrl(String url, Properties info) throws
IoTDBURLException {
Properties properties = info == null ? new Properties() : info;
IoTDBConnectionParams params = new IoTDBConnectionParams(url);
- if (url.trim().equalsIgnoreCase(Config.IOTDB_URL_PREFIX)) {
- return params;
- }
- boolean isUrlLegal = false;
+ boolean isUrlLegal = url.trim().equalsIgnoreCase(Config.IOTDB_URL_PREFIX);
Matcher matcher = null;
String host = null;
String suffixURL = null;
- if (url.startsWith(Config.IOTDB_URL_PREFIX)) {
+ if (!isUrlLegal && url.startsWith(Config.IOTDB_URL_PREFIX)) {
String subURL = url.substring(Config.IOTDB_URL_PREFIX.length());
- int i = subURL.lastIndexOf(COLON);
- if (i <= 0) {
+ int authorityEnd = findAuthorityEnd(subURL);
+ String authority = subURL.substring(0, authorityEnd);
+ int portSeparatorIndex = authority.lastIndexOf(COLON);
+ if (portSeparatorIndex <= 0 || portSeparatorIndex == authority.length()
- 1) {
throw new IoTDBURLException(
"Error url format, url should be
jdbc:iotdb://anything:port/[database] or
jdbc:iotdb://anything:port[/database]?property1=value1&property2=value2,
current url is "
+ url);
}
- host = subURL.substring(0, i);
+ host = authority.substring(0, portSeparatorIndex);
params.setHost(host);
- i++;
+ String portText = authority.substring(portSeparatorIndex + 1);
// parse port
- int port = 0;
- for (; i < subURL.length() && Character.isDigit(subURL.charAt(i)); i++) {
- port = port * 10 + (subURL.charAt(i) - '0');
- }
- suffixURL = i < subURL.length() ? subURL.substring(i) : "";
+ int port = parsePort(portText);
+ suffixURL = subURL.substring(authorityEnd);
// legal port
if (port >= 1 && port <= 65535) {
params.setPort(port);
// parse database
- if (i < subURL.length() && subURL.charAt(i) == SLASH) {
- int endIndex = subURL.indexOf(PARAMETER_SEPARATOR, i + 1);
+ if (!suffixURL.isEmpty() && suffixURL.charAt(0) == SLASH) {
+ int endIndex = suffixURL.indexOf(PARAMETER_SEPARATOR, 1);
String database;
- if (endIndex <= i + 1) {
- if (i + 1 == subURL.length()) {
+ if (endIndex < 0) {
+ if (suffixURL.length() == 1) {
database = null;
} else {
- database = subURL.substring(i + 1);
+ database = suffixURL.substring(1);
}
suffixURL = "";
} else {
- database = subURL.substring(i + 1, endIndex);
- suffixURL = subURL.substring(endIndex);
+ database = endIndex == 1 ? null : suffixURL.substring(1, endIndex);
+ suffixURL = suffixURL.substring(endIndex);
}
params.setDb(database);
}
@@ -115,16 +111,17 @@ public class Utils {
}
if (properties.containsKey(Config.DEFAULT_BUFFER_CAPACITY)) {
params.setThriftDefaultBufferSize(
- parseIntegerProperty(properties, Config.DEFAULT_BUFFER_CAPACITY));
+ parsePositiveIntegerProperty(properties,
Config.DEFAULT_BUFFER_CAPACITY));
}
if (properties.containsKey(Config.THRIFT_FRAME_MAX_SIZE)) {
- params.setThriftMaxFrameSize(parseIntegerProperty(properties,
Config.THRIFT_FRAME_MAX_SIZE));
+ params.setThriftMaxFrameSize(
+ parsePositiveIntegerProperty(properties,
Config.THRIFT_FRAME_MAX_SIZE));
}
if (properties.containsKey(Config.VERSION)) {
params.setVersion(parseVersionProperty(properties));
}
if (properties.containsKey(Config.NETWORK_TIMEOUT)) {
- params.setNetworkTimeout(parseIntegerProperty(properties,
Config.NETWORK_TIMEOUT));
+ params.setNetworkTimeout(parseNonNegativeIntegerProperty(properties,
Config.NETWORK_TIMEOUT));
}
if (properties.containsKey(Config.TIME_ZONE)) {
params.setTimeZone(validateTimeZoneProperty(properties));
@@ -133,7 +130,7 @@ public class Utils {
params.setCharset(validateCharsetProperty(properties));
}
if (properties.containsKey(Config.USE_SSL)) {
- params.setUseSSL(parseBooleanProperty(properties));
+ params.setUseSSL(parseBooleanProperty(properties, Config.USE_SSL));
}
if (properties.containsKey(Config.TRUST_STORE)) {
params.setTrustStore(properties.getProperty(Config.TRUST_STORE));
@@ -141,6 +138,9 @@ public class Utils {
if (properties.containsKey(Config.TRUST_STORE_PWD)) {
params.setTrustStorePwd(properties.getProperty(Config.TRUST_STORE_PWD));
}
+ if (properties.containsKey(RPC_COMPRESS)) {
+ params.setRpcThriftCompressionEnabled(parseBooleanProperty(properties,
RPC_COMPRESS));
+ }
if (properties.containsKey(Config.SQL_DIALECT)) {
params.setSqlDialect(validateSqlDialectProperty(properties));
}
@@ -172,7 +172,7 @@ public class Utils {
switch (key) {
case RPC_COMPRESS:
if (isBoolean(value)) {
- Config.rpcThriftCompressionEnable = Boolean.parseBoolean(value);
+ info.put(key, value);
} else {
return false;
}
@@ -197,7 +197,9 @@ public class Utils {
break;
case Config.NETWORK_TIMEOUT:
try {
- Integer.parseInt(value);
+ if (Integer.parseInt(value) < 0) {
+ return false;
+ }
} catch (NumberFormatException e) {
return false;
}
@@ -237,6 +239,34 @@ public class Utils {
return "true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value);
}
+ private static int findAuthorityEnd(String subURL) {
+ int slashIndex = subURL.indexOf(SLASH);
+ int parameterIndex = subURL.indexOf(PARAMETER_SEPARATOR);
+ if (slashIndex < 0) {
+ return parameterIndex < 0 ? subURL.length() : parameterIndex;
+ }
+ if (parameterIndex < 0) {
+ return slashIndex;
+ }
+ return Math.min(slashIndex, parameterIndex);
+ }
+
+ private static int parsePort(String portText) {
+ if (portText.isEmpty()) {
+ return -1;
+ }
+ for (int i = 0; i < portText.length(); i++) {
+ if (!Character.isDigit(portText.charAt(i))) {
+ return -1;
+ }
+ }
+ try {
+ return Integer.parseInt(portText);
+ } catch (NumberFormatException e) {
+ return -1;
+ }
+ }
+
private static int parseIntegerProperty(Properties properties, String key)
throws IoTDBURLException {
String value = getPropertyValue(properties, key);
@@ -247,6 +277,24 @@ public class Utils {
}
}
+ private static int parsePositiveIntegerProperty(Properties properties,
String key)
+ throws IoTDBURLException {
+ int value = parseIntegerProperty(properties, key);
+ if (value <= 0) {
+ throw invalidPropertyValue(key, String.valueOf(value), null);
+ }
+ return value;
+ }
+
+ private static int parseNonNegativeIntegerProperty(Properties properties,
String key)
+ throws IoTDBURLException {
+ int value = parseIntegerProperty(properties, key);
+ if (value < 0) {
+ throw invalidPropertyValue(key, String.valueOf(value), null);
+ }
+ return value;
+ }
+
private static Constant.Version parseVersionProperty(Properties properties)
throws IoTDBURLException {
String value = getPropertyValue(properties, Config.VERSION);
@@ -257,10 +305,11 @@ public class Utils {
}
}
- private static boolean parseBooleanProperty(Properties properties) throws
IoTDBURLException {
- String value = getPropertyValue(properties, Config.USE_SSL);
+ private static boolean parseBooleanProperty(Properties properties, String
key)
+ throws IoTDBURLException {
+ String value = getPropertyValue(properties, key);
if (!isBoolean(value)) {
- throw invalidPropertyValue(Config.USE_SSL, value, null);
+ throw invalidPropertyValue(key, value, null);
}
return Boolean.parseBoolean(value);
}
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 b1668dda5b2..230cb2c9b50 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
@@ -35,6 +35,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.sql.Connection;
+import java.sql.ResultSet;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.time.ZoneId;
@@ -124,6 +125,17 @@ public class IoTDBConnectionTest {
Assert.assertEquals(60, connection.getQueryTimeout());
}
+ @Test
+ public void testStandardConnectionStateMethods() throws SQLException {
+ assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT,
connection.getHoldability());
+ assertFalse(connection.isValid(0));
+ }
+
+ @Test(expected = SQLException.class)
+ public void testIsValidRejectsNegativeTimeout() throws SQLException {
+ connection.isValid(-1);
+ }
+
@Test
public void testWrapperMethods() throws SQLException {
assertTrue(connection.isWrapperFor(IoTDBConnection.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 b2f3ad4926f..e9e9a336058 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
@@ -39,7 +39,7 @@ import static org.junit.Assert.assertTrue;
public class IoTDBDataSourceFactoryTest {
@Test
- public void testCreateDataSourceAllowsNullProperties() {
+ public void testCreateDataSourceAllowsNullProperties() throws SQLException {
DataSource dataSource = new
IoTDBDataSourceFactory().createDataSource(null);
assertTrue(dataSource instanceof IoTDBDataSource);
@@ -50,7 +50,7 @@ public class IoTDBDataSourceFactoryTest {
}
@Test
- public void testCreateDataSourceAllowsUrlOnlyProperties() {
+ public void testCreateDataSourceAllowsUrlOnlyProperties() throws
SQLException {
String url = "jdbc:iotdb://localhost:6667";
Properties properties = new Properties();
properties.setProperty(DataSourceFactory.JDBC_URL, url);
@@ -64,6 +64,65 @@ public class IoTDBDataSourceFactoryTest {
assertEquals(url, properties.getProperty(DataSourceFactory.JDBC_URL));
}
+ @Test
+ public void
testCreateDataSourceSupportsStandardServerPortAndDatabaseProperties()
+ throws SQLException {
+ Properties properties = new Properties();
+ properties.setProperty(DataSourceFactory.JDBC_SERVER_NAME, "127.0.0.1");
+ properties.put(DataSourceFactory.JDBC_PORT_NUMBER, 6688);
+ properties.setProperty(DataSourceFactory.JDBC_DATABASE_NAME, "root.sg");
+
+ IoTDBDataSource dataSource =
+ (IoTDBDataSource) new
IoTDBDataSourceFactory().createDataSource(properties);
+
+ assertEquals("127.0.0.1", dataSource.getServerName());
+ assertEquals(Integer.valueOf(6688), dataSource.getPortNumber());
+ assertEquals("root.sg", dataSource.getDatabaseName());
+ assertNull(dataSource.getUrl());
+ assertEquals("jdbc:iotdb://127.0.0.1:6688/root.sg",
dataSource.getConnectionUrl());
+ assertEquals(Integer.valueOf(6688),
properties.get(DataSourceFactory.JDBC_PORT_NUMBER));
+ }
+
+ @Test
+ public void
testCreateDataSourceAcceptsStandardInformationalAndPoolProperties()
+ throws SQLException {
+ Properties properties = new Properties();
+ properties.setProperty(DataSourceFactory.JDBC_DATASOURCE_NAME, "iotdb-ds");
+ properties.setProperty(DataSourceFactory.JDBC_DESCRIPTION, "IoTDB test
data source");
+ properties.setProperty(DataSourceFactory.JDBC_NETWORK_PROTOCOL, "tcp");
+ properties.setProperty(DataSourceFactory.JDBC_ROLE_NAME, "reader");
+ properties.put(DataSourceFactory.JDBC_INITIAL_POOL_SIZE, 1);
+ properties.put(DataSourceFactory.JDBC_MAX_POOL_SIZE, 2);
+
+ IoTDBDataSource dataSource =
+ (IoTDBDataSource) new
IoTDBDataSourceFactory().createDataSource(properties);
+
+ assertEquals("iotdb-ds", dataSource.getDataSourceName());
+ assertEquals("IoTDB test data source", dataSource.getDescription());
+ assertEquals("tcp", dataSource.getNetworkProtocol());
+ assertEquals("reader", dataSource.getRoleName());
+ }
+
+ @Test(expected = SQLException.class)
+ public void testCreateDataSourceRejectsInvalidStandardPortProperty() throws
SQLException {
+ Properties properties = new Properties();
+ properties.setProperty(DataSourceFactory.JDBC_PORT_NUMBER, "bad");
+
+ new IoTDBDataSourceFactory().createDataSource(properties);
+ }
+
+ @Test
+ public void testDataSourceExplicitUrlTakesPrecedenceOverStandardProperties()
{
+ IoTDBDataSource dataSource = new IoTDBDataSource();
+
+ dataSource.setUrl("jdbc:iotdb://explicit:6667/root.explicit");
+ dataSource.setServerName("127.0.0.1");
+ dataSource.setPortNumber(6688);
+ dataSource.setDatabaseName("root.sg");
+
+ assertEquals("jdbc:iotdb://explicit:6667/root.explicit",
dataSource.getConnectionUrl());
+ }
+
@Test
public void testDataSourceAllowsClearingUserAndPassword() {
IoTDBDataSource dataSource = new IoTDBDataSource();
diff --git
a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDriverTest.java
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDriverTest.java
index 2dcd873dcd9..fb44d3664ec 100644
--- a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDriverTest.java
+++ b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDriverTest.java
@@ -22,6 +22,7 @@ package org.apache.iotdb.jdbc;
import org.junit.Test;
import java.sql.DriverPropertyInfo;
+import java.sql.SQLException;
import java.util.Arrays;
import java.util.Properties;
@@ -52,7 +53,7 @@ public class IoTDBDriverTest {
}
@Test
- public void testGetPropertyInfo() {
+ public void testGetPropertyInfo() throws SQLException {
IoTDBDriver driver = new IoTDBDriver();
Properties properties = new Properties();
properties.setProperty(Config.AUTH_USER, "root");
@@ -78,7 +79,7 @@ public class IoTDBDriverTest {
}
@Test
- public void testGetPropertyInfoAllowsNullProperties() {
+ public void testGetPropertyInfoAllowsNullProperties() throws SQLException {
IoTDBDriver driver = new IoTDBDriver();
DriverPropertyInfo[] propertyInfos =
@@ -88,6 +89,41 @@ public class IoTDBDriverTest {
assertEquals(Config.DEFAULT_USER, findProperty(propertyInfos,
Config.AUTH_USER).value);
}
+ @Test
+ public void testGetPropertyInfoMergesUrlPropertiesWithoutMutatingInput()
throws SQLException {
+ IoTDBDriver driver = new IoTDBDriver();
+ Properties properties = new Properties();
+ properties.setProperty(Config.USE_SSL, "false");
+ boolean originalRpcCompression = Config.rpcThriftCompressionEnable;
+ Config.rpcThriftCompressionEnable = false;
+ try {
+ DriverPropertyInfo[] propertyInfos =
+ driver.getPropertyInfo(
+
"jdbc:iotdb://localhost:6667?use_ssl=true&sql_dialect=table&network_timeout=123&rpc_compress=true",
+ properties);
+
+ assertEquals("true", findProperty(propertyInfos, Config.USE_SSL).value);
+ assertEquals(Constant.TABLE, findProperty(propertyInfos,
Config.SQL_DIALECT).value);
+ assertEquals("123", findProperty(propertyInfos,
Config.NETWORK_TIMEOUT).value);
+ assertEquals("true", findProperty(propertyInfos,
Utils.RPC_COMPRESS).value);
+ assertEquals("false", properties.getProperty(Config.USE_SSL));
+ assertFalse(Config.rpcThriftCompressionEnable);
+ } finally {
+ Config.rpcThriftCompressionEnable = originalRpcCompression;
+ }
+ }
+
+ @Test(expected = SQLException.class)
+ public void testGetPropertyInfoRejectsInvalidIoTDBUrl() throws SQLException {
+ new IoTDBDriver().getPropertyInfo("jdbc:iotdb://localhost", new
Properties());
+ }
+
+ @Test(expected = SQLException.class)
+ public void testGetPropertyInfoRejectsInvalidUrlProperties() throws
SQLException {
+ new IoTDBDriver()
+ .getPropertyInfo("jdbc:iotdb://localhost:6667?network_timeout=-1", new
Properties());
+ }
+
private static DriverPropertyInfo findProperty(DriverPropertyInfo[]
propertyInfos, String name) {
for (DriverPropertyInfo propertyInfo : propertyInfos) {
if (name.equals(propertyInfo.name)) {
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 854709fddbb..208c77295db 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
@@ -207,6 +207,7 @@ public class IoTDBJDBCResultSetTest {
Assert.assertFalse(resultSet.isWrapperFor(null));
Assert.assertSame(resultSet, resultSet.unwrap(IoTDBJDBCResultSet.class));
Assert.assertSame(resultSet, resultSet.unwrap(ResultSet.class));
+ Assert.assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT,
resultSet.getHoldability());
// check columnInfoMap
Assert.assertEquals(1, resultSet.findColumn("Time"));
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 95973222498..d54ccf15fa3 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
@@ -32,6 +32,7 @@ import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.ZoneId;
@@ -111,6 +112,12 @@ public class IoTDBStatementTest {
Assert.assertEquals(100, statement.getQueryTimeout());
}
+ @Test(expected = SQLException.class)
+ public void testSetQueryTimeoutRejectsNegativeValue() throws SQLException {
+ IoTDBStatement statement = new IoTDBStatement(connection, client,
sessionId, zoneID);
+ statement.setQueryTimeout(-1);
+ }
+
@Test
public void testWrapperMethods() throws SQLException {
IoTDBStatement statement = new IoTDBStatement(connection, client,
sessionId, zoneID);
@@ -123,6 +130,13 @@ public class IoTDBStatementTest {
assertSame(statement, statement.unwrap(Statement.class));
}
+ @Test
+ public void testStandardResultSetHoldability() throws SQLException {
+ IoTDBStatement statement = new IoTDBStatement(connection, client,
sessionId, zoneID);
+
+ assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT,
statement.getResultSetHoldability());
+ }
+
@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/UtilsTest.java
b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/UtilsTest.java
index 9927d050cb9..e5b1de15da8 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
@@ -30,6 +30,7 @@ import org.junit.Test;
import java.util.Properties;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -115,6 +116,40 @@ public class UtilsTest {
assertEquals(Config.DEFAULT_PASSWORD, params.getPassword());
}
+ @Test
+ public void testParseDefaultUrlAppliesConnectionProperties() throws
IoTDBURLException {
+ Properties properties = new Properties();
+ properties.setProperty(Config.AUTH_USER, "root");
+ properties.setProperty(Config.NETWORK_TIMEOUT, "123");
+
+ IoTDBConnectionParams params = Utils.parseUrl(Config.IOTDB_URL_PREFIX,
properties);
+
+ assertEquals(Config.IOTDB_DEFAULT_HOST, params.getHost());
+ assertEquals(Config.IOTDB_DEFAULT_PORT, params.getPort());
+ assertEquals("root", params.getUsername());
+ assertEquals(123, params.getNetworkTimeout());
+ }
+
+ @Test
+ public void testParseUrlAllowsEmptyDatabaseBeforeQuery() throws
IoTDBURLException {
+ IoTDBConnectionParams params =
+ Utils.parseUrl("jdbc:iotdb://test:6667/?use_ssl=true", new
Properties());
+
+ assertEquals("test", params.getHost());
+ assertEquals(6667, params.getPort());
+ assertFalse(params.getDb().isPresent());
+ assertTrue(params.isUseSSL());
+ }
+
+ @Test
+ public void testParseUrlAllowsColonAfterAuthority() throws IoTDBURLException
{
+ Properties properties = new Properties();
+
+ Utils.parseUrl("jdbc:iotdb://127.0.0.1:6667?trust_store=scheme:path",
properties);
+
+ assertEquals("scheme:path", properties.getProperty(Config.TRUST_STORE));
+ }
+
@Test(expected = IoTDBURLException.class)
public void testParseWrongUrl2() throws IoTDBURLException {
Properties properties = new Properties();
@@ -170,9 +205,21 @@ public class UtilsTest {
@Test
public void testRpcCompress() throws IoTDBURLException {
+ boolean originalRpcCompression = Config.rpcThriftCompressionEnable;
+ Config.rpcThriftCompressionEnable = false;
Properties properties = new Properties();
- Utils.parseUrl("jdbc:iotdb://127.0.0.1:6667?rpc_compress=true",
properties);
- assertTrue(Config.rpcThriftCompressionEnable);
+ try {
+ IoTDBConnectionParams params =
+ Utils.parseUrl("jdbc:iotdb://127.0.0.1:6667?rpc_compress=true",
properties);
+
+ assertTrue(params.isRpcThriftCompressionEnabled());
+ assertFalse(Config.rpcThriftCompressionEnable);
+ assertFalse(
+ Utils.parseUrl("jdbc:iotdb://127.0.0.1:6667", new Properties())
+ .isRpcThriftCompressionEnabled());
+ } finally {
+ Config.rpcThriftCompressionEnable = originalRpcCompression;
+ }
}
@Test
@@ -209,6 +256,11 @@ public class UtilsTest {
Utils.parseUrl("jdbc:iotdb://127.0.0.1:6667?network_timeout=bad", new
Properties());
}
+ @Test(expected = IoTDBURLException.class)
+ public void testParseUrlParamRejectsNegativeNetworkTimeoutValue() throws
IoTDBURLException {
+ Utils.parseUrl("jdbc:iotdb://127.0.0.1:6667?network_timeout=-1", new
Properties());
+ }
+
@Test(expected = IoTDBURLException.class)
public void testParseUrlParamRejectsInvalidSqlDialectValue() throws
IoTDBURLException {
Utils.parseUrl("jdbc:iotdb://127.0.0.1:6667?sql_dialect=bad", new
Properties());
@@ -226,6 +278,13 @@ public class UtilsTest {
assertInvalidProperty(Config.SQL_DIALECT, "bad");
}
+ @Test
+ public void testParseUrlRejectsInvalidIntegerRanges() {
+ assertInvalidProperty(Config.DEFAULT_BUFFER_CAPACITY, "0");
+ assertInvalidProperty(Config.THRIFT_FRAME_MAX_SIZE, "-1");
+ assertInvalidProperty(Config.NETWORK_TIMEOUT, "-1");
+ }
+
private static void assertInvalidProperty(String key, String value) {
Properties properties = new Properties();
properties.setProperty(key, value);