From 226ca6236885120655feacd3dcf961d3bb344324 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Wed, 22 May 2024 11:25:21 +0200 Subject: [PATCH] [#1915] Fix NPE when batching inserts The NullPointerException because the method that converts the generated id from the database to a ResultSet was not implemented. We forgot about it because there was no test for identity generation with batching. --- .../adaptor/impl/ResultSetAdaptor.java | 68 ++++++++++++++++++- .../reactive/pool/BatchingConnection.java | 8 +-- 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/adaptor/impl/ResultSetAdaptor.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/adaptor/impl/ResultSetAdaptor.java index b481fdf01a..c9a021a4ac 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/adaptor/impl/ResultSetAdaptor.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/adaptor/impl/ResultSetAdaptor.java @@ -44,6 +44,7 @@ import io.vertx.sqlclient.PropertyKind; import io.vertx.sqlclient.Row; import io.vertx.sqlclient.RowSet; +import io.vertx.sqlclient.Tuple; import io.vertx.sqlclient.desc.ColumnDescriptor; import io.vertx.sqlclient.impl.RowBase; @@ -56,13 +57,71 @@ */ public class ResultSetAdaptor implements ResultSet { - private final Iterator iterator; + private final Iterator iterator; private final List columnDescriptors; private final List columnNames; private Row row; private boolean wasNull; + public ResultSetAdaptor(Object id, Class idClass, String columnName) { + requireNonNull( id ); + this.iterator = List.of( new RowAdaptor( id, idClass, columnName ) ).iterator(); + this.columnNames = columnName == null ? emptyList() : List.of( columnName ); + this.columnDescriptors = List.of( toColumnDescriptor( idClass, columnName ) ); + } + + private static class RowAdaptor implements Row { + private final Object id; + private final Class idClass; + private final String columnName; + + public RowAdaptor(Object id, Class idClass, String columnName) { + this.id = id; + this.idClass = idClass; + this.columnName = columnName; + } + + @Override + public Object getValue(String column) { + return id; + } + + @Override + public String getColumnName(int pos) { + return columnName; + } + + @Override + public int getColumnIndex(String column) { + return 0; + } + + @Override + public Object getValue(int pos) { + return id; + } + + @Override + public Tuple addValue(Object value) { + return null; + } + + @Override + public int size() { + return 1; + } + + @Override + public void clear() { + } + + @Override + public List> types() { + return List.of( idClass ); + } + } + public ResultSetAdaptor(RowSet rows) { requireNonNull( rows ); this.iterator = rows.iterator(); @@ -83,7 +142,11 @@ private ResultSetAdaptor(RowSet rows, Row row, String idColumnName, Class idClass, String idColumnName) { + return new ColumnDescriptor() { @Override public String name() { return idColumnName; @@ -104,7 +167,6 @@ public JDBCType jdbcType() { return null; } }; - this.columnDescriptors = List.of( columnDescriptor ); } private static class RowFromId extends RowBase { diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/BatchingConnection.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/BatchingConnection.java index 0d52341295..88062bc0b2 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/BatchingConnection.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/BatchingConnection.java @@ -12,6 +12,8 @@ import java.util.concurrent.CompletionStage; +import org.hibernate.reactive.adaptor.impl.ResultSetAdaptor; + import io.vertx.sqlclient.spi.DatabaseMetadata; import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture; @@ -169,11 +171,7 @@ public CompletionStage insertAndSelectIdentifierAsResultSet( Class idClass, String idColumnName) { return insertAndSelectIdentifier( sql, paramValues, idClass, idColumnName ) - .thenApply( this::convertToResultSet ); - } - - private ResultSet convertToResultSet(Object o) { - return null; + .thenApply( id -> new ResultSetAdaptor( id, idClass, idColumnName ) ); } public CompletionStage select(String sql) {