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 c23ff58f160 Fix JDBC statement and metadata edge cases
c23ff58f160 is described below
commit c23ff58f1609cf1cb3291b85b22776d046b36fff
Author: Caideyipi <[email protected]>
AuthorDate: Tue Jun 9 15:11:12 2026 +0800
Fix JDBC statement and metadata edge cases
---
.../org/apache/iotdb/jdbc/IoTDBJDBCResultSet.java | 18 +++--
.../apache/iotdb/jdbc/IoTDBPreparedStatement.java | 7 +-
.../org/apache/iotdb/jdbc/IoTDBResultMetadata.java | 64 +++++++++++-----
.../java/org/apache/iotdb/jdbc/IoTDBStatement.java | 41 +++++++----
.../iotdb/jdbc/IoTDBTablePreparedStatement.java | 4 +
.../apache/iotdb/jdbc/IoTDBJDBCResultSetTest.java | 58 +++++++++++++++
.../iotdb/jdbc/IoTDBPreparedStatementTest.java | 10 +++
.../apache/iotdb/jdbc/IoTDBResultMetadataTest.java | 86 ++++++++++++++++++++++
.../org/apache/iotdb/jdbc/IoTDBStatementTest.java | 20 +++++
9 files changed, 269 insertions(+), 39 deletions(-)
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 f30fcadba86..903f0bb8926 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
@@ -274,17 +274,25 @@ public class IoTDBJDBCResultSet implements ResultSet {
@Override
public BigDecimal getBigDecimal(String columnName) throws SQLException {
String value = getValueByName(columnName);
- if (value != null) {
- return new BigDecimal(value);
- } else {
+ if (value == null) {
return null;
}
+ try {
+ return new BigDecimal(value);
+ } catch (NumberFormatException e) {
+ throw new SQLException(e.getMessage(), e);
+ }
}
@Override
public BigDecimal getBigDecimal(int columnIndex, int scale) throws
SQLException {
- MathContext mc = new MathContext(scale);
- return getBigDecimal(columnIndex).round(mc);
+ try {
+ MathContext mc = new MathContext(scale);
+ BigDecimal value = getBigDecimal(columnIndex);
+ return value == null ? null : value.round(mc);
+ } catch (IllegalArgumentException e) {
+ throw new SQLException(e.getMessage(), e);
+ }
}
@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 203aacdc073..60222d3e7da 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
@@ -100,6 +100,7 @@ public class IoTDBPreparedStatement extends IoTDBStatement
implements PreparedSt
@Override
public void addBatch() throws SQLException {
+ checkConnection("addBatch");
super.addBatch(createCompleteSql(sql, parameters));
}
@@ -110,22 +111,26 @@ public class IoTDBPreparedStatement extends
IoTDBStatement implements PreparedSt
@Override
public boolean execute() throws SQLException {
+ checkConnection("execute");
return super.execute(createCompleteSql(sql, parameters));
}
@Override
public ResultSet executeQuery() throws SQLException {
+ checkConnection("executeQuery");
return super.executeQuery(createCompleteSql(sql, parameters));
}
@Override
public int executeUpdate() throws SQLException {
+ checkConnection("executeUpdate");
return super.executeUpdate(createCompleteSql(sql, parameters));
}
@Override
public ResultSetMetaData getMetaData() throws SQLException {
- return getResultSet().getMetaData();
+ ResultSet currentResultSet = getResultSet();
+ return currentResultSet == null ? null : currentResultSet.getMetaData();
}
@Override
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 4fba689c3e5..973f6a888a4 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
@@ -83,6 +83,7 @@ public class IoTDBResultMetadata implements ResultSetMetaData
{
}) // ignore Cognitive Complexity of methods should not be too high
@Override
public String getCatalogName(int column) throws SQLException {
+ checkColumnIndex(column);
String systemSchmea = "_system_schmea";
String system = "_system";
String systemUser = "_system_user";
@@ -92,9 +93,6 @@ public class IoTDBResultMetadata implements ResultSetMetaData
{
String systemNull = "";
String columnName = columnInfoList.get(column - 1);
List<String> listColumns = columnInfoList;
- if (column < 1 || column > columnInfoList.size()) {
- throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
- }
if ("SHOW".equals(operationType)) {
if ("count".equals(listColumns.get(0))) {
return systemDatabase;
@@ -135,16 +133,22 @@ public class IoTDBResultMetadata implements
ResultSetMetaData {
} else if (!"FILL".equals(operationType)) {
return systemNull;
}
- if (nonAlign) {
- return sgColumns.get(column - 1);
- } else {
- return sgColumns.get(column - 2);
+ if (sgColumns == null || sgColumns.isEmpty()) {
+ return systemNull;
}
+ int sgColumnIndex = nonAlign ? column - 1 : column - 2;
+ if (sgColumnIndex < 0 || sgColumnIndex >= sgColumns.size()) {
+ return systemNull;
+ }
+ return sgColumns.get(sgColumnIndex);
}
@Override
public String getColumnClassName(int column) throws SQLException {
String columnTypeName = getColumnTypeName(column);
+ if (columnTypeName == null) {
+ return null;
+ }
switch (columnTypeName) {
case TIMESTAMP:
return Timestamp.class.getName();
@@ -210,7 +214,7 @@ public class IoTDBResultMetadata implements
ResultSetMetaData {
if (column == 1 && !ignoreTimestamp) {
return Types.TIMESTAMP;
}
- String columnType = columnTypeList.get(column - 1);
+ String columnType = getColumnTypeString(column);
switch (columnType.toUpperCase()) {
case BOOLEAN:
@@ -244,7 +248,7 @@ public class IoTDBResultMetadata implements
ResultSetMetaData {
if (column == 1 && !ignoreTimestamp) {
return TIMESTAMP;
}
- String columnType = columnTypeList.get(column - 1);
+ String columnType = getColumnTypeString(column);
String typeString = columnType.toUpperCase();
if (BOOLEAN.equals(typeString)
|| INT32.equals(typeString)
@@ -267,7 +271,7 @@ public class IoTDBResultMetadata implements
ResultSetMetaData {
if (column == 1 && !ignoreTimestamp) {
return 3;
}
- String columnType = columnTypeList.get(column - 1);
+ String columnType = getColumnTypeString(column);
switch (columnType.toUpperCase()) {
case BOOLEAN:
return 1;
@@ -299,7 +303,7 @@ public class IoTDBResultMetadata implements
ResultSetMetaData {
if (column == 1 && !ignoreTimestamp) {
return 0;
}
- String columnType = columnTypeList.get(column - 1);
+ String columnType = getColumnTypeString(column);
switch (columnType.toUpperCase()) {
case BOOLEAN:
case INT32:
@@ -337,47 +341,67 @@ public class IoTDBResultMetadata implements
ResultSetMetaData {
}
@Override
- public boolean isAutoIncrement(int arg0) throws SQLException {
+ public boolean isAutoIncrement(int column) throws SQLException {
+ checkColumnIndex(column);
return false;
}
@Override
- public boolean isCaseSensitive(int arg0) throws SQLException {
+ public boolean isCaseSensitive(int column) throws SQLException {
+ checkColumnIndex(column);
return true;
}
@Override
- public boolean isCurrency(int arg0) throws SQLException {
+ public boolean isCurrency(int column) throws SQLException {
+ checkColumnIndex(column);
return false;
}
@Override
- public boolean isDefinitelyWritable(int arg0) throws SQLException {
+ public boolean isDefinitelyWritable(int column) throws SQLException {
+ checkColumnIndex(column);
return false;
}
@Override
- public int isNullable(int arg0) throws SQLException {
+ public int isNullable(int column) throws SQLException {
+ checkColumnIndex(column);
return 1;
}
@Override
- public boolean isReadOnly(int arg0) throws SQLException {
+ public boolean isReadOnly(int column) throws SQLException {
+ checkColumnIndex(column);
return true;
}
@Override
- public boolean isSearchable(int arg0) throws SQLException {
+ public boolean isSearchable(int column) throws SQLException {
+ checkColumnIndex(column);
return true;
}
@Override
- public boolean isSigned(int arg0) throws SQLException {
+ public boolean isSigned(int column) throws SQLException {
+ checkColumnIndex(column);
return true;
}
@Override
- public boolean isWritable(int arg0) throws SQLException {
+ public boolean isWritable(int column) throws SQLException {
+ checkColumnIndex(column);
return false;
}
+
+ private String getColumnTypeString(int column) throws SQLException {
+ if (columnTypeList == null || column > columnTypeList.size()) {
+ throw new SQLException(String.format(JdbcMessages.COLUMN_DOES_NOT_EXIST,
column));
+ }
+ String columnType = columnTypeList.get(column - 1);
+ if (columnType == null) {
+ throw new SQLException(String.format(JdbcMessages.COLUMN_DOES_NOT_EXIST,
column));
+ }
+ return columnType;
+ }
}
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 5952bb56e9b..6bc1f03fbd2 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
@@ -73,6 +73,8 @@ public class IoTDBStatement implements Statement {
private List<String> batchSQLList;
private static final String NOT_SUPPORT_EXECUTE = "Not support execute";
private static final String NOT_SUPPORT_EXECUTE_UPDATE = "Not support
executeUpdate";
+ private static final String CANNOT_AFTER_STATEMENT_CLOSED =
+ "Cannot %s after statement has been closed!";
/** Keep state so we can fail certain calls made after close(). */
private boolean isClosed = false;
@@ -191,7 +193,8 @@ public class IoTDBStatement implements Statement {
}
@Override
- public void addBatch(String sql) {
+ public void addBatch(String sql) throws SQLException {
+ checkConnection("addBatch");
if (batchSQLList == null) {
batchSQLList = new ArrayList<>();
}
@@ -217,7 +220,12 @@ public class IoTDBStatement implements Statement {
}
@Override
- public void clearBatch() {
+ public void clearBatch() throws SQLException {
+ checkConnection("clearBatch");
+ clearBatchInternal();
+ }
+
+ private void clearBatchInternal() {
if (batchSQLList == null) {
batchSQLList = new ArrayList<>();
}
@@ -225,7 +233,8 @@ public class IoTDBStatement implements Statement {
}
@Override
- public void clearWarnings() {
+ public void clearWarnings() throws SQLException {
+ checkConnection("clearWarnings");
warningChain = null;
}
@@ -273,7 +282,6 @@ public class IoTDBStatement implements Statement {
@Override
public boolean execute(String sql) throws SQLException {
checkConnection("execute");
- isClosed = false;
try {
return executeSQL(sql);
} catch (TException e) {
@@ -415,14 +423,13 @@ public class IoTDBStatement implements Statement {
@Override
public int[] executeBatch() throws SQLException {
checkConnection("executeBatch");
- isClosed = false;
try {
return executeBatchSQL();
} catch (TException e) {
throw new SQLException(
"Fail to reconnect to server when executing batch sqls. please check
server status", e);
} finally {
- clearBatch();
+ clearBatchInternal();
}
}
@@ -478,7 +485,6 @@ public class IoTDBStatement implements Statement {
public ResultSet executeQuery(String sql, long timeoutInMS) throws
SQLException {
checkConnection("execute query");
- isClosed = false;
try {
return executeQuerySQL(sql, timeoutInMS);
} catch (TException e) {
@@ -545,7 +551,6 @@ public class IoTDBStatement implements Statement {
@Override
public int executeUpdate(String sql) throws SQLException {
checkConnection("execute update");
- isClosed = false;
try {
return executeUpdateSQL(sql);
} catch (TException e) {
@@ -588,7 +593,8 @@ public class IoTDBStatement implements Statement {
}
@Override
- public Connection getConnection() {
+ public Connection getConnection() throws SQLException {
+ checkConnection("getConnection");
return connection;
}
@@ -639,6 +645,7 @@ public class IoTDBStatement implements Statement {
@Override
public int getMaxRows() throws SQLException {
+ checkConnection("getMaxRows");
return this.maxRows;
}
@@ -653,6 +660,7 @@ public class IoTDBStatement implements Statement {
@Override
public boolean getMoreResults() throws SQLException {
+ checkConnection("getMoreResults");
return false;
}
@@ -662,7 +670,8 @@ public class IoTDBStatement implements Statement {
}
@Override
- public int getQueryTimeout() {
+ public int getQueryTimeout() throws SQLException {
+ checkConnection("getQueryTimeout");
return this.queryTimeout;
}
@@ -689,6 +698,7 @@ public class IoTDBStatement implements Statement {
@Override
public int getResultSetHoldability() throws SQLException {
+ checkConnection("getResultSetHoldability");
return ResultSet.HOLD_CURSORS_OVER_COMMIT;
}
@@ -699,12 +709,14 @@ public class IoTDBStatement implements Statement {
}
@Override
- public int getUpdateCount() {
+ public int getUpdateCount() throws SQLException {
+ checkConnection("getUpdateCount");
return -1;
}
@Override
- public SQLWarning getWarnings() {
+ public SQLWarning getWarnings() throws SQLException {
+ checkConnection("getWarnings");
return warningChain;
}
@@ -738,10 +750,13 @@ public class IoTDBStatement implements Statement {
throw new SQLException(JdbcMessages.NOT_SUPPORT_SET_ESCAPE_PROCESSING);
}
- private void checkConnection(String action) throws SQLException {
+ protected void checkConnection(String action) throws SQLException {
if (connection == null || connection.isClosed()) {
throw new
SQLException(String.format(JdbcMessages.CANNOT_AFTER_CONNECTION_CLOSED,
action));
}
+ if (isClosed) {
+ throw new SQLException(String.format(CANNOT_AFTER_STATEMENT_CLOSED,
action));
+ }
}
private boolean reInit() throws SQLException {
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 459a4fead14..25bfbdcadb2 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
@@ -140,6 +140,7 @@ public class IoTDBTablePreparedStatement extends
IoTDBStatement implements Prepa
@Override
public void addBatch() throws SQLException {
+ checkConnection("addBatch");
super.addBatch(createCompleteSql(sql, parameters));
}
@@ -156,6 +157,7 @@ public class IoTDBTablePreparedStatement extends
IoTDBStatement implements Prepa
@Override
public boolean execute() throws SQLException {
+ checkConnection("execute");
if (isQueryStatement(sql)) {
TSExecuteStatementResp resp = executeInternal();
return resp.isSetQueryDataSet() || resp.isSetQueryResult();
@@ -174,12 +176,14 @@ public class IoTDBTablePreparedStatement extends
IoTDBStatement implements Prepa
@Override
public ResultSet executeQuery() throws SQLException {
+ checkConnection("executeQuery");
TSExecuteStatementResp resp = executeInternal();
return processQueryResult(resp);
}
@Override
public int executeUpdate() throws SQLException {
+ checkConnection("executeUpdate");
return super.executeUpdate(createCompleteSql(sql, parameters));
}
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 c323fb032bc..d06464112cd 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
@@ -30,9 +30,11 @@ import
org.apache.iotdb.service.rpc.thrift.TSFetchMetadataResp;
import org.apache.iotdb.service.rpc.thrift.TSFetchResultsReq;
import org.apache.iotdb.service.rpc.thrift.TSFetchResultsResp;
+import org.apache.tsfile.common.conf.TSFileConfig;
import org.apache.tsfile.enums.TSDataType;
import org.apache.tsfile.read.common.block.TsBlockBuilder;
import org.apache.tsfile.read.common.block.column.TsBlockSerde;
+import org.apache.tsfile.utils.Binary;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -227,6 +229,11 @@ public class IoTDBJDBCResultSetTest {
Assert.assertTrue(resultSet.wasNull());
Assert.assertNull(resultSet.getTimestamp(4));
Assert.assertTrue(resultSet.wasNull());
+ Assert.assertNull(resultSet.getBigDecimal(4, 2));
+ Assert.assertTrue(resultSet.wasNull());
+ Assert.assertNull(resultSet.getBigDecimal("root.vehicle.d0.s0", 2));
+ Assert.assertTrue(resultSet.wasNull());
+ Assert.assertThrows(SQLException.class, () ->
resultSet.getBigDecimal(4, -1));
firstRow = false;
}
for (int i = 1; i <= colCount; i++) {
@@ -274,6 +281,20 @@ public class IoTDBJDBCResultSetTest {
}
}
+ @SuppressWarnings("resource")
+ @Test
+ public void testInvalidBigDecimalConversionThrowsSQLException() throws
Exception {
+ mockTextQueryResponse();
+
+ Assert.assertTrue(statement.execute("select s3 from root.vehicle.d0"));
+
+ try (ResultSet resultSet = statement.getResultSet()) {
+ Assert.assertTrue(resultSet.next());
+ Assert.assertThrows(SQLException.class, () ->
resultSet.getBigDecimal(2));
+ Assert.assertThrows(SQLException.class, () ->
resultSet.getBigDecimal("root.vehicle.d0.s3"));
+ }
+ }
+
private void mockVehicleQueryResponse() {
List<String> columns = new ArrayList<>();
columns.add("root.vehicle.d0.s2");
@@ -313,6 +334,25 @@ public class IoTDBJDBCResultSetTest {
.getDataType();
}
+ private void mockTextQueryResponse() {
+ List<String> columns = new
ArrayList<>(Collections.singletonList("root.vehicle.d0.s3"));
+ List<String> dataTypeList = new
ArrayList<>(Collections.singletonList("TEXT"));
+
+ when(execResp.isSetColumns()).thenReturn(true);
+ when(execResp.getColumns()).thenReturn(columns);
+ when(execResp.isSetDataTypeList()).thenReturn(true);
+ when(execResp.getDataTypeList()).thenReturn(dataTypeList);
+ when(execResp.isSetOperationType()).thenReturn(true);
+ when(execResp.getOperationType()).thenReturn("QUERY");
+ when(execResp.isSetQueryId()).thenReturn(true);
+ when(execResp.getQueryId()).thenReturn(queryId);
+ when(execResp.isSetTableModel()).thenReturn(false);
+ when(execResp.isIgnoreTimeStamp()).thenReturn(false);
+ when(execResp.getColumnIndex2TsBlockColumnIndexList())
+ .thenReturn(new ArrayList<>(Collections.singletonList(0)));
+ execResp.queryResult = fakedTextFetchTsBlockResult();
+ }
+
private void constructObjectList(List<Object> standardObject) {
Object[][] input = {
{
@@ -416,4 +456,22 @@ public class IoTDBJDBCResultSetTest {
return Collections.singletonList(tsBlock);
}
+
+ private List<ByteBuffer> fakedTextFetchTsBlockResult() {
+ TsBlockBuilder tsBlockBuilder = new
TsBlockBuilder(Collections.singletonList(TSDataType.TEXT));
+ tsBlockBuilder.getTimeColumnBuilder().writeLong(1L);
+ tsBlockBuilder
+ .getColumnBuilder(0)
+ .writeBinary(new Binary("not-a-number", TSFileConfig.STRING_CHARSET));
+ tsBlockBuilder.declarePosition();
+
+ ByteBuffer tsBlock = null;
+ try {
+ tsBlock = new TsBlockSerde().serialize(tsBlockBuilder.build());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return Collections.singletonList(tsBlock);
+ }
}
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 9375e032bb6..b043705cf72 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
@@ -43,6 +43,7 @@ import java.time.ZoneId;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
@@ -125,6 +126,15 @@ public class IoTDBPreparedStatementTest {
assertEquals(ParameterMetaData.parameterModeUnknown,
metadata.getParameterMode(1));
}
+ @SuppressWarnings("resource")
+ @Test
+ public void getMetaDataReturnsNullWhenNoResultSetExists() throws Exception {
+ IoTDBPreparedStatement ps =
+ new IoTDBPreparedStatement(connection, client, sessionId, "SELECT ?",
zoneId);
+
+ assertNull(ps.getMetaData());
+ }
+
@SuppressWarnings("resource")
@Test
public void invalidParameterIndex() 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 b9e5b3dfedb..69afa751093 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
@@ -33,7 +33,9 @@ import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
public class IoTDBResultMetadataTest {
@@ -176,6 +178,90 @@ public class IoTDBResultMetadataTest {
}
}
+ @Test
+ public void testMetadataColumnMethodsRejectInvalidIndex() throws
SQLException {
+ metadata =
+ new IoTDBResultMetadata(
+ false,
+ null,
+ "QUERY",
+ Arrays.asList("Time", "root.a.b.c1"),
+ Arrays.asList("TIMESTAMP", "INT32"),
+ false);
+
+ assertThrows(SQLException.class, () -> metadata.getCatalogName(0));
+ assertThrows(SQLException.class, () -> metadata.isAutoIncrement(0));
+ assertThrows(SQLException.class, () -> metadata.isNullable(3));
+ assertFalse(metadata.isAutoIncrement(1));
+ assertTrue(metadata.isCaseSensitive(1));
+ assertEquals(ResultSetMetaData.columnNullable, metadata.isNullable(1));
+ }
+
+ @Test
+ public void testMissingColumnTypeMetadataThrowsSQLException() {
+ metadata =
+ new IoTDBResultMetadata(
+ false,
+ null,
+ "QUERY",
+ Arrays.asList("Time", "root.a.b.c1"),
+ Collections.singletonList("TIMESTAMP"),
+ false);
+
+ assertThrows(SQLException.class, () -> metadata.getColumnType(2));
+ assertThrows(SQLException.class, () -> metadata.getColumnTypeName(2));
+ assertThrows(SQLException.class, () -> metadata.getPrecision(2));
+ assertThrows(SQLException.class, () -> metadata.getScale(2));
+ }
+
+ @Test
+ public void testNullColumnTypeMetadataThrowsSQLException() {
+ metadata =
+ new IoTDBResultMetadata(
+ false,
+ null,
+ "QUERY",
+ Arrays.asList("Time", "root.a.b.c1"),
+ Arrays.asList("TIMESTAMP", null),
+ false);
+
+ assertThrows(SQLException.class, () -> metadata.getColumnType(2));
+ assertThrows(SQLException.class, () -> metadata.getColumnTypeName(2));
+ assertThrows(SQLException.class, () -> metadata.getPrecision(2));
+ assertThrows(SQLException.class, () -> metadata.getScale(2));
+ }
+
+ @Test
+ public void testCatalogAndSchemaHandleMissingStorageGroupMetadata() throws
SQLException {
+ metadata =
+ new IoTDBResultMetadata(
+ false,
+ null,
+ "QUERY",
+ Arrays.asList("Time", "root.a.b.c1"),
+ Arrays.asList("TIMESTAMP", "INT32"),
+ false);
+
+ assertEquals("", metadata.getCatalogName(2));
+ assertEquals("", metadata.getSchemaName(2));
+ }
+
+ @Test
+ public void testUnknownColumnTypeClassNameReturnsNull() throws SQLException {
+ metadata =
+ new IoTDBResultMetadata(
+ false,
+ null,
+ "QUERY",
+ Arrays.asList("Time", "root.a.b.c1"),
+ Arrays.asList("TIMESTAMP", "UNKNOWN"),
+ false);
+
+ assertEquals(0, metadata.getColumnType(2));
+ assertNull(metadata.getColumnTypeName(2));
+ assertNull(metadata.getColumnClassName(2));
+ }
+
@Test
public void testWrapperMethods() throws SQLException {
metadata = new IoTDBResultMetadata(false, null, "QUERY", null, null,
false);
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 d54ccf15fa3..cee793b773e 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
@@ -40,6 +40,7 @@ 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.when;
@@ -137,6 +138,25 @@ public class IoTDBStatementTest {
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT,
statement.getResultSetHoldability());
}
+ @Test
+ public void testClosedStatementRejectsOperations() throws SQLException {
+ IoTDBStatement statement = new IoTDBStatement(connection, client,
sessionId, zoneID, 0, -1L);
+
+ statement.close();
+
+ assertTrue(statement.isClosed());
+ assertThrows(SQLException.class, () -> statement.execute("select 1"));
+ assertThrows(SQLException.class, () -> statement.executeQuery("select 1"));
+ assertThrows(
+ SQLException.class,
+ () -> statement.executeUpdate("insert into root.sg.d(time,s)
values(1,1)"));
+ assertThrows(SQLException.class, () -> statement.executeBatch());
+ assertThrows(SQLException.class, () -> statement.addBatch("select 1"));
+ assertThrows(SQLException.class, () -> statement.clearBatch());
+ assertThrows(SQLException.class, () -> statement.getFetchSize());
+ assertThrows(SQLException.class, () -> statement.getWarnings());
+ }
+
@Test(expected = SQLException.class)
public void testUnwrapRejectsUnsupportedClass() throws SQLException {
new IoTDBStatement(connection, client, sessionId,
zoneID).unwrap(String.class);