From 9d0e72271822acdfc8120a4d10cfae342866f361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kraus?= Date: Tue, 6 Aug 2024 19:33:38 +0200 Subject: [PATCH] Issue #2279 - Return generated IDs from INSERT statement. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomáš Kraus --- .../java/io/helidon/dbclient/DbResultDml.java | 51 +++++++ .../io/helidon/dbclient/DbResultDmlImpl.java | 36 +++++ .../io/helidon/dbclient/DbStatementDml.java | 34 ++++- .../helidon/dbclient/jdbc/JdbcStatement.java | 17 ++- .../dbclient/jdbc/JdbcStatementDml.java | 96 ++++++++++++- .../dbclient/jdbc/JdbcStatementQuery.java | 4 +- .../jdbc/JdbcTransactionStatementDml.java | 60 +++++++- .../dbclient/mongodb/MongoDbStatementDml.java | 128 +++++++++++++++++- .../integration/dbclient/common/DBHelper.java | 4 + .../dbclient/common/SimpleTestImpl.java | 122 +++++++++++++++++ .../dbclient/common/SimpleTests.java | 11 ++ .../dbclient/common/TransactionTestImpl.java | 127 +++++++++++++++++ .../dbclient/common/TransactionTests.java | 11 ++ .../common/src/main/resources/db-common.yaml | 8 ++ .../dbclient/h2/H2SimpleLocalTestIT.java | 12 ++ .../dbclient/h2/H2SimpleRemoteTestIT.java | 12 ++ .../dbclient/h2/H2TransactionLocalTestIT.java | 12 ++ .../h2/H2TransactionRemoteTestIT.java | 12 ++ .../mongodb/src/main/resources/db.yaml | 8 ++ .../mongodb/MongoDBSimpleLocalTestIT.java | 12 ++ .../mongodb/MongoDBSimpleRemoteTestIT.java | 12 ++ .../mysql/MySQLSimpleLocalTestIT.java | 12 ++ .../mysql/MySQLSimpleRemoteTestIT.java | 12 ++ .../mysql/MySQLTransactionLocalTestIT.java | 12 ++ .../mysql/MySQLTransactionRemoteTestIT.java | 12 ++ .../oracle/src/main/resources/db.yaml | 8 ++ .../oracle/OracleSimpleLocalTestIT.java | 12 ++ .../oracle/OracleSimpleRemoteTestIT.java | 12 ++ .../oracle/OracleTransactionLocalTestIT.java | 12 ++ .../oracle/OracleTransactionRemoteTestIT.java | 12 ++ .../dbclient/pgsql/src/main/resources/db.yaml | 7 + .../pgsql/PostgreSQLSimpleLocalTestIT.java | 12 ++ .../pgsql/PostgreSQLSimpleRemoteTestIT.java | 12 ++ .../PostgreSQLTransactionLocalTestIT.java | 12 ++ .../PostgreSQLTransactionRemoteTestIT.java | 12 ++ 35 files changed, 937 insertions(+), 11 deletions(-) create mode 100644 dbclient/dbclient/src/main/java/io/helidon/dbclient/DbResultDml.java create mode 100644 dbclient/dbclient/src/main/java/io/helidon/dbclient/DbResultDmlImpl.java diff --git a/dbclient/dbclient/src/main/java/io/helidon/dbclient/DbResultDml.java b/dbclient/dbclient/src/main/java/io/helidon/dbclient/DbResultDml.java new file mode 100644 index 00000000000..4e92fd2a616 --- /dev/null +++ b/dbclient/dbclient/src/main/java/io/helidon/dbclient/DbResultDml.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.dbclient; + +import java.util.stream.Stream; + +/** + * Result of DML statement execution. + */ +public interface DbResultDml extends AutoCloseable { + + /** + * Retrieves any auto-generated keys created as a result of executing this DML statement. + * + * @return the auto-generated keys + */ + Stream generatedKeys(); + + /** + * Retrieve statement execution result. + * + * @return row count for Data Manipulation Language (DML) statements or {@code 0} + * for statements that return nothing. + */ + long result(); + + /** + * Create new instance of DML statement execution result. + * + * @param generatedKeys the auto-generated keys + * @param result the statement execution result + * @return new instance of DML statement execution result + */ + static DbResultDml create(Stream generatedKeys, long result) { + return new DbResultDmlImpl(generatedKeys, result); + } + +} diff --git a/dbclient/dbclient/src/main/java/io/helidon/dbclient/DbResultDmlImpl.java b/dbclient/dbclient/src/main/java/io/helidon/dbclient/DbResultDmlImpl.java new file mode 100644 index 00000000000..c2659b860bd --- /dev/null +++ b/dbclient/dbclient/src/main/java/io/helidon/dbclient/DbResultDmlImpl.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.dbclient; + +import java.util.Objects; +import java.util.stream.Stream; + +// DbResultDml implementation +record DbResultDmlImpl(Stream generatedKeys, long result) implements DbResultDml { + + DbResultDmlImpl { + Objects.requireNonNull(generatedKeys, "List of auto-generated keys value is null"); + if (result < 0) { + throw new IllegalArgumentException("Statement execution result value is less than 0"); + } + } + + @Override + public void close() throws Exception { + generatedKeys.close(); + } + +} diff --git a/dbclient/dbclient/src/main/java/io/helidon/dbclient/DbStatementDml.java b/dbclient/dbclient/src/main/java/io/helidon/dbclient/DbStatementDml.java index 70532049f3d..37f1c11fe61 100644 --- a/dbclient/dbclient/src/main/java/io/helidon/dbclient/DbStatementDml.java +++ b/dbclient/dbclient/src/main/java/io/helidon/dbclient/DbStatementDml.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,8 @@ */ package io.helidon.dbclient; +import java.util.List; + /** * Data Manipulation Language (DML) database statement. * A DML statement modifies records in the database and returns the number of modified records. @@ -24,7 +26,35 @@ public interface DbStatementDml extends DbStatement { /** * Execute this statement using the parameters configured with {@code params} and {@code addParams} methods. * - * @return The result of this statement. + * @return the result of this statement */ long execute(); + + /** + * Execute {@code INSERT} statement using the parameters configured with {@code params} and {@code addParams} methods + * and return compound result with generated keys. + * + * @return the result of this statement with generated keys + */ + DbResultDml insert(); + + /** + * Set auto-generated keys to be returned from the statement execution using {@link #insert()}. + * Only one method from {@link #returnGeneratedKeys()} and {@link #returnColumns(List)} may be used. + * This feature is database provider specific and some databases require specific columns to be set. + * + * @return updated db statement + */ + DbStatementDml returnGeneratedKeys(); + + /** + * Set column names to be returned from the inserted row or rows from the statement execution using {@link #insert()}. + * Only one method from {@link #returnGeneratedKeys()} and {@link #returnColumns(List)} may be used. + * This feature is database provider specific. + * + * @param columnNames an array of column names indicating the columns that should be returned from the inserted row or rows + * @return updated db statement + */ + DbStatementDml returnColumns(List columnNames); + } diff --git a/dbclient/jdbc/src/main/java/io/helidon/dbclient/jdbc/JdbcStatement.java b/dbclient/jdbc/src/main/java/io/helidon/dbclient/jdbc/JdbcStatement.java index f109f58e346..9685fa5bfa7 100644 --- a/dbclient/jdbc/src/main/java/io/helidon/dbclient/jdbc/JdbcStatement.java +++ b/dbclient/jdbc/src/main/java/io/helidon/dbclient/jdbc/JdbcStatement.java @@ -79,11 +79,20 @@ private JdbcExecuteContext jdbcContext() { return context(JdbcExecuteContext.class); } + /** + * Set the connection. + * + * @param connection the database connection + */ + protected void connection(Connection connection) { + this.connection = connection; + } + /** * Create the {@link PreparedStatement}. * * @param serviceContext client service context - * @return PreparedStatement + * @return new instance of {@link PreparedStatement} */ protected PreparedStatement prepareStatement(DbClientServiceContext serviceContext) { String stmtName = serviceContext.statementName(); @@ -105,7 +114,7 @@ protected PreparedStatement prepareStatement(DbClientServiceContext serviceConte * * @param stmtName statement name * @param stmt statement text - * @return statement + * @return new instance of {@link PreparedStatement} */ protected PreparedStatement prepareStatement(String stmtName, String stmt) { Connection connection = connectionPool.connection(); @@ -120,10 +129,10 @@ protected PreparedStatement prepareStatement(String stmtName, String stmt) { /** * Create the {@link PreparedStatement}. * - * @param connection connection + * @param connection the database connection * @param stmtName statement name * @param stmt statement text - * @return statement + * @return new instance of {@link PreparedStatement} */ protected PreparedStatement prepareStatement(Connection connection, String stmtName, String stmt) { try { diff --git a/dbclient/jdbc/src/main/java/io/helidon/dbclient/jdbc/JdbcStatementDml.java b/dbclient/jdbc/src/main/java/io/helidon/dbclient/jdbc/JdbcStatementDml.java index 65bd3b94e45..b54ff7c5006 100644 --- a/dbclient/jdbc/src/main/java/io/helidon/dbclient/jdbc/JdbcStatementDml.java +++ b/dbclient/jdbc/src/main/java/io/helidon/dbclient/jdbc/JdbcStatementDml.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,11 +15,22 @@ */ package io.helidon.dbclient.jdbc; +import java.sql.Connection; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Statement; +import java.util.Collections; +import java.util.List; +import java.util.Objects; import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; +import io.helidon.dbclient.DbClientException; import io.helidon.dbclient.DbClientServiceContext; +import io.helidon.dbclient.DbResultDml; +import io.helidon.dbclient.DbRow; import io.helidon.dbclient.DbStatementDml; import io.helidon.dbclient.DbStatementException; import io.helidon.dbclient.DbStatementType; @@ -29,7 +40,17 @@ */ class JdbcStatementDml extends JdbcStatement implements DbStatementDml { + static final String[] EMPTY_STRING_ARRAY = new String[0]; + private final DbStatementType type; + // Column names to be returned from the inserted row or rows from the statement execution. + // Value of null (default) indicates no columns are set. + private List columnNames = List.of(); + // Whether PreparedStatement shall be created with Statement.RETURN_GENERATED_KEYS: + // - value of false (default) indicates that autoGeneratedKeys won't be passed to PreparedStatement creation + // - value of true indicates that Statement.RETURN_GENERATED_KEYS as autoGeneratedKeys will be passed + // to PreparedStatement creation + private boolean returnGeneratedKeys; /** * Create a new instance. @@ -58,6 +79,45 @@ public long execute() { }); } + @Override + public DbResultDml insert() { + return doExecute((future, context) -> doInsert(this, future, context, this::closeConnection)); + } + + @Override + public DbStatementDml returnGeneratedKeys() { + if (!columnNames.isEmpty()) { + throw new IllegalStateException("Method returnColumns(String[]) was already called to set specific column names."); + } + returnGeneratedKeys = true; + return this; + } + + @Override + public DbStatementDml returnColumns(List columnNames) { + if (returnGeneratedKeys) { + throw new IllegalStateException("Method returnGeneratedKeys() was already called."); + } + Objects.requireNonNull(columnNames, "List of column names value is null"); + this.columnNames = Collections.unmodifiableList(columnNames); + return this; + } + + @Override + protected PreparedStatement prepareStatement(Connection connection, String stmtName, String stmt) { + try { + connection(connection); + if (returnGeneratedKeys) { + return connection.prepareStatement(stmt, Statement.RETURN_GENERATED_KEYS); + } else if (!columnNames.isEmpty()) { + return connection.prepareStatement(stmt, columnNames.toArray(EMPTY_STRING_ARRAY)); + } + return connection.prepareStatement(stmt); + } catch (SQLException e) { + throw new DbClientException(String.format("Failed to prepare statement: %s", stmtName), e); + } + } + /** * Execute the given statement. * @@ -75,7 +135,41 @@ static long doExecute(JdbcStatement dbStmt, future.complete(result); return result; } catch (SQLException ex) { + dbStmt.closeConnection(); throw new DbStatementException("Failed to execute statement", dbStmt.context().statement(), ex); } } + + /** + * Execute the given insert statement. + * + * @param dbStmt db statement + * @param future query future + * @param context service context + * @return query result + */ + static DbResultDml doInsert(JdbcStatement dbStmt, + CompletableFuture future, + DbClientServiceContext context, + Runnable onClose) { + PreparedStatement statement; + try { + statement = dbStmt.prepareStatement(context); + long result = statement.executeUpdate(); + ResultSet rs = statement.getGeneratedKeys(); + JdbcRow.Spliterator spliterator = new JdbcRow.Spliterator(rs, statement, dbStmt.context(), future); + Stream generatedKeys = autoClose(StreamSupport.stream(spliterator, false) + .onClose(() -> { + spliterator.close(); + if (onClose != null) { + onClose.run(); + } + })); + return DbResultDml.create(generatedKeys, result); + } catch (SQLException ex) { + dbStmt.closeConnection(); + throw new DbStatementException("Failed to execute statement", dbStmt.context().statement(), ex); + } + } + } diff --git a/dbclient/jdbc/src/main/java/io/helidon/dbclient/jdbc/JdbcStatementQuery.java b/dbclient/jdbc/src/main/java/io/helidon/dbclient/jdbc/JdbcStatementQuery.java index 3938f476c42..f917830495a 100644 --- a/dbclient/jdbc/src/main/java/io/helidon/dbclient/jdbc/JdbcStatementQuery.java +++ b/dbclient/jdbc/src/main/java/io/helidon/dbclient/jdbc/JdbcStatementQuery.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -82,7 +82,7 @@ static Stream doExecute(JdbcStatement dbStmt, })); } catch (SQLException ex) { dbStmt.closeConnection(); - throw new DbStatementException("Failed to create Statement", dbStmt.context().statement(), ex); + throw new DbStatementException("Failed to execute Statement", dbStmt.context().statement(), ex); } } } diff --git a/dbclient/jdbc/src/main/java/io/helidon/dbclient/jdbc/JdbcTransactionStatementDml.java b/dbclient/jdbc/src/main/java/io/helidon/dbclient/jdbc/JdbcTransactionStatementDml.java index 9f33049e4fd..96d8846e84f 100644 --- a/dbclient/jdbc/src/main/java/io/helidon/dbclient/jdbc/JdbcTransactionStatementDml.java +++ b/dbclient/jdbc/src/main/java/io/helidon/dbclient/jdbc/JdbcTransactionStatementDml.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,16 @@ */ package io.helidon.dbclient.jdbc; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import io.helidon.dbclient.DbClientException; +import io.helidon.dbclient.DbResultDml; import io.helidon.dbclient.DbStatementDml; import io.helidon.dbclient.DbStatementType; @@ -24,6 +34,14 @@ class JdbcTransactionStatementDml extends JdbcTransactionStatement implements DbStatementDml { private final DbStatementType type; + // Column names to be returned from the inserted row or rows from the statement execution. + // Value of null (default) indicates no columns are set. + private List columnNames = List.of(); + // Whether PreparedStatement shall be created with Statement.RETURN_GENERATED_KEYS: + // - value of false (default) indicates that autoGeneratedKeys won't be passed to PreparedStatement creation + // - value of true indicates that Statement.RETURN_GENERATED_KEYS as autoGeneratedKeys will be passed + // to PreparedStatement creation + private boolean returnGeneratedKeys; /** * Create a new instance. @@ -49,4 +67,44 @@ public DbStatementType statementType() { public long execute() { return doExecute((future, context) -> JdbcStatementDml.doExecute(this, future, context)); } + + @Override + public DbResultDml insert() { + return doExecute((future, context) -> JdbcStatementDml.doInsert(this, future, context, null)); + } + + @Override + public DbStatementDml returnGeneratedKeys() { + if (!columnNames.isEmpty()) { + throw new IllegalStateException("Method returnColumns(String[]) was already called to set specific column names."); + } + returnGeneratedKeys = true; + return this; + } + + @Override + public DbStatementDml returnColumns(List columnNames) { + if (returnGeneratedKeys) { + throw new IllegalStateException("Method returnGeneratedKeys() was already called."); + } + Objects.requireNonNull(columnNames, "List of column names value is null"); + this.columnNames = Collections.unmodifiableList(columnNames); + return this; + } + + @Override + protected PreparedStatement prepareStatement(Connection connection, String stmtName, String stmt) { + try { + connection(connection); + if (returnGeneratedKeys) { + return connection.prepareStatement(stmt, Statement.RETURN_GENERATED_KEYS); + } else if (!columnNames.isEmpty()) { + return connection.prepareStatement(stmt, columnNames.toArray(JdbcStatementDml.EMPTY_STRING_ARRAY)); + } + return connection.prepareStatement(stmt); + } catch (SQLException e) { + throw new DbClientException(String.format("Failed to prepare statement: %s", stmtName), e); + } + } + } diff --git a/dbclient/mongodb/src/main/java/io/helidon/dbclient/mongodb/MongoDbStatementDml.java b/dbclient/mongodb/src/main/java/io/helidon/dbclient/mongodb/MongoDbStatementDml.java index f22d3d7adb1..3b71c7bf8e4 100644 --- a/dbclient/mongodb/src/main/java/io/helidon/dbclient/mongodb/MongoDbStatementDml.java +++ b/dbclient/mongodb/src/main/java/io/helidon/dbclient/mongodb/MongoDbStatementDml.java @@ -15,15 +15,25 @@ */ package io.helidon.dbclient.mongodb; +import java.util.List; +import java.util.stream.Stream; + import io.helidon.dbclient.DbExecuteContext; +import io.helidon.dbclient.DbResultDml; import io.helidon.dbclient.DbStatementDml; import io.helidon.dbclient.DbStatementType; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import com.mongodb.client.result.DeleteResult; +import com.mongodb.client.result.InsertOneResult; import com.mongodb.client.result.UpdateResult; +import org.bson.BsonDocument; +import org.bson.BsonDocumentReader; +import org.bson.BsonValue; import org.bson.Document; +import org.bson.codecs.DecoderContext; +import org.bson.codecs.DocumentCodec; /** * MongoDB {@link DbStatementDml} implementation. @@ -31,8 +41,11 @@ public class MongoDbStatementDml extends MongoDbStatement implements DbStatementDml { private static final System.Logger LOGGER = System.getLogger(MongoDbStatementDml.class.getName()); - + // Whether generated ID shall be returned + private boolean returnGeneratedKeys; private final DbStatementType type; + private final DocumentCodec codec = new DocumentCodec(); + private final DecoderContext decoderContext = DecoderContext.builder().build(); /** * Create a new instance. @@ -59,6 +72,7 @@ public long execute() { case INSERT -> executeInsert(stmt); case UPDATE -> executeUpdate(stmt); case DELETE -> executeDelete(stmt); + case DML -> executeDml(stmt); default -> throw new UnsupportedOperationException(String.format( "Statement operation not yet supported: %s", type.name())); @@ -81,12 +95,75 @@ public long execute() { }); } + @Override + @SuppressWarnings("resource") // DbResultDml life-cycle is handled by user of this method + public DbResultDml insert() { + return doExecute((future, context) -> { + MongoStatement stmt = new MongoStatement(type, prepareStatement(context)); + try { + DbResultDml result = switch (type) { + case INSERT -> executeInsertAsDbResultDml(stmt); + case UPDATE -> executeUpdateAsDbResultDml(stmt); + case DELETE -> executeDeleteAsDbResultDml(stmt); + case DML -> executeDmlAsDbResultDml(stmt); + default -> throw new UnsupportedOperationException(String.format( + "Statement operation not yet supported: %s", + type.name())); + }; + future.complete(result.result()); + LOGGER.log(System.Logger.Level.DEBUG, () -> String.format( + "%s DML %s execution succeeded", + type.name(), + context().statementName())); + return result; + } catch (UnsupportedOperationException ex) { + throw ex; + } catch (Throwable throwable) { + LOGGER.log(System.Logger.Level.DEBUG, () -> String.format( + "%s DML %s execution failed", + type.name(), + context().statementName())); + throw throwable; + } + }); + } + + @Override + public DbStatementDml returnGeneratedKeys() { + returnGeneratedKeys = true; + return this; + } + + @Override + public DbStatementDml returnColumns(List columnNames) { + throw new UnsupportedOperationException("Retrieval of specific auto-generated columns is not supported for Mongo"); + } + private Long executeInsert(MongoStatement stmt) { MongoCollection mc = db().getCollection(stmt.getCollection()); mc.insertOne(stmt.getValue()); return 1L; } + private DbResultDml executeInsertAsDbResultDml(MongoStatement stmt) { + MongoCollection mc = db().getCollection(stmt.getCollection()); + InsertOneResult result = mc.insertOne(stmt.getValue()); + if (returnGeneratedKeys && result.wasAcknowledged()) { + BsonValue insertedId = result.getInsertedId(); + if (insertedId != null) { + return DbResultDml.create( + Stream.of( + new MongoDbRow( + codec.decode( + new BsonDocumentReader(new BsonDocument("_id", insertedId)), + decoderContext), + context())), + 1L); + } + } + return DbResultDml.create(Stream.of(), 1L); + } + private Long executeUpdate(MongoStatement stmt) { MongoCollection mc = db().getCollection(stmt.getCollection()); Document query = stmt.getQuery(); @@ -94,10 +171,59 @@ private Long executeUpdate(MongoStatement stmt) { return updateResult.getModifiedCount(); } + private DbResultDml executeUpdateAsDbResultDml(MongoStatement stmt) { + MongoCollection mc = db().getCollection(stmt.getCollection()); + Document query = stmt.getQuery(); + UpdateResult result = mc.updateMany(query, stmt.getValue()); + if (returnGeneratedKeys && result.wasAcknowledged()) { + BsonValue upsertedId = result.getUpsertedId(); + if (upsertedId != null) { + return DbResultDml.create( + Stream.of( + new MongoDbRow( + codec.decode( + new BsonDocumentReader(new BsonDocument("_id", upsertedId)), + decoderContext), + context())), + 1L); + } + } + return DbResultDml.create(Stream.of(), 1L); + } + private Long executeDelete(MongoStatement stmt) { MongoCollection mc = db().getCollection(stmt.getCollection()); Document query = stmt.getQuery(); DeleteResult deleteResult = mc.deleteMany(query); return deleteResult.getDeletedCount(); } + + private DbResultDml executeDeleteAsDbResultDml(MongoStatement stmt) { + return DbResultDml.create(Stream.of(), executeDelete(stmt)); + } + + private Long executeDml(MongoStatement stmt) { + switch (stmt.getOperation()) { + case INSERT: return executeInsert(stmt); + case UPDATE: return executeUpdate(stmt); + case DELETE: return executeDelete(stmt); + case COMMAND: + default: throw new UnsupportedOperationException(String.format( + "Statement operation %s is not supported as DML", + stmt.getOperation())); + } + } + + private DbResultDml executeDmlAsDbResultDml(MongoStatement stmt) { + switch (stmt.getOperation()) { + case INSERT: return executeInsertAsDbResultDml(stmt); + case UPDATE: return executeUpdateAsDbResultDml(stmt); + case DELETE: return executeDeleteAsDbResultDml(stmt); + case COMMAND: + default: throw new UnsupportedOperationException(String.format( + "Statement operation %s is not supported as DML", + stmt.getOperation())); + } + } + } diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/DBHelper.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/DBHelper.java index c031ed61727..4e75fb2ce7b 100644 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/DBHelper.java +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/DBHelper.java @@ -41,6 +41,10 @@ public static void createSchema(DbClient db) { exec.namedDml("create-types"); exec.namedDml("create-pokemons"); exec.namedDml("create-poketypes"); + exec.namedDml("create-matches"); + if (db.dbType().equals("jdbc:oracle")) { + exec.namedDml("create-matches-seq"); + } } catch (DbClientException ex) { ex.printStackTrace(System.err); } diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTestImpl.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTestImpl.java index 54eacadc05e..38c7493bfbc 100644 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTestImpl.java +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTestImpl.java @@ -15,15 +15,23 @@ */ package io.helidon.tests.integration.dbclient.common; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Stream; import io.helidon.config.Config; import io.helidon.dbclient.DbClient; +import io.helidon.dbclient.DbColumn; +import io.helidon.dbclient.DbResultDml; import io.helidon.dbclient.DbRow; import io.helidon.tests.integration.dbclient.common.model.Pokemon; import io.helidon.tests.integration.dbclient.common.model.Pokemons; import io.helidon.tests.integration.dbclient.common.model.Types; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; + /** * Actual implementation of {@link SimpleTests}. */ @@ -464,6 +472,120 @@ public void testInsertOrderArgs() { verifyInsertPokemon(result, pokemon); } + /** + * Verify {@code namedInsert(String)} API method with named parameters and returned generated keys. + */ + @Override + public void testInsertNamedArgsReturnedKeys() throws Exception { + try (DbResultDml result = db.execute().createNamedInsert("insert-match") + .addParam("red", Pokemons.RAICHU.id()) + .addParam("blue", Pokemons.MACHOP.id()) + .returnGeneratedKeys() + .insert()) { + List keys = result.generatedKeys().toList(); + long records = result.result(); + assertThat(records, equalTo(1L)); + assertThat(keys, hasSize(1)); + DbRow keysRow = keys.getFirst(); + AtomicInteger columnsCount = new AtomicInteger(0); + keysRow.forEach(dbColumn -> columnsCount.incrementAndGet()); + DbColumn keyByName; + // Result is vendor dependent + switch(db.dbType()) { + case "mongoDb": + assertThat(columnsCount.get(), equalTo(1)); + keyByName = keysRow.column("_id"); + break; + case "jdbc:h2": + assertThat(columnsCount.get(), equalTo(1)); + keyByName = keysRow.column("id"); + break; + case "jdbc:mysql": + assertThat(columnsCount.get(), equalTo(1)); + keyByName = keysRow.column("GENERATED_KEY"); + break; + case "jdbc:postgresql": + assertThat(columnsCount.get(), equalTo(3)); + keyByName = keysRow.column("id"); + break; + case "jdbc:oracle": + assertThat(columnsCount.get(), equalTo(1)); + keyByName = keysRow.column("ROWID"); + break; + default: + throw new IllegalStateException("Unknown database type: " + db.dbType()); + } + DbColumn keyByIndex = keysRow.column(1); + assertThat(keyByName, equalTo(keyByIndex)); + } + } + + /** + * Verify {@code namedInsert(String)} API method with named parameters and returned insert columns. + */ + @Override + public void testInsertNamedArgsReturnedColumns() throws Exception { + // Not supported in Mongo, skip the test + if (db.dbType().equals("mongoDb")) { + return; + } + try (DbResultDml result = db.execute().createNamedInsert("insert-match") + .addParam("red", Pokemons.SNORLAX.id()) + .addParam("blue", Pokemons.CHARIZARD.id()) + .returnColumns(List.of("id", "red")) + .insert()) { + List keys = result.generatedKeys().toList(); + long records = result.result(); + assertThat(records, equalTo(1L)); + assertThat(keys, hasSize(1)); + DbRow keysRow = keys.getFirst(); + AtomicInteger columnsCount = new AtomicInteger(0); + keysRow.forEach(dbColumn -> columnsCount.incrementAndGet()); + DbColumn idByName; + DbColumn idByIndex; + DbColumn redByName; + DbColumn redByIndex; + // Result is vendor dependent + switch(db.dbType()) { + case "jdbc:h2": + assertThat(columnsCount.get(), equalTo(2)); + idByName = keysRow.column("id"); + idByIndex = keysRow.column(1); + assertThat(idByName, equalTo(idByIndex)); + redByName = keysRow.column("red"); + redByIndex = keysRow.column(2); + assertThat(redByName, equalTo(redByIndex)); + break; + case "jdbc:mysql": + assertThat(columnsCount.get(), equalTo(1)); + idByName = keysRow.column("GENERATED_KEY"); + idByIndex = keysRow.column(1); + assertThat(idByName, equalTo(idByIndex)); + break; + case "jdbc:postgresql": + assertThat(columnsCount.get(), equalTo(2)); + idByName = keysRow.column("id"); + idByIndex = keysRow.column(1); + assertThat(idByName, equalTo(idByIndex)); + redByName = keysRow.column("red"); + redByIndex = keysRow.column(2); + assertThat(redByName, equalTo(redByIndex)); + break; + case "jdbc:oracle": + assertThat(columnsCount.get(), equalTo(2)); + idByName = keysRow.column("ID"); + idByIndex = keysRow.column(1); + assertThat(idByName, equalTo(idByIndex)); + redByName = keysRow.column("RED"); + redByIndex = keysRow.column(2); + assertThat(redByName, equalTo(redByIndex)); + break; + default: + throw new IllegalStateException("Unknown database type: " + db.dbType()); + } + } + } + @Override public void testCreateNamedQueryStrStrOrderArgs() { Pokemon expected = Pokemons.PIKACHU; diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTests.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTests.java index b9b3a935d45..443855bd2b3 100644 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTests.java +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTests.java @@ -256,6 +256,17 @@ interface InsertTest { * Verify {@code insert(String)} API method with ordered parameters passed directly to the {@code insert} method. */ void testInsertOrderArgs(); + + /** + * Verify {@code namedInsert(String)} API method with named parameters and returned generated keys. + */ + void testInsertNamedArgsReturnedKeys() throws Exception; + + /** + * Verify {@code namedInsert(String)} API method with named parameters and returned insert columns. + */ + void testInsertNamedArgsReturnedColumns() throws Exception; + } /** diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTestImpl.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTestImpl.java index 504463395e6..d2f39938215 100644 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTestImpl.java +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTestImpl.java @@ -16,15 +16,22 @@ package io.helidon.tests.integration.dbclient.common; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; import io.helidon.config.Config; import io.helidon.dbclient.DbClient; +import io.helidon.dbclient.DbColumn; +import io.helidon.dbclient.DbResultDml; import io.helidon.dbclient.DbRow; import io.helidon.dbclient.DbTransaction; import io.helidon.tests.integration.dbclient.common.model.Pokemon; import io.helidon.tests.integration.dbclient.common.model.Pokemons; import io.helidon.tests.integration.dbclient.common.model.Types; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; + /** * Actual implementation of {@link TransactionTests}. */ @@ -375,6 +382,126 @@ public void testInsertOrderArgs() { verifyInsertPokemon(result, pokemon); } + /** + * Verify {@code namedInsert(String)} API method with named parameters and returned generated keys. + */ + @Override + public void testInsertNamedArgsReturnedKeys() throws Exception { + DbTransaction tx = db.transaction(); + try (DbResultDml result = tx.createNamedInsert("insert-match") + .addParam("red", Pokemons.RAICHU.id()) + .addParam("blue", Pokemons.MACHOP.id()) + .returnGeneratedKeys() + .insert()) { + List keys = result.generatedKeys().toList(); + long records = result.result(); + assertThat(records, equalTo(1L)); + assertThat(keys, hasSize(1)); + DbRow keysRow = keys.getFirst(); + AtomicInteger columnsCount = new AtomicInteger(0); + keysRow.forEach(dbColumn -> columnsCount.incrementAndGet()); + DbColumn keyByName; + // Result is vendor dependent + switch(db.dbType()) { + case "mongoDb": + assertThat(columnsCount.get(), equalTo(1)); + keyByName = keysRow.column("_id"); + break; + case "jdbc:h2": + assertThat(columnsCount.get(), equalTo(1)); + keyByName = keysRow.column("id"); + break; + case "jdbc:mysql": + assertThat(columnsCount.get(), equalTo(1)); + keyByName = keysRow.column("GENERATED_KEY"); + break; + case "jdbc:postgresql": + assertThat(columnsCount.get(), equalTo(3)); + keyByName = keysRow.column("id"); + break; + case "jdbc:oracle": + assertThat(columnsCount.get(), equalTo(1)); + keyByName = keysRow.column("ROWID"); + break; + default: + throw new IllegalStateException("Unknown database type: " + db.dbType()); + } + DbColumn keyByIndex = keysRow.column(1); + assertThat(keyByName, equalTo(keyByIndex)); + tx.commit(); + } catch (Exception ex) { + tx.rollback(); + } + } + + /** + * Verify {@code namedInsert(String)} API method with named parameters and returned insert columns. + */ + @Override + public void testInsertNamedArgsReturnedColumns() throws Exception { + DbTransaction tx = db.transaction(); + try (DbResultDml result = tx.createNamedInsert("insert-match") + .addParam("red", Pokemons.SNORLAX.id()) + .addParam("blue", Pokemons.CHARIZARD.id()) + .returnColumns(List.of("id", "red")) + .insert()) { + List keys = result.generatedKeys().toList(); + long records = result.result(); + assertThat(records, equalTo(1L)); + assertThat(keys, hasSize(1)); + DbRow keysRow = keys.getFirst(); + AtomicInteger columnsCount = new AtomicInteger(0); + keysRow.forEach(dbColumn -> columnsCount.incrementAndGet()); + DbColumn idByName; + DbColumn idByIndex; + DbColumn redByName; + DbColumn redByIndex; + // Result is vendor dependent + switch(db.dbType()) { + case "mongoDb": + break; + case "jdbc:h2": + assertThat(columnsCount.get(), equalTo(2)); + idByName = keysRow.column("id"); + idByIndex = keysRow.column(1); + assertThat(idByName, equalTo(idByIndex)); + redByName = keysRow.column("red"); + redByIndex = keysRow.column(2); + assertThat(redByName, equalTo(redByIndex)); + break; + case "jdbc:mysql": + assertThat(columnsCount.get(), equalTo(1)); + idByName = keysRow.column("GENERATED_KEY"); + idByIndex = keysRow.column(1); + assertThat(idByName, equalTo(idByIndex)); + break; + case "jdbc:postgresql": + assertThat(columnsCount.get(), equalTo(2)); + idByName = keysRow.column("id"); + idByIndex = keysRow.column(1); + assertThat(idByName, equalTo(idByIndex)); + redByName = keysRow.column("red"); + redByIndex = keysRow.column(2); + assertThat(redByName, equalTo(redByIndex)); + break; + case "jdbc:oracle": + assertThat(columnsCount.get(), equalTo(2)); + idByName = keysRow.column("ID"); + idByIndex = keysRow.column(1); + assertThat(idByName, equalTo(idByIndex)); + redByName = keysRow.column("RED"); + redByIndex = keysRow.column(2); + assertThat(redByName, equalTo(redByIndex)); + break; + default: + throw new IllegalStateException("Unknown database type: " + db.dbType()); + } + tx.commit(); + } catch (Exception ex) { + tx.rollback(); + } + } + @Override public void testCreateNamedQueryStrStrOrderArgs() { Pokemon expected = Pokemons.PIKACHU; diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTests.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTests.java index a72aa0194ff..142ff422f81 100644 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTests.java +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTests.java @@ -172,6 +172,17 @@ interface TxInsertTest { * Verify {@code insert(String)} API method with ordered parameters passed directly to the {@code insert} method. */ void testInsertOrderArgs(); + + /** + * Verify {@code namedInsert(String)} API method with named parameters and returned generated keys. + */ + void testInsertNamedArgsReturnedKeys() throws Exception; + + /** + * Verify {@code namedInsert(String)} API method with named parameters and returned insert columns. + */ + void testInsertNamedArgsReturnedColumns() throws Exception; + } /** diff --git a/tests/integration/dbclient/common/src/main/resources/db-common.yaml b/tests/integration/dbclient/common/src/main/resources/db-common.yaml index fffece98bde..6b602f2c3c9 100644 --- a/tests/integration/dbclient/common/src/main/resources/db-common.yaml +++ b/tests/integration/dbclient/common/src/main/resources/db-common.yaml @@ -34,12 +34,20 @@ db: id_pokemon INTEGER NOT NULL REFERENCES Pokemons(id) ON DELETE CASCADE, id_type INTEGER NOT NULL REFERENCES Types(id) ON DELETE CASCADE ) + create-matches: | + CREATE TABLE Matches ( + id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, + red INTEGER NOT NULL REFERENCES Pokemons(id), + blue INTEGER NOT NULL REFERENCES Pokemons(id) + ) drop-types: "DROP TABLE Types" drop-pokemons: "DROP TABLE Pokemons" drop-poketypes: "DROP TABLE PokemonTypes" + drop-matches: "DROP TABLE Matches" insert-type: "INSERT INTO Types(id, name) VALUES(?, ?)" insert-pokemon: "INSERT INTO Pokemons(id, name) VALUES(?, ?)" insert-poketype: "INSERT INTO PokemonTypes(id_pokemon, id_type) VALUES(?, ?)" + insert-match: "INSERT INTO Matches(red, blue) VALUES (:red, :blue)" insert-pokemon-named-arg: "INSERT INTO Pokemons(id, name) VALUES(:id, :name)" insert-pokemon-order-arg: "INSERT INTO Pokemons(id, name) VALUES(?, ?)" insert-pokemon-order-arg-rev: "INSERT INTO Pokemons(name, id) VALUES(?, ?)" diff --git a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2SimpleLocalTestIT.java b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2SimpleLocalTestIT.java index c11f2c8b9e5..85cb25fb9ec 100644 --- a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2SimpleLocalTestIT.java +++ b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2SimpleLocalTestIT.java @@ -292,6 +292,18 @@ public void testInsertOrderArgs() { ctx.delegate().testInsertOrderArgs(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedKeys(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedColumns(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() { diff --git a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2SimpleRemoteTestIT.java b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2SimpleRemoteTestIT.java index 17073783943..74dfaa7f6bf 100644 --- a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2SimpleRemoteTestIT.java +++ b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2SimpleRemoteTestIT.java @@ -280,6 +280,18 @@ public void testInsertOrderArgs() { remoteTest(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() { + remoteTest(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() { + remoteTest(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() { diff --git a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2TransactionLocalTestIT.java b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2TransactionLocalTestIT.java index 92e36d1cafe..f36c1bee81a 100644 --- a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2TransactionLocalTestIT.java +++ b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2TransactionLocalTestIT.java @@ -196,6 +196,18 @@ public void testInsertOrderArgs() { ctx.delegate().testInsertOrderArgs(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedKeys(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedColumns(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() { diff --git a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2TransactionRemoteTestIT.java b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2TransactionRemoteTestIT.java index be12d2c9692..60ee6389545 100644 --- a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2TransactionRemoteTestIT.java +++ b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2TransactionRemoteTestIT.java @@ -184,6 +184,18 @@ public void testInsertOrderArgs() { remoteTest(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() { + remoteTest(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() { + remoteTest(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() { diff --git a/tests/integration/dbclient/mongodb/src/main/resources/db.yaml b/tests/integration/dbclient/mongodb/src/main/resources/db.yaml index 003f8d9306b..a33ee78dd18 100644 --- a/tests/integration/dbclient/mongodb/src/main/resources/db.yaml +++ b/tests/integration/dbclient/mongodb/src/main/resources/db.yaml @@ -76,6 +76,14 @@ db: "id_type": ? } } + insert-match: | + { + "collection": "matches", + "value": { + "red": $red, + "blue": $blue + } + } select-types: | { "collection": "types", diff --git a/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSimpleLocalTestIT.java b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSimpleLocalTestIT.java index 03f9e69f4c7..d5d831197de 100644 --- a/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSimpleLocalTestIT.java +++ b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSimpleLocalTestIT.java @@ -286,6 +286,18 @@ public void testInsertOrderArgs() { ctx.delegate().testInsertOrderArgs(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedKeys(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedColumns(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() { diff --git a/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSimpleRemoteTestIT.java b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSimpleRemoteTestIT.java index 5f6528cff1a..d2cec6e99c3 100644 --- a/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSimpleRemoteTestIT.java +++ b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSimpleRemoteTestIT.java @@ -280,6 +280,18 @@ public void testInsertOrderArgs() { remoteTest(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() { + remoteTest(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() { + remoteTest(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() { diff --git a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLSimpleLocalTestIT.java b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLSimpleLocalTestIT.java index c720de50a7b..2e33267ac80 100644 --- a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLSimpleLocalTestIT.java +++ b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLSimpleLocalTestIT.java @@ -286,6 +286,18 @@ public void testInsertOrderArgs() { ctx.delegate().testInsertOrderArgs(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedKeys(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedColumns(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() { diff --git a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLSimpleRemoteTestIT.java b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLSimpleRemoteTestIT.java index 050a0418c28..c8e5eb90d9c 100644 --- a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLSimpleRemoteTestIT.java +++ b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLSimpleRemoteTestIT.java @@ -280,6 +280,18 @@ public void testInsertOrderArgs() { remoteTest(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() { + remoteTest(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() { + remoteTest(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() { diff --git a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTransactionLocalTestIT.java b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTransactionLocalTestIT.java index 445ed8d30a3..fd747b2dfc2 100644 --- a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTransactionLocalTestIT.java +++ b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTransactionLocalTestIT.java @@ -190,6 +190,18 @@ public void testInsertOrderArgs() { ctx.delegate().testInsertOrderArgs(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedKeys(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedColumns(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() { diff --git a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTransactionRemoteTestIT.java b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTransactionRemoteTestIT.java index 7e9d495df94..cd9f9a12e64 100644 --- a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTransactionRemoteTestIT.java +++ b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTransactionRemoteTestIT.java @@ -184,6 +184,18 @@ public void testInsertOrderArgs() { remoteTest(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() { + remoteTest(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() { + remoteTest(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() { diff --git a/tests/integration/dbclient/oracle/src/main/resources/db.yaml b/tests/integration/dbclient/oracle/src/main/resources/db.yaml index f1daebdfa6c..85ee7e7c4c1 100644 --- a/tests/integration/dbclient/oracle/src/main/resources/db.yaml +++ b/tests/integration/dbclient/oracle/src/main/resources/db.yaml @@ -27,3 +27,11 @@ db: statement: "SELECT 1 FROM DUAL" statements: ping: "SELECT 1 FROM DUAL" + create-matches: | + CREATE TABLE Matches ( + id INTEGER NOT NULL PRIMARY KEY, + red INTEGER NOT NULL REFERENCES Pokemons(id), + blue INTEGER NOT NULL REFERENCES Pokemons(id) + ) + create-matches-seq: "CREATE SEQUENCE MatchesSeq START WITH 1" + insert-match: "INSERT INTO Matches(id, red, blue) VALUES (MatchesSeq.NEXTVAL, :red, :blue)" diff --git a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleSimpleLocalTestIT.java b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleSimpleLocalTestIT.java index 89f1883022a..c2970a752fd 100644 --- a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleSimpleLocalTestIT.java +++ b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleSimpleLocalTestIT.java @@ -286,6 +286,18 @@ public void testInsertOrderArgs() { ctx.delegate().testInsertOrderArgs(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedKeys(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedColumns(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() { diff --git a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleSimpleRemoteTestIT.java b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleSimpleRemoteTestIT.java index 92db52011dd..93eedf41a0c 100644 --- a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleSimpleRemoteTestIT.java +++ b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleSimpleRemoteTestIT.java @@ -280,6 +280,18 @@ public void testInsertOrderArgs() { remoteTest(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() { + remoteTest(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() { + remoteTest(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() { diff --git a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTransactionLocalTestIT.java b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTransactionLocalTestIT.java index 53a7a668521..e6c34e65b2c 100644 --- a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTransactionLocalTestIT.java +++ b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTransactionLocalTestIT.java @@ -190,6 +190,18 @@ public void testInsertOrderArgs() { ctx.delegate().testInsertOrderArgs(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedKeys(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedColumns(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() { diff --git a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTransactionRemoteTestIT.java b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTransactionRemoteTestIT.java index c23b5caf5ff..1731a9c46c7 100644 --- a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTransactionRemoteTestIT.java +++ b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTransactionRemoteTestIT.java @@ -184,6 +184,18 @@ public void testInsertOrderArgs() { remoteTest(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() { + remoteTest(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() { + remoteTest(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() { diff --git a/tests/integration/dbclient/pgsql/src/main/resources/db.yaml b/tests/integration/dbclient/pgsql/src/main/resources/db.yaml index 25d524ca4d8..f54be4de3a2 100644 --- a/tests/integration/dbclient/pgsql/src/main/resources/db.yaml +++ b/tests/integration/dbclient/pgsql/src/main/resources/db.yaml @@ -26,3 +26,10 @@ db: health-check: type: query statement: "SELECT 0" + statements: + create-matches: | + CREATE TABLE Matches ( + id SERIAL NOT NULL PRIMARY KEY, + red INTEGER NOT NULL REFERENCES Pokemons(id), + blue INTEGER NOT NULL REFERENCES Pokemons(id) + ) diff --git a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLSimpleLocalTestIT.java b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLSimpleLocalTestIT.java index a8fdbfd5380..a9997747fae 100644 --- a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLSimpleLocalTestIT.java +++ b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLSimpleLocalTestIT.java @@ -286,6 +286,18 @@ public void testInsertOrderArgs() { ctx.delegate().testInsertOrderArgs(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedKeys(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedColumns(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() { diff --git a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLSimpleRemoteTestIT.java b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLSimpleRemoteTestIT.java index d0607b5d7ab..8079e409041 100644 --- a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLSimpleRemoteTestIT.java +++ b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLSimpleRemoteTestIT.java @@ -280,6 +280,18 @@ public void testInsertOrderArgs() { remoteTest(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() { + remoteTest(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() { + remoteTest(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() { diff --git a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTransactionLocalTestIT.java b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTransactionLocalTestIT.java index 9258f730340..3c887695b92 100644 --- a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTransactionLocalTestIT.java +++ b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTransactionLocalTestIT.java @@ -190,6 +190,18 @@ public void testInsertOrderArgs() { ctx.delegate().testInsertOrderArgs(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedKeys(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() throws Exception { + ctx.delegate().testInsertNamedArgsReturnedColumns(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() { diff --git a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTransactionRemoteTestIT.java b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTransactionRemoteTestIT.java index 9341b4a26ec..880c643739e 100644 --- a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTransactionRemoteTestIT.java +++ b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTransactionRemoteTestIT.java @@ -184,6 +184,18 @@ public void testInsertOrderArgs() { remoteTest(); } + @Test + @Override + public void testInsertNamedArgsReturnedKeys() { + remoteTest(); + } + + @Test + @Override + public void testInsertNamedArgsReturnedColumns() { + remoteTest(); + } + @Test @Override public void testCreateNamedQueryStrStrOrderArgs() {