Skip to content

Commit 0e4d873

Browse files
committed
[#1906] Support @IdGeneratorType
1 parent 4e6abdb commit 0e4d873

23 files changed

+740
-254
lines changed

hibernate-reactive-core/src/main/java/org/hibernate/reactive/adaptor/impl/ResultSetAdaptor.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.time.LocalDate;
2929
import java.time.LocalDateTime;
3030
import java.time.LocalTime;
31+
import java.util.ArrayList;
3132
import java.util.Calendar;
3233
import java.util.Collection;
3334
import java.util.Iterator;
@@ -134,20 +135,27 @@ public ResultSetAdaptor(RowSet<Row> rows) {
134135
this.columnDescriptors = rows.columnDescriptors();
135136
}
136137

137-
public ResultSetAdaptor(RowSet<Row> rows, PropertyKind<Row> propertyKind, String idColumnName, Class<?> idClass) {
138-
this( rows, rows.property( propertyKind ), idColumnName, idClass );
138+
public ResultSetAdaptor(RowSet<Row> rows, PropertyKind<Row> propertyKind, List<String> generatedColumnNames, List<Class<?>> generatedColumnClasses) {
139+
this( rows, rows.property( propertyKind ), generatedColumnNames, generatedColumnClasses );
139140
}
140141

141142
public ResultSetAdaptor(RowSet<Row> rows, Collection<?> ids, String idColumnName, Class<?> idClass) {
142143
this( rows, new RowFromId( ids, idColumnName ), idColumnName, idClass );
143144
}
144145

145146
private ResultSetAdaptor(RowSet<Row> rows, Row row, String idColumnName, Class<?> idClass) {
147+
this( rows, row, List.of( idColumnName ), List.of( idClass ) );
148+
}
149+
150+
private ResultSetAdaptor(RowSet<Row> rows, Row row, List<String> columnNames, List<Class<?>> columnClasses) {
146151
requireNonNull( rows );
147-
requireNonNull( idColumnName );
152+
requireNonNull( columnNames );
148153
this.iterator = List.of( row ).iterator();
149-
this.columnNames = List.of( idColumnName );
150-
this.columnDescriptors = List.of( toColumnDescriptor( idClass, idColumnName ) );
154+
this.columnNames = columnNames ;
155+
this.columnDescriptors = new ArrayList<>(columnNames.size());
156+
for (int i =0; i < columnNames.size(); i++) {
157+
columnDescriptors.add( toColumnDescriptor( columnClasses.get( i ), columnNames.get(i) ) );
158+
}
151159
}
152160

153161
private static ColumnDescriptor toColumnDescriptor(Class<?> idClass, String idColumnName) {

hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveEntityIdentityInsertAction.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.hibernate.event.spi.EventSource;
1717
import org.hibernate.generator.values.GeneratedValues;
1818
import org.hibernate.internal.util.NullnessUtil;
19+
import org.hibernate.metamodel.mapping.EntityRowIdMapping;
1920
import org.hibernate.persister.entity.EntityPersister;
2021
import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister;
2122
import org.hibernate.stat.spi.StatisticsImplementor;
@@ -31,6 +32,7 @@ public class ReactiveEntityIdentityInsertAction extends EntityIdentityInsertActi
3132
private final boolean isVersionIncrementDisabled;
3233
private boolean executed;
3334
private boolean transientReferencesNullified;
35+
private Object rowId;
3436

3537
public ReactiveEntityIdentityInsertAction(
3638
Object[] state,
@@ -108,6 +110,13 @@ private CompletionStage<Void> processInsertGeneratedProperties(
108110
Object instance,
109111
GeneratedValues generatedValues,
110112
SharedSessionContractImplementor session) {
113+
final EntityRowIdMapping rowIdMapping = persister.getRowIdMapping();
114+
if ( rowIdMapping != null ) {
115+
rowId = generatedValues.getGeneratedValue( rowIdMapping );
116+
if ( rowId != null && !isEarlyInsert() ) {
117+
session.getPersistenceContext().replaceEntityEntryRowId( getInstance(), rowId );
118+
}
119+
}
111120
return persister.hasInsertGeneratedProperties()
112121
? persister.reactiveProcessInsertGenerated( generatedId, instance, getState(), generatedValues, session )
113122
: voidFuture();
@@ -153,4 +162,9 @@ public boolean areTransientReferencesNullified() {
153162
public void setTransientReferencesNullified() {
154163
transientReferencesNullified = true;
155164
}
165+
166+
@Override
167+
public Object getRowId() {
168+
return rowId;
169+
}
156170
}

hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveEntityRegularInsertAction.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.hibernate.engine.spi.SharedSessionContractImplementor;
1818
import org.hibernate.event.spi.EventSource;
1919
import org.hibernate.generator.values.GeneratedValues;
20+
import org.hibernate.metamodel.mapping.EntityRowIdMapping;
2021
import org.hibernate.persister.entity.EntityPersister;
2122
import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister;
2223
import org.hibernate.stat.spi.StatisticsImplementor;
@@ -111,8 +112,19 @@ private CompletionStage<Void> processInsertGeneratedProperties(
111112
// setVersion( Versioning.getVersion( getState(), persister ) );
112113
}
113114
return persister.reactiveProcessInsertGenerated( id, instance, getState(), generatedValues, session )
114-
.thenAccept( v -> entry.postUpdate( instance, getState(), getVersion() ) );
115-
115+
.thenAccept( v -> {
116+
// Process row-id values when available early by replacing the entity entry
117+
if ( generatedValues != null ) {
118+
final EntityRowIdMapping rowIdMapping = persister.getRowIdMapping();
119+
if ( rowIdMapping != null ) {
120+
final Object rowId = generatedValues.getGeneratedValue( rowIdMapping );
121+
if ( rowId != null ) {
122+
session.getPersistenceContext().replaceEntityEntryRowId( getInstance(), rowId );
123+
}
124+
}
125+
}
126+
entry.postUpdate( instance, getState(), getVersion() );
127+
} );
116128
}
117129
else {
118130
return voidFuture();

hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveEntityUpdateAction.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.hibernate.engine.spi.Status;
1616
import org.hibernate.event.spi.EventSource;
1717
import org.hibernate.generator.values.GeneratedValues;
18+
import org.hibernate.metamodel.mapping.EntityRowIdMapping;
1819
import org.hibernate.persister.entity.EntityPersister;
1920
import org.hibernate.reactive.engine.ReactiveExecutable;
2021
import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister;
@@ -143,7 +144,19 @@ private CompletionStage<Void> processGeneratedProperties(
143144
throw new UnsupportedOperationException( "generated version attribute not supported in Hibernate Reactive" );
144145
// setNextVersion( Versioning.getVersion( getState(), persister ) );
145146
}
146-
return persister.reactiveProcessUpdateGenerated( id, instance, getState(), generatedValues, session );
147+
return persister.reactiveProcessUpdateGenerated( id, instance, getState(), generatedValues, session )
148+
.thenAccept( v -> {
149+
// Process row-id values when available early by replacing the entity entry
150+
if ( generatedValues != null ) {
151+
final EntityRowIdMapping rowIdMapping = persister.getRowIdMapping();
152+
if ( rowIdMapping != null ) {
153+
final Object rowId = generatedValues.getGeneratedValue( rowIdMapping );
154+
if ( rowId != null ) {
155+
session.getPersistenceContext().replaceEntityEntryRowId( getInstance(), rowId );
156+
}
157+
}
158+
}
159+
} );
147160

148161
}
149162
else {

hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/mutation/internal/ReactiveMutationExecutorSingleNonBatched.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77

88
import java.util.concurrent.CompletionStage;
99

10-
import org.hibernate.dialect.Dialect;
11-
import org.hibernate.dialect.MariaDBDialect;
1210
import org.hibernate.engine.jdbc.mutation.OperationResultChecker;
1311
import org.hibernate.engine.jdbc.mutation.TableInclusionChecker;
1412
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
@@ -48,7 +46,7 @@ public CompletionStage<GeneratedValues> performReactiveNonBatchedOperations(
4846
boolean isIdentityInsert,
4947
String[] identifierColumnsNames) {
5048
PreparedStatementDetails singleStatementDetails = getStatementGroup().getSingleStatementDetails();
51-
if ( generatedValuesDelegate != null && !isRegularInsertWithMariaDb( session, isIdentityInsert ) ) {
49+
if ( generatedValuesDelegate != null ) {
5250
return generatedValuesDelegate.reactivePerformMutation(
5351
singleStatementDetails,
5452
getJdbcValueBindings(),
@@ -67,14 +65,6 @@ public CompletionStage<GeneratedValues> performReactiveNonBatchedOperations(
6765
).thenCompose( CompletionStages::nullFuture );
6866
}
6967

70-
private boolean isRegularInsertWithMariaDb(SharedSessionContractImplementor session, boolean isIdentityInsert) {
71-
if ( isIdentityInsert ) {
72-
return false;
73-
}
74-
Dialect dialect = session.getJdbcServices().getDialect();
75-
return dialect instanceof MariaDBDialect;
76-
}
77-
7868
@Override
7969
public void release() {
8070
}

hibernate-reactive-core/src/main/java/org/hibernate/reactive/generator/values/GeneratedValuesMutationDelegateAdaptor.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
import org.hibernate.sql.model.ast.builder.TableMutationBuilder;
2020
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
2121

22+
/**
23+
* @deprecated No longer used
24+
*/
25+
@Deprecated(since = "7.1", forRemoval = true)
2226
public class GeneratedValuesMutationDelegateAdaptor implements ReactiveGeneratedValuesMutationDelegate {
2327
private final ReactiveGeneratedValuesMutationDelegate delegate;
2428

hibernate-reactive-core/src/main/java/org/hibernate/reactive/generator/values/internal/ReactiveGeneratedValuesHelper.java

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77

88
import org.hibernate.HibernateException;
99
import org.hibernate.Internal;
10+
import org.hibernate.dialect.CockroachDialect;
1011
import org.hibernate.dialect.Dialect;
12+
import org.hibernate.dialect.MariaDBDialect;
13+
import org.hibernate.dialect.MySQLDialect;
14+
import org.hibernate.dialect.OracleDialect;
1115
import org.hibernate.engine.spi.SharedSessionContractImplementor;
1216
import org.hibernate.generator.EventType;
1317
import org.hibernate.generator.values.GeneratedValueBasicResultBuilder;
@@ -17,15 +21,16 @@
1721
import org.hibernate.generator.values.internal.GeneratedValuesImpl;
1822
import org.hibernate.generator.values.internal.GeneratedValuesMappingProducer;
1923
import org.hibernate.id.IdentifierGeneratorHelper;
20-
import org.hibernate.id.insert.GetGeneratedKeysDelegate;
21-
import org.hibernate.id.insert.UniqueKeySelectingDelegate;
2224
import org.hibernate.internal.CoreLogging;
2325
import org.hibernate.internal.CoreMessageLogger;
2426
import org.hibernate.metamodel.mapping.ModelPart;
27+
import org.hibernate.metamodel.mapping.SelectableMapping;
2528
import org.hibernate.persister.entity.EntityPersister;
2629
import org.hibernate.pretty.MessageHelper;
2730
import org.hibernate.query.spi.QueryOptions;
31+
import org.hibernate.reactive.id.insert.ReactiveGetGeneratedKeysDelegate;
2832
import org.hibernate.reactive.id.insert.ReactiveInsertReturningDelegate;
33+
import org.hibernate.reactive.id.insert.ReactiveUniqueKeySelectingDelegate;
2934
import org.hibernate.reactive.sql.exec.spi.ReactiveRowProcessingState;
3035
import org.hibernate.reactive.sql.exec.spi.ReactiveValuesResultSet;
3136
import org.hibernate.reactive.sql.results.internal.ReactiveDirectResultSetAccess;
@@ -38,7 +43,6 @@
3843
import org.hibernate.sql.results.internal.RowTransformerArrayImpl;
3944
import org.hibernate.sql.results.jdbc.internal.JdbcValuesSourceProcessingStateStandardImpl;
4045
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
41-
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
4246
import org.hibernate.type.descriptor.WrapperOptions;
4347

4448
import java.sql.PreparedStatement;
@@ -51,6 +55,7 @@
5155
import static org.hibernate.generator.values.internal.GeneratedValuesHelper.noCustomSql;
5256
import static org.hibernate.internal.NaturalIdHelper.getNaturalIdPropertyNames;
5357
import static org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer.UniqueSemantic.NONE;
58+
import static org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions.NO_OPTIONS;
5459

5560
/**
5661
* @see org.hibernate.generator.values.internal.GeneratedValuesHelper
@@ -64,13 +69,21 @@ public class ReactiveGeneratedValuesHelper {
6469
* @see GeneratedValuesHelper#getGeneratedValuesDelegate(EntityPersister, EventType)
6570
*/
6671
public static GeneratedValuesMutationDelegate getGeneratedValuesDelegate(EntityPersister persister, EventType timing) {
67-
final boolean hasGeneratedProperties = !persister.getGeneratedProperties( timing ).isEmpty();
72+
final List<? extends ModelPart> generatedProperties = persister.getGeneratedProperties( timing );
73+
final boolean hasGeneratedProperties = !generatedProperties.isEmpty();
6874
final boolean hasRowId = timing == EventType.INSERT && persister.getRowIdMapping() != null;
6975
final Dialect dialect = persister.getFactory().getJdbcServices().getDialect();
7076

77+
final boolean hasFormula =
78+
generatedProperties.stream()
79+
.anyMatch( part -> part instanceof SelectableMapping selectable
80+
&& selectable.isFormula() );
81+
82+
// Cockroach supports insert returning it but the CockroachDb#supportsInsertReturningRowId() wrongly returns false ( https://hibernate.atlassian.net/browse/HHH-19717 )
83+
boolean supportsInsertReturningRowId = dialect.supportsInsertReturningRowId() || dialect instanceof CockroachDialect;
7184
if ( hasRowId
72-
&& dialect.supportsInsertReturning()
73-
&& dialect.supportsInsertReturningRowId()
85+
&& supportsInsertReturning( dialect )
86+
&& supportsInsertReturningRowId
7487
&& noCustomSql( persister, timing ) ) {
7588
// Special case for RowId on INSERT, since GetGeneratedKeysDelegate doesn't support it
7689
// make InsertReturningDelegate the preferred method if the dialect supports it
@@ -81,26 +94,40 @@ && noCustomSql( persister, timing ) ) {
8194
return null;
8295
}
8396

84-
if ( dialect.supportsInsertReturningGeneratedKeys()
85-
&& persister.getFactory().getSessionFactoryOptions().isGetGeneratedKeysEnabled() ) {
86-
return new GetGeneratedKeysDelegate( persister, false, timing );
87-
}
88-
else if ( supportsReturning( dialect, timing ) && noCustomSql( persister, timing ) ) {
97+
if ( supportsReturning( dialect, timing ) && noCustomSql( persister, timing ) ) {
8998
return new ReactiveInsertReturningDelegate( persister, timing );
9099
}
91-
else if ( timing == EventType.INSERT && persister.getNaturalIdentifierProperties() != null
92-
&& !persister.getEntityMetamodel().isNaturalIdentifierInsertGenerated() ) {
93-
return new UniqueKeySelectingDelegate(
94-
persister,
95-
getNaturalIdPropertyNames( persister ),
96-
timing
97-
);
100+
else if ( !hasFormula && dialect.supportsInsertReturningGeneratedKeys() ) {
101+
return new ReactiveGetGeneratedKeysDelegate( persister, false, timing );
102+
}
103+
else if ( timing == EventType.INSERT && persister.getNaturalIdentifierProperties() != null && !persister.getEntityMetamodel()
104+
.isNaturalIdentifierInsertGenerated() ) {
105+
return new ReactiveUniqueKeySelectingDelegate( persister, getNaturalIdPropertyNames( persister ), timing );
98106
}
99107
return null;
100108
}
101109

102-
private static boolean supportsReturning(Dialect dialect, EventType timing) {
103-
return timing == EventType.INSERT ? dialect.supportsInsertReturning() : dialect.supportsUpdateReturning();
110+
public static boolean supportReactiveGetGeneratedKey(Dialect dialect, List<? extends ModelPart> generatedProperties) {
111+
return dialect instanceof OracleDialect
112+
|| (dialect instanceof MySQLDialect && generatedProperties.size() == 1 && !(dialect instanceof MariaDBDialect));
113+
}
114+
115+
public static boolean supportsReturning(Dialect dialect, EventType timing) {
116+
if ( dialect instanceof CockroachDialect ) {
117+
// Cockroach supports insert and update returning but the CockroachDb#supportsInsertReturning() wrongly returns false ( https://hibernate.atlassian.net/browse/HHH-19717 )
118+
return true;
119+
}
120+
return timing == EventType.INSERT
121+
? dialect.supportsInsertReturning()
122+
: dialect.supportsUpdateReturning();
123+
}
124+
125+
public static boolean supportsInsertReturning(Dialect dialect) {
126+
if ( dialect instanceof CockroachDialect ) {
127+
// Cockroach supports insert returning but the CockroachDb#supportsInsertReturning() wrongly returns false ( https://hibernate.atlassian.net/browse/HHH-19717 )
128+
return true;
129+
}
130+
return dialect.supportsInsertReturning();
104131
}
105132

106133
/**
@@ -181,31 +208,9 @@ private static CompletionStage<Object[]> readGeneratedValues(
181208
executionContext
182209
);
183210

184-
final JdbcValuesSourceProcessingOptions processingOptions = new JdbcValuesSourceProcessingOptions() {
185-
@Override
186-
public Object getEffectiveOptionalObject() {
187-
return null;
188-
}
189-
190-
@Override
191-
public String getEffectiveOptionalEntityName() {
192-
return null;
193-
}
194-
195-
@Override
196-
public Object getEffectiveOptionalId() {
197-
return null;
198-
}
199-
200-
@Override
201-
public boolean shouldReturnProxies() {
202-
return true;
203-
}
204-
};
205-
206211
final JdbcValuesSourceProcessingStateStandardImpl valuesProcessingState = new JdbcValuesSourceProcessingStateStandardImpl(
207212
executionContext,
208-
processingOptions
213+
NO_OPTIONS
209214
);
210215

211216
final ReactiveRowReader<Object[]> rowReader = ReactiveResultsHelper.createRowReader(
@@ -217,7 +222,7 @@ public boolean shouldReturnProxies() {
217222

218223
final ReactiveRowProcessingState rowProcessingState = new ReactiveRowProcessingState( valuesProcessingState, executionContext, rowReader, jdbcValues );
219224
return ReactiveListResultsConsumer.<Object[]>instance( NONE )
220-
.consume( jdbcValues, session, processingOptions, valuesProcessingState, rowProcessingState, rowReader )
225+
.consume( jdbcValues, session, NO_OPTIONS, valuesProcessingState, rowProcessingState, rowReader )
221226
.thenApply( results -> {
222227
if ( results.isEmpty() ) {
223228
throw new HibernateException( "The database returned no natively generated values : " + persister.getNavigableRole().getFullPath() );

hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/ReactiveIdentifierGenerator.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@
66
package org.hibernate.reactive.id;
77

88
import org.hibernate.Incubating;
9+
import org.hibernate.engine.spi.SharedSessionContractImplementor;
910
import org.hibernate.generator.EventType;
10-
import org.hibernate.generator.Generator;
1111
import org.hibernate.id.IdentifierGenerator;
12+
import org.hibernate.reactive.logging.impl.Log;
13+
import org.hibernate.reactive.logging.impl.LoggerFactory;
1214
import org.hibernate.reactive.session.ReactiveConnectionSupplier;
1315

16+
import java.lang.invoke.MethodHandles;
1417
import java.util.concurrent.CompletionStage;
1518

1619
/**
@@ -26,7 +29,8 @@
2629
* @see IdentifierGenerator
2730
*/
2831
@Incubating
29-
public interface ReactiveIdentifierGenerator<Id> extends Generator {
32+
public interface ReactiveIdentifierGenerator<Id> extends IdentifierGenerator {
33+
Log LOG = LoggerFactory.make( Log.class, MethodHandles.lookup() );
3034

3135
/**
3236
* Returns a generated identifier, via a {@link CompletionStage}.
@@ -38,4 +42,18 @@ public interface ReactiveIdentifierGenerator<Id> extends Generator {
3842
default CompletionStage<Id> generate(ReactiveConnectionSupplier session, Object owner, Object currentValue, EventType eventType) {
3943
return generate( session, owner );
4044
}
45+
46+
@Override
47+
default Id generate(
48+
SharedSessionContractImplementor session,
49+
Object owner,
50+
Object currentValue,
51+
EventType eventType){
52+
throw LOG.nonReactiveMethodCall( "generate(ReactiveConnectionSupplier, Object, Object, EventType)" );
53+
}
54+
55+
@Override
56+
default Object generate(SharedSessionContractImplementor session, Object object){
57+
throw LOG.nonReactiveMethodCall( "generate(ReactiveConnectionSupplier, Object)" );
58+
}
4159
}

0 commit comments

Comments
 (0)