diff --git a/src/main/java/org/tarantool/Key.java b/src/main/java/org/tarantool/Key.java index f07ed7e8..f4a7d57e 100644 --- a/src/main/java/org/tarantool/Key.java +++ b/src/main/java/org/tarantool/Key.java @@ -33,7 +33,8 @@ public enum Key implements Callable { SQL_BIND(0x41), SQL_OPTIONS(0x42), SQL_INFO(0x42), - SQL_ROW_COUNT(0); + SQL_ROW_COUNT(0x00), + SQL_INFO_AUTOINCREMENT_IDS(0x01); int id; diff --git a/src/main/java/org/tarantool/SqlProtoUtils.java b/src/main/java/org/tarantool/SqlProtoUtils.java index 98b933e5..9c10eb24 100644 --- a/src/main/java/org/tarantool/SqlProtoUtils.java +++ b/src/main/java/org/tarantool/SqlProtoUtils.java @@ -5,6 +5,7 @@ import org.tarantool.protocol.TarantoolPacket; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -41,7 +42,7 @@ public static List getSQLMetadata(TarantoolPacket pack) { return values; } - public static Long getSqlRowCount(TarantoolPacket pack) { + public static Long getSQLRowCount(TarantoolPacket pack) { Map info = (Map) pack.getBody().get(Key.SQL_INFO.getId()); Number rowCount; if (info != null && (rowCount = ((Number) info.get(Key.SQL_ROW_COUNT.getId()))) != null) { @@ -50,6 +51,15 @@ public static Long getSqlRowCount(TarantoolPacket pack) { return null; } + public static List getSQLAutoIncrementIds(TarantoolPacket pack) { + Map info = (Map) pack.getBody().get(Key.SQL_INFO.getId()); + if (info != null) { + List generatedIds = (List) info.get(Key.SQL_INFO_AUTOINCREMENT_IDS.getId()); + return generatedIds == null ? Collections.emptyList() : generatedIds; + } + return Collections.emptyList(); + } + public static class SQLMetaData { private String name; private TarantoolSqlType type; diff --git a/src/main/java/org/tarantool/TarantoolClientImpl.java b/src/main/java/org/tarantool/TarantoolClientImpl.java index eed09a45..dcb7a8ba 100644 --- a/src/main/java/org/tarantool/TarantoolClientImpl.java +++ b/src/main/java/org/tarantool/TarantoolClientImpl.java @@ -482,7 +482,7 @@ protected void complete(TarantoolPacket packet, TarantoolOp future) { } protected void completeSql(TarantoolOp future, TarantoolPacket pack) { - Long rowCount = SqlProtoUtils.getSqlRowCount(pack); + Long rowCount = SqlProtoUtils.getSQLRowCount(pack); if (rowCount != null) { ((TarantoolOp) future).complete(rowCount); } else { diff --git a/src/main/java/org/tarantool/TarantoolConnection.java b/src/main/java/org/tarantool/TarantoolConnection.java index cf9c553f..09883bc0 100644 --- a/src/main/java/org/tarantool/TarantoolConnection.java +++ b/src/main/java/org/tarantool/TarantoolConnection.java @@ -80,7 +80,7 @@ public void close() { @Override public Long update(String sql, Object... bind) { TarantoolPacket pack = sql(sql, bind); - return SqlProtoUtils.getSqlRowCount(pack); + return SqlProtoUtils.getSQLRowCount(pack); } @Override diff --git a/src/main/java/org/tarantool/jdbc/SQLConnection.java b/src/main/java/org/tarantool/jdbc/SQLConnection.java index 0da87a6f..15f3258a 100644 --- a/src/main/java/org/tarantool/jdbc/SQLConnection.java +++ b/src/main/java/org/tarantool/jdbc/SQLConnection.java @@ -49,7 +49,7 @@ *

* Supports creating {@link Statement} and {@link PreparedStatement} instances */ -public class SQLConnection implements Connection { +public class SQLConnection implements TarantoolConnection { private static final int UNSET_HOLDABILITY = 0; private static final String PING_QUERY = "SELECT 1"; @@ -148,10 +148,7 @@ public PreparedStatement prepareStatement(String sql, public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { checkNotClosed(); JdbcConstants.checkGeneratedKeysConstant(autoGeneratedKeys); - if (autoGeneratedKeys != Statement.NO_GENERATED_KEYS) { - throw new SQLFeatureNotSupportedException(); - } - return prepareStatement(sql); + return new SQLPreparedStatement(this, sql, autoGeneratedKeys); } @Override @@ -527,14 +524,17 @@ public int getNetworkTimeout() throws SQLException { return (int) client.getOperationTimeout(); } - protected SQLResultHolder execute(long timeout, SQLQueryHolder query) throws SQLException { + @Override + public SQLResultHolder execute(long timeout, SQLQueryHolder query) throws SQLException { checkNotClosed(); return (useNetworkTimeout(timeout)) ? executeWithNetworkTimeout(query) : executeWithQueryTimeout(timeout, query); } - protected SQLBatchResultHolder executeBatch(long timeout, List queries) throws SQLException { + @Override + public SQLBatchResultHolder executeBatch(long timeout, List queries) + throws SQLException { checkNotClosed(); SQLTarantoolClientImpl.SQLRawOps sqlOps = client.sqlRawOps(); SQLBatchResultHolder batchResult = useNetworkTimeout(timeout) @@ -810,10 +810,10 @@ SQLRawOps sqlRawOps() { @Override protected void completeSql(TarantoolOp future, TarantoolPacket pack) { - Long rowCount = SqlProtoUtils.getSqlRowCount(pack); + Long rowCount = SqlProtoUtils.getSQLRowCount(pack); SQLResultHolder result = (rowCount == null) ? SQLResultHolder.ofQuery(SqlProtoUtils.getSQLMetadata(pack), SqlProtoUtils.getSQLData(pack)) - : SQLResultHolder.ofUpdate(rowCount.intValue()); + : SQLResultHolder.ofUpdate(rowCount.intValue(), SqlProtoUtils.getSQLAutoIncrementIds(pack)); ((TarantoolOp) future).complete(result); } diff --git a/src/main/java/org/tarantool/jdbc/SQLDatabaseMetadata.java b/src/main/java/org/tarantool/jdbc/SQLDatabaseMetadata.java index f59dfaef..98d2ea1d 100644 --- a/src/main/java/org/tarantool/jdbc/SQLDatabaseMetadata.java +++ b/src/main/java/org/tarantool/jdbc/SQLDatabaseMetadata.java @@ -978,7 +978,7 @@ public boolean supportsMultipleOpenResults() throws SQLException { @Override public boolean supportsGetGeneratedKeys() throws SQLException { - return false; + return true; } @Override @@ -1104,7 +1104,7 @@ private ResultSet asEmptyMetadataResultSet(List parameters; - + private final int autoGeneratedKeys; private List> batchParameters = new ArrayList<>(); - public SQLPreparedStatement(SQLConnection connection, String sql) throws SQLException { + public SQLPreparedStatement(SQLConnection connection, String sql, int autoGeneratedKeys) throws SQLException { super(connection); this.sql = sql; this.parameters = new HashMap<>(); + this.autoGeneratedKeys = autoGeneratedKeys; setPoolable(true); } @@ -52,13 +53,14 @@ public SQLPreparedStatement(SQLConnection connection, super(connection, resultSetType, resultSetConcurrency, resultSetHoldability); this.sql = sql; this.parameters = new HashMap<>(); + this.autoGeneratedKeys = NO_GENERATED_KEYS; setPoolable(true); } @Override public ResultSet executeQuery() throws SQLException { checkNotClosed(); - if (!executeInternal(sql, toParametersList(parameters))) { + if (!executeInternal(autoGeneratedKeys, sql, toParametersList(parameters))) { throw new SQLException("No results were returned", SQLStates.NO_DATA.getSqlState()); } return resultSet; @@ -73,7 +75,7 @@ public ResultSet executeQuery(String sql) throws SQLException { @Override public int executeUpdate() throws SQLException { checkNotClosed(); - if (executeInternal(sql, toParametersList(parameters))) { + if (executeInternal(autoGeneratedKeys, sql, toParametersList(parameters))) { throw new SQLException( "Result was returned but nothing was expected", SQLStates.TOO_MANY_RESULTS.getSqlState() @@ -244,7 +246,7 @@ private void setParameter(int parameterIndex, Object value) throws SQLException @Override public boolean execute() throws SQLException { checkNotClosed(); - return executeInternal(sql, toParametersList(parameters)); + return executeInternal(autoGeneratedKeys, sql, toParametersList(parameters)); } @Override diff --git a/src/main/java/org/tarantool/jdbc/SQLResultHolder.java b/src/main/java/org/tarantool/jdbc/SQLResultHolder.java index 9298cae1..13a4992a 100644 --- a/src/main/java/org/tarantool/jdbc/SQLResultHolder.java +++ b/src/main/java/org/tarantool/jdbc/SQLResultHolder.java @@ -16,24 +16,29 @@ public class SQLResultHolder { private final List sqlMetadata; private final List> rows; private final int updateCount; + private final List generatedIds; - public SQLResultHolder(List sqlMetadata, List> rows, int updateCount) { + public SQLResultHolder(List sqlMetadata, + List> rows, + int updateCount, + List generatedIds) { this.sqlMetadata = sqlMetadata; this.rows = rows; this.updateCount = updateCount; + this.generatedIds = generatedIds; } public static SQLResultHolder ofQuery(final List sqlMetadata, final List> rows) { - return new SQLResultHolder(sqlMetadata, rows, NO_UPDATE_COUNT); + return new SQLResultHolder(sqlMetadata, rows, NO_UPDATE_COUNT, Collections.emptyList()); } public static SQLResultHolder ofEmptyQuery() { return ofQuery(Collections.emptyList(), Collections.emptyList()); } - public static SQLResultHolder ofUpdate(int updateCount) { - return new SQLResultHolder(null, null, updateCount); + public static SQLResultHolder ofUpdate(int updateCount, List generatedIds) { + return new SQLResultHolder(null, null, updateCount, generatedIds); } public List getSqlMetadata() { @@ -48,6 +53,10 @@ public int getUpdateCount() { return updateCount; } + public List getGeneratedIds() { + return generatedIds; + } + public boolean isQueryResult() { return sqlMetadata != null && rows != null; } diff --git a/src/main/java/org/tarantool/jdbc/SQLStatement.java b/src/main/java/org/tarantool/jdbc/SQLStatement.java index 059a44eb..bbb68a7a 100644 --- a/src/main/java/org/tarantool/jdbc/SQLStatement.java +++ b/src/main/java/org/tarantool/jdbc/SQLStatement.java @@ -1,5 +1,7 @@ package org.tarantool.jdbc; +import org.tarantool.SqlProtoUtils; +import org.tarantool.jdbc.type.TarantoolSqlType; import org.tarantool.util.JdbcConstants; import org.tarantool.util.SQLStates; @@ -13,6 +15,7 @@ import java.sql.SQLWarning; import java.sql.Statement; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -27,13 +30,17 @@ */ public class SQLStatement implements TarantoolStatement { - protected final SQLConnection connection; + private static final String GENERATED_KEY_COLUMN_NAME = "GENERATED_KEY"; + + protected final TarantoolConnection connection; + private final SQLResultSet emptyGeneratedKeys; /** * Current result set / update count associated to this statement. */ protected SQLResultSet resultSet; protected int updateCount; + protected SQLResultSet generatedKeys; private List batchQueries = new ArrayList<>(); @@ -61,10 +68,12 @@ public class SQLStatement implements TarantoolStatement { private final AtomicBoolean isClosed = new AtomicBoolean(false); protected SQLStatement(SQLConnection sqlConnection) throws SQLException { - this.connection = sqlConnection; - this.resultSetType = ResultSet.TYPE_FORWARD_ONLY; - this.resultSetConcurrency = ResultSet.CONCUR_READ_ONLY; - this.resultSetHoldability = sqlConnection.getHoldability(); + this( + sqlConnection, + ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, + sqlConnection.getHoldability() + ); } protected SQLStatement(SQLConnection sqlConnection, @@ -75,12 +84,13 @@ protected SQLStatement(SQLConnection sqlConnection, this.resultSetType = resultSetType; this.resultSetConcurrency = resultSetConcurrency; this.resultSetHoldability = resultSetHoldability; + this.emptyGeneratedKeys = this.generatedKeys = executeGeneratedKeys(Collections.emptyList()); } @Override public ResultSet executeQuery(String sql) throws SQLException { checkNotClosed(); - if (!executeInternal(sql)) { + if (!executeInternal(NO_GENERATED_KEYS, sql)) { throw new SQLException("No results were returned", SQLStates.NO_DATA.getSqlState()); } return resultSet; @@ -88,24 +98,20 @@ public ResultSet executeQuery(String sql) throws SQLException { @Override public int executeUpdate(String sql) throws SQLException { - checkNotClosed(); - if (executeInternal(sql)) { - throw new SQLException( - "Result was returned but nothing was expected", - SQLStates.TOO_MANY_RESULTS.getSqlState() - ); - } - return updateCount; + return executeUpdate(sql, NO_GENERATED_KEYS); } @Override public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { checkNotClosed(); JdbcConstants.checkGeneratedKeysConstant(autoGeneratedKeys); - if (autoGeneratedKeys != Statement.NO_GENERATED_KEYS) { - throw new SQLFeatureNotSupportedException(); + if (executeInternal(autoGeneratedKeys, sql)) { + throw new SQLException( + "Result was returned but nothing was expected", + SQLStates.TOO_MANY_RESULTS.getSqlState() + ); } - return executeUpdate(sql); + return updateCount; } @Override @@ -195,17 +201,14 @@ public void setCursorName(String name) throws SQLException { @Override public boolean execute(String sql) throws SQLException { checkNotClosed(); - return executeInternal(sql); + return executeInternal(NO_GENERATED_KEYS, sql); } @Override public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { checkNotClosed(); JdbcConstants.checkGeneratedKeysConstant(autoGeneratedKeys); - if (autoGeneratedKeys != Statement.NO_GENERATED_KEYS) { - throw new SQLFeatureNotSupportedException(); - } - return execute(sql); + return executeInternal(autoGeneratedKeys, sql); } @Override @@ -321,7 +324,7 @@ public Connection getConnection() throws SQLException { @Override public ResultSet getGeneratedKeys() throws SQLException { checkNotClosed(); - return new SQLResultSet(SQLResultHolder.ofEmptyQuery(), this); + return generatedKeys; } @Override @@ -401,6 +404,7 @@ protected void discardLastResults() throws SQLException { clearWarnings(); updateCount = -1; resultSet = null; + generatedKeys = emptyGeneratedKeys; if (lastResultSet != null) { try { @@ -419,7 +423,7 @@ protected void discardLastResults() throws SQLException { * * @return {@code true}, if the result is a ResultSet object; */ - protected boolean executeInternal(String sql, Object... params) throws SQLException { + protected boolean executeInternal(int autoGeneratedKeys, String sql, Object... params) throws SQLException { discardLastResults(); SQLResultHolder holder; try { @@ -433,6 +437,9 @@ protected boolean executeInternal(String sql, Object... params) throws SQLExcept resultSet = new SQLResultSet(holder, this); } updateCount = holder.getUpdateCount(); + if (autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS) { + generatedKeys = executeGeneratedKeys(holder.getGeneratedIds()); + } return holder.isQueryResult(); } @@ -474,4 +481,13 @@ protected void checkNotClosed() throws SQLException { } } + protected SQLResultSet executeGeneratedKeys(List generatedKeys) throws SQLException { + SqlProtoUtils.SQLMetaData sqlMetaData = + new SqlProtoUtils.SQLMetaData(GENERATED_KEY_COLUMN_NAME, TarantoolSqlType.INTEGER); + List> rows = generatedKeys.stream() + .map(Collections::singletonList) + .collect(Collectors.toList()); + return createResultSet(SQLResultHolder.ofQuery(Collections.singletonList(sqlMetaData), rows)); + } + } diff --git a/src/main/java/org/tarantool/jdbc/TarantoolConnection.java b/src/main/java/org/tarantool/jdbc/TarantoolConnection.java new file mode 100644 index 00000000..6354f508 --- /dev/null +++ b/src/main/java/org/tarantool/jdbc/TarantoolConnection.java @@ -0,0 +1,40 @@ +package org.tarantool.jdbc; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.List; + +/** + * Tarantool specific connection extensions. + */ +public interface TarantoolConnection extends Connection { + + /** + * Executes SQL query. + * + * @param timeout query timeout + * @param query query holder + * + * @return wrapper that holds processed sql results + * + * @throws SQLException if errors occur while the query is being performed. + * {@link java.sql.SQLTimeoutException} is raised when execution time exceeds the timeout + */ + SQLResultHolder execute(long timeout, SQLQueryHolder query) throws SQLException; + + /** + * Executes number of update queries. The given timeout will + * be applied to each query from the list. + * + * @param timeout query timeout + * @param queries list of queries to be executed in a batch + * + * @return wrapper that holds processed sql results + * + * @throws SQLException if errors occur while the query is being performed. + * {@link java.sql.SQLTimeoutException} is raised when execution time exceeds the timeout + */ + SQLBatchResultHolder executeBatch(long timeout, List queries) + throws SQLException; + +} diff --git a/src/test/java/org/tarantool/jdbc/JdbcConnectionIT.java b/src/test/java/org/tarantool/jdbc/JdbcConnectionIT.java index eca60d0d..afda6205 100644 --- a/src/test/java/org/tarantool/jdbc/JdbcConnectionIT.java +++ b/src/test/java/org/tarantool/jdbc/JdbcConnectionIT.java @@ -440,10 +440,6 @@ public void testGeneratedKeys() throws SQLException { assertThrows(SQLException.class, () -> conn.prepareStatement(sql, Integer.MAX_VALUE)); assertThrows(SQLException.class, () -> conn.prepareStatement(sql, Integer.MIN_VALUE)); assertThrows(SQLException.class, () -> conn.prepareStatement(sql, -76)); - assertThrows( - SQLFeatureNotSupportedException.class, - () -> conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) - ); } @Test diff --git a/src/test/java/org/tarantool/jdbc/JdbcDatabaseMetaDataIT.java b/src/test/java/org/tarantool/jdbc/JdbcDatabaseMetaDataIT.java index 28477a0b..3c4ba0f7 100644 --- a/src/test/java/org/tarantool/jdbc/JdbcDatabaseMetaDataIT.java +++ b/src/test/java/org/tarantool/jdbc/JdbcDatabaseMetaDataIT.java @@ -295,7 +295,7 @@ public void testIsWrapperFor() throws SQLException { @Test public void testSupportGeneratedKeys() throws SQLException { - assertFalse(meta.supportsGetGeneratedKeys()); + assertTrue(meta.supportsGetGeneratedKeys()); } @Test diff --git a/src/test/java/org/tarantool/jdbc/JdbcExceptionHandlingTest.java b/src/test/java/org/tarantool/jdbc/JdbcExceptionHandlingTest.java index acba1a57..f6a37ff4 100644 --- a/src/test/java/org/tarantool/jdbc/JdbcExceptionHandlingTest.java +++ b/src/test/java/org/tarantool/jdbc/JdbcExceptionHandlingTest.java @@ -173,7 +173,10 @@ private void checkPreparedStatementCommunicationException(final ThrowingConsumer SQLTarantoolClientImpl client = buildSQLClient(sqlOps, null); final PreparedStatement prep = new SQLPreparedStatement( - buildTestSQLConnection(client, "jdbc:tarantool://0:0"), "TEST"); + buildTestSQLConnection(client, "jdbc:tarantool://0:0"), + "TEST", + Statement.NO_GENERATED_KEYS + ); SQLException e = assertThrows(SQLException.class, new Executable() { diff --git a/src/test/java/org/tarantool/jdbc/JdbcPreparedStatementIT.java b/src/test/java/org/tarantool/jdbc/JdbcPreparedStatementIT.java index d32eb6fe..4aad887f 100644 --- a/src/test/java/org/tarantool/jdbc/JdbcPreparedStatementIT.java +++ b/src/test/java/org/tarantool/jdbc/JdbcPreparedStatementIT.java @@ -29,6 +29,7 @@ import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.sql.Statement; +import java.sql.Types; import java.util.Collections; import java.util.List; @@ -239,6 +240,80 @@ public void testSupportGeneratedKeys() throws SQLException { assertEquals(ResultSet.CONCUR_READ_ONLY, generatedKeys.getConcurrency()); } + @Test + public void testExecuteReturnGeneratedKeys() throws SQLException { + testHelper.executeSql("CREATE TABLE test_auto (id INT PRIMARY KEY AUTOINCREMENT)"); + + prep = conn.prepareStatement("INSERT INTO test_auto VALUES (?)", Statement.RETURN_GENERATED_KEYS); + prep.setNull(1, Types.INTEGER); + prep.execute(); + + assertEquals(1, prep.getUpdateCount()); + ResultSet generatedKeys = prep.getGeneratedKeys(); + assertTrue(generatedKeys.next()); + assertEquals(1, generatedKeys.getInt("generated_key")); + + testHelper.executeSql("DROP TABLE test_auto"); + } + + @Test + public void testExecuteUpdateReturnGeneratedKeys() throws SQLException { + testHelper.executeSql("CREATE TABLE test_auto (id INT PRIMARY KEY AUTOINCREMENT)"); + + prep = conn.prepareStatement("INSERT INTO test_auto VALUES (?), (?)", Statement.RETURN_GENERATED_KEYS); + prep.setNull(1, Types.INTEGER); + prep.setNull(2, Types.INTEGER); + prep.execute(); + + assertEquals(2, prep.getUpdateCount()); + ResultSet generatedKeys = prep.getGeneratedKeys(); + assertTrue(generatedKeys.next()); + assertEquals(1, generatedKeys.getInt("generated_key")); + assertTrue(generatedKeys.next()); + assertEquals(2, generatedKeys.getInt("generated_key")); + + testHelper.executeSql("DROP TABLE test_auto"); + } + + @Test + public void testExecuteReturnEmptyGeneratedKeys() throws SQLException { + testHelper.executeSql("CREATE TABLE test_auto (id INT PRIMARY KEY AUTOINCREMENT)"); + + prep = conn.prepareStatement("INSERT INTO test_auto VALUES (?), (?)", Statement.RETURN_GENERATED_KEYS); + prep.setInt(1, 10); + prep.setInt(2, 20); + prep.execute(); + + assertEquals(2, prep.getUpdateCount()); + ResultSet generatedKeys = prep.getGeneratedKeys(); + assertFalse(generatedKeys.next()); + + testHelper.executeSql("DROP TABLE test_auto"); + } + + @Test + public void testExecuteReturnMixedGeneratedKeys() throws SQLException { + testHelper.executeSql("CREATE TABLE test_auto (id INT PRIMARY KEY AUTOINCREMENT)"); + + prep = conn.prepareStatement( + "INSERT INTO test_auto VALUES (?), (?), (?), (?)", Statement.RETURN_GENERATED_KEYS + ); + prep.setInt(1, 10); + prep.setNull(2, Types.INTEGER); + prep.setInt(3, 20); + prep.setNull(4, Types.INTEGER); + prep.execute(); + + assertEquals(4, prep.getUpdateCount()); + ResultSet generatedKeys = prep.getGeneratedKeys(); + assertTrue(generatedKeys.next()); + assertEquals(11, generatedKeys.getInt("generated_key")); + assertTrue(generatedKeys.next()); + assertEquals(21, generatedKeys.getInt("generated_key")); + + testHelper.executeSql("DROP TABLE test_auto"); + } + @Test void testStatementConnection() throws SQLException { Statement statement = conn.prepareStatement("SELECT * FROM TEST"); diff --git a/src/test/java/org/tarantool/jdbc/JdbcResultSetMetaDataIT.java b/src/test/java/org/tarantool/jdbc/JdbcResultSetMetaDataIT.java index ec34bc51..13140d53 100644 --- a/src/test/java/org/tarantool/jdbc/JdbcResultSetMetaDataIT.java +++ b/src/test/java/org/tarantool/jdbc/JdbcResultSetMetaDataIT.java @@ -9,6 +9,8 @@ import org.tarantool.ServerVersion; import org.tarantool.TarantoolTestHelper; +import org.tarantool.jdbc.type.JdbcType; +import org.tarantool.jdbc.type.TarantoolSqlType; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; diff --git a/src/test/java/org/tarantool/jdbc/JdbcStatementIT.java b/src/test/java/org/tarantool/jdbc/JdbcStatementIT.java index 30708c03..171eaddc 100644 --- a/src/test/java/org/tarantool/jdbc/JdbcStatementIT.java +++ b/src/test/java/org/tarantool/jdbc/JdbcStatementIT.java @@ -197,6 +197,7 @@ public void testExecuteUpdateNoGeneratedKeys() throws SQLException { assertEquals(1, affectedRows); ResultSet generatedKeys = stmt.getGeneratedKeys(); assertNotNull(generatedKeys); + assertFalse(generatedKeys.next()); assertEquals(ResultSet.TYPE_FORWARD_ONLY, generatedKeys.getType()); assertEquals(ResultSet.CONCUR_READ_ONLY, generatedKeys.getConcurrency()); } @@ -216,25 +217,60 @@ public void testExecuteNoGeneratedKeys() throws SQLException { } @Test - void testExecuteUpdateGeneratedKeys() { - assertThrows( - SQLException.class, - () -> stmt.executeUpdate( - "INSERT INTO test(id, val) VALUES (100, 'hundred'), (1000, 'thousand')", - Statement.RETURN_GENERATED_KEYS - ) - ); + public void testExecuteReturnGeneratedKeys() throws SQLException { + testHelper.executeSql("CREATE TABLE test_auto (id INT PRIMARY KEY AUTOINCREMENT)"); + + stmt.execute("INSERT INTO test_auto VALUES (null)", Statement.RETURN_GENERATED_KEYS); + assertEquals(1, stmt.getUpdateCount()); + ResultSet generatedKeys = stmt.getGeneratedKeys(); + assertTrue(generatedKeys.next()); + assertEquals(1, generatedKeys.getInt("generated_key")); + + testHelper.executeSql("DROP TABLE test_auto"); + } + + @Test + public void testExecuteUpdateReturnGeneratedKeys() throws SQLException { + testHelper.executeSql("CREATE TABLE test_auto (id INT PRIMARY KEY AUTOINCREMENT)"); + + stmt.executeUpdate("INSERT INTO test_auto VALUES (null), (null)", Statement.RETURN_GENERATED_KEYS); + assertEquals(2, stmt.getUpdateCount()); + ResultSet generatedKeys = stmt.getGeneratedKeys(); + assertTrue(generatedKeys.next()); + assertEquals(1, generatedKeys.getInt("generated_key")); + assertTrue(generatedKeys.next()); + assertEquals(2, generatedKeys.getInt("generated_key")); + + testHelper.executeSql("DROP TABLE test_auto"); + } + + @Test + public void testExecuteReturnEmptyGeneratedKeys() throws SQLException { + testHelper.executeSql("CREATE TABLE test_auto (id INT PRIMARY KEY AUTOINCREMENT)"); + + stmt.executeUpdate("INSERT INTO test_auto VALUES (10), (20)", Statement.RETURN_GENERATED_KEYS); + assertEquals(2, stmt.getUpdateCount()); + ResultSet generatedKeys = stmt.getGeneratedKeys(); + assertFalse(generatedKeys.next()); + + testHelper.executeSql("DROP TABLE test_auto"); } @Test - void testExecuteGeneratedKeys() { - assertThrows( - SQLException.class, - () -> stmt.execute( - "INSERT INTO test(id, val) VALUES (100, 'hundred'), (1000, 'thousand')", - Statement.RETURN_GENERATED_KEYS - ) + public void testExecuteReturnMixedGeneratedKeys() throws SQLException { + testHelper.executeSql("CREATE TABLE test_auto (id INT PRIMARY KEY AUTOINCREMENT)"); + + stmt.executeUpdate( + "INSERT INTO test_auto VALUES (10), (null), (20), (null)", Statement.RETURN_GENERATED_KEYS ); + assertEquals(4, stmt.getUpdateCount()); + ResultSet generatedKeys = stmt.getGeneratedKeys(); + assertTrue(generatedKeys.next()); + assertEquals(11, generatedKeys.getInt("generated_key")); + assertTrue(generatedKeys.next()); + assertEquals(21, generatedKeys.getInt("generated_key")); + + testHelper.executeSql("DROP TABLE test_auto"); } @Test