Skip to content

Commit 868dd3e

Browse files
committed
[DRAFT] Fix remaining test with MariaDB
1 parent 897a193 commit 868dd3e

11 files changed

+146
-30
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public CompletionStage<Void> reactiveExecute() throws HibernateException {
6363
final ReactiveEntityPersister reactivePersister = (ReactiveEntityPersister) persister;
6464
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
6565
return stage
66-
.thenCompose( v -> reactivePersister.insertReactive( id, getState(), instance, session ) )
66+
.thenCompose( v -> reactivePersister.insertReactive( id, getState(), instance, session, false ) )
6767
.thenCompose( generatedValues -> {
6868
final EntityEntry entry = persistenceContext.getEntry( instance );
6969
if ( entry == null ) {

hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/env/internal/ReactiveMutationExecutor.java

+73-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
import java.lang.invoke.MethodHandles;
99
import java.util.concurrent.CompletionStage;
1010

11+
import org.hibernate.dialect.DB2Dialect;
12+
import org.hibernate.dialect.Dialect;
13+
import org.hibernate.dialect.DialectDelegateWrapper;
14+
import org.hibernate.dialect.MySQLDialect;
15+
import org.hibernate.dialect.OracleDialect;
16+
import org.hibernate.dialect.SQLServerDialect;
1117
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
1218
import org.hibernate.engine.jdbc.mutation.MutationExecutor;
1319
import org.hibernate.engine.jdbc.mutation.OperationResultChecker;
@@ -52,7 +58,17 @@ default CompletionStage<GeneratedValues> executeReactive(
5258
TableInclusionChecker inclusionChecker,
5359
OperationResultChecker resultChecker,
5460
SharedSessionContractImplementor session) {
55-
return performReactiveNonBatchedOperations( modelReference, valuesAnalysis, inclusionChecker, resultChecker, session )
61+
return executeReactive( modelReference, valuesAnalysis, inclusionChecker, resultChecker, session, true );
62+
}
63+
64+
default CompletionStage<GeneratedValues> executeReactive(
65+
Object modelReference,
66+
ValuesAnalysis valuesAnalysis,
67+
TableInclusionChecker inclusionChecker,
68+
OperationResultChecker resultChecker,
69+
SharedSessionContractImplementor session,
70+
boolean isIdentityInsert) {
71+
return performReactiveNonBatchedOperations( modelReference, valuesAnalysis, inclusionChecker, resultChecker, session, isIdentityInsert )
5672
.thenCompose( generatedValues -> performReactiveSelfExecutingOperations( valuesAnalysis, inclusionChecker, session )
5773
.thenCompose( v -> performReactiveBatchedOperations( valuesAnalysis, inclusionChecker, resultChecker, session ) )
5874
.thenApply( v -> generatedValues )
@@ -64,7 +80,8 @@ default CompletionStage<GeneratedValues> performReactiveNonBatchedOperations(
6480
ValuesAnalysis valuesAnalysis,
6581
TableInclusionChecker inclusionChecker,
6682
OperationResultChecker resultChecker,
67-
SharedSessionContractImplementor session) {
83+
SharedSessionContractImplementor session,
84+
boolean isIdentityInsert) {
6885
return nullFuture();
6986
}
7087

@@ -82,6 +99,58 @@ default CompletionStage<Void> performReactiveBatchedOperations(
8299
return voidFuture();
83100
}
84101

102+
private static String createInsert(String insertSql, String identifierColumnName, Dialect dialect) {
103+
String sql = insertSql;
104+
final String sqlEnd = " returning " + identifierColumnName;
105+
Dialect realDialect = DialectDelegateWrapper.extractRealDialect( dialect );
106+
if ( realDialect instanceof MySQLDialect ) {
107+
// For some reason ORM generates a query with an invalid syntax
108+
int index = sql.lastIndexOf( sqlEnd );
109+
return index > -1
110+
? sql.substring( 0, index )
111+
: sql;
112+
}
113+
if ( realDialect instanceof SQLServerDialect ) {
114+
int index = sql.lastIndexOf( sqlEnd );
115+
// FIXME: this is a hack for HHH-16365
116+
if ( index > -1 ) {
117+
sql = sql.substring( 0, index );
118+
}
119+
if ( sql.endsWith( "default values" ) ) {
120+
index = sql.indexOf( "default values" );
121+
sql = sql.substring( 0, index );
122+
sql = sql + "output inserted." + identifierColumnName + " default values";
123+
}
124+
else {
125+
sql = sql.replace( ") values (", ") output inserted." + identifierColumnName + " values (" );
126+
}
127+
return sql;
128+
}
129+
if ( realDialect instanceof DB2Dialect ) {
130+
// ORM query: select id from new table ( insert into IntegerTypeEntity values ( ))
131+
// Correct : select id from new table ( insert into LongTypeEntity (id) values (default))
132+
return sql.replace( " values ( ))", " (" + identifierColumnName + ") values (default))" );
133+
}
134+
if ( realDialect instanceof OracleDialect ) {
135+
final String valuesStr = " values ( )";
136+
int index = sql.lastIndexOf( sqlEnd );
137+
// remove "returning id" since it's added via
138+
if ( index > -1 ) {
139+
sql = sql.substring( 0, index );
140+
}
141+
142+
// Oracle is expecting values (default)
143+
if ( sql.endsWith( valuesStr ) ) {
144+
index = sql.lastIndexOf( valuesStr );
145+
sql = sql.substring( 0, index );
146+
sql = sql + " values (default)";
147+
}
148+
149+
return sql;
150+
}
151+
return sql;
152+
}
153+
85154
/**
86155
* Perform a non-batched mutation
87156
*/
@@ -124,8 +193,9 @@ default CompletionStage<Void> performReactiveNonBatchedMutation(
124193
valueBindings.beforeStatement( details );
125194
} );
126195

196+
Dialect dialect = session.getJdbcServices().getDialect();
127197
ReactiveConnection reactiveConnection = ( (ReactiveConnectionSupplier) session ).getReactiveConnection();
128-
String sqlString = statementDetails.getSqlString();
198+
String sqlString = createInsert( statementDetails.getSqlString(), "id", dialect );
129199
return reactiveConnection
130200
.update( sqlString, params )
131201
.thenCompose( affectedRowCount -> {

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

+13-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
import java.util.concurrent.CompletionStage;
99

10+
import org.hibernate.dialect.Dialect;
11+
import org.hibernate.dialect.MariaDBDialect;
1012
import org.hibernate.engine.jdbc.mutation.OperationResultChecker;
1113
import org.hibernate.engine.jdbc.mutation.TableInclusionChecker;
1214
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
@@ -42,9 +44,10 @@ public CompletionStage<GeneratedValues> performReactiveNonBatchedOperations(
4244
ValuesAnalysis valuesAnalysis,
4345
TableInclusionChecker inclusionChecker,
4446
OperationResultChecker resultChecker,
45-
SharedSessionContractImplementor session) {
47+
SharedSessionContractImplementor session,
48+
boolean isIdentityInsert) {
4649
PreparedStatementDetails singleStatementDetails = getStatementGroup().getSingleStatementDetails();
47-
if ( generatedValuesDelegate != null ) {
50+
if ( generatedValuesDelegate != null && !isRegularInsertWithMariaDb( session, isIdentityInsert ) ) {
4851
return generatedValuesDelegate.reactivePerformMutation(
4952
singleStatementDetails,
5053
getJdbcValueBindings(),
@@ -62,6 +65,14 @@ public CompletionStage<GeneratedValues> performReactiveNonBatchedOperations(
6265
).thenCompose( CompletionStages::nullFuture );
6366
}
6467

68+
private boolean isRegularInsertWithMariaDb(SharedSessionContractImplementor session, boolean isIdentityInsert) {
69+
if ( isIdentityInsert ) {
70+
return false;
71+
}
72+
Dialect dialect = session.getJdbcServices().getDialect();
73+
return dialect instanceof MariaDBDialect;
74+
}
75+
6576
@Override
6677
public void release() {
6778
}

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ public CompletionStage<GeneratedValues> performReactiveNonBatchedOperations(
109109
ValuesAnalysis valuesAnalysis,
110110
TableInclusionChecker inclusionChecker,
111111
OperationResultChecker resultChecker,
112-
SharedSessionContractImplementor session) {
112+
SharedSessionContractImplementor session,
113+
boolean isIndentityInsert) {
113114

114115
if ( getNonBatchedStatementGroup() == null || getNonBatchedStatementGroup().getNumberOfStatements() <= 0 ) {
115116
return nullFuture();

hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/insert/ReactiveInsertReturningDelegate.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,11 @@ public ReactiveInsertReturningDelegate(PostInsertIdentityPersister persister, Di
5959
// With JDBC it's possible to enabled GetGeneratedKeys for identity generation.
6060
// Vert.x doesn't have this option, so we always use the same strategy for all database.
6161
// But MySQL requires setting supportsArbitraryValues to false or it's not going to work.
62-
this( persister, EventType.INSERT, !(dialect instanceof MySQLDialect) );
62+
this( persister, EventType.INSERT, supportsArbitraryValues( dialect ) );
63+
}
64+
65+
private static boolean supportsArbitraryValues( Dialect dialect) {
66+
return !( dialect instanceof MySQLDialect );
6367
}
6468

6569
private ReactiveInsertReturningDelegate(PostInsertIdentityPersister persister, EventType timing, boolean supportsArbitraryValues) {

hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveEntityPersister.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,16 @@ public interface ReactiveEntityPersister extends EntityPersister {
3232
*
3333
* @see EntityPersister#insert(Object, Object[], Object, SharedSessionContractImplementor)
3434
*/
35-
CompletionStage<GeneratedValues> insertReactive(Object id, Object[] fields, Object object, SharedSessionContractImplementor session);
35+
default CompletionStage<GeneratedValues> insertReactive(Object id, Object[] fields, Object object, SharedSessionContractImplementor session) {
36+
return insertReactive( id, fields, object, session );
37+
};
38+
39+
/**
40+
* Insert the given instance state without blocking, but it allows to specify if it's an identity insert or a regular one.
41+
*
42+
* @see EntityPersister#insert(Object, Object[], Object, SharedSessionContractImplementor)
43+
*/
44+
CompletionStage<GeneratedValues> insertReactive(Object id, Object[] fields, Object object, SharedSessionContractImplementor session, boolean isIdentityType);
3645

3746
/**
3847
* Insert the given instance state without blocking.

hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveJoinedSubclassEntityPersister.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,17 @@ public NaturalIdMapping generateNaturalIdMapping(MappingModelCreationProcess cre
179179

180180
@Override
181181
public CompletionStage<GeneratedValues> insertReactive(Object id, Object[] fields, Object object, SharedSessionContractImplementor session) {
182-
return ( (ReactiveInsertCoordinatorStandard) getInsertCoordinator() ).coordinateReactiveInsert( object, id, fields, session );
182+
return insertReactive( id, fields, object, session, true );
183+
}
184+
185+
@Override
186+
public CompletionStage<GeneratedValues> insertReactive(Object id, Object[] fields, Object object, SharedSessionContractImplementor session, boolean isIdentityInsert) {
187+
return ( (ReactiveInsertCoordinatorStandard) getInsertCoordinator() ).coordinateReactiveInsert( object, id, fields, session, isIdentityInsert );
183188
}
184189

185190
@Override
186191
public CompletionStage<GeneratedValues> insertReactive(Object[] fields, Object object, SharedSessionContractImplementor session) {
187-
return ( (ReactiveInsertCoordinatorStandard) getInsertCoordinator() ).coordinateReactiveInsert( object, null, fields, session );
192+
return ( (ReactiveInsertCoordinatorStandard) getInsertCoordinator() ).coordinateReactiveInsert( object, null, fields, session, true );
188193
}
189194

190195
@Override

hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveSingleTableEntityPersister.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -342,12 +342,17 @@ private CompletionStage<Object> doReactiveLoad(Object id, Object optionalObject,
342342

343343
@Override
344344
public CompletionStage<GeneratedValues> insertReactive(Object[] fields, Object entity, SharedSessionContractImplementor session) {
345-
return ( (ReactiveInsertCoordinatorStandard) getInsertCoordinator() ).coordinateReactiveInsert( entity, null, fields, session );
345+
return ( (ReactiveInsertCoordinatorStandard) getInsertCoordinator() ).coordinateReactiveInsert( entity, null, fields, session, true );
346346
}
347347

348348
@Override
349349
public CompletionStage<GeneratedValues> insertReactive(Object id, Object[] fields, Object entity, SharedSessionContractImplementor session) {
350-
return ( (ReactiveInsertCoordinatorStandard) getInsertCoordinator() ).coordinateReactiveInsert( entity, id, fields, session );
350+
return insertReactive( id, fields, entity, session, true );
351+
}
352+
353+
@Override
354+
public CompletionStage<GeneratedValues> insertReactive(Object id, Object[] fields, Object entity, SharedSessionContractImplementor session, boolean isIdentityInsert) {
355+
return ( (ReactiveInsertCoordinatorStandard) getInsertCoordinator() ).coordinateReactiveInsert( entity, id, fields, session, isIdentityInsert );
351356
}
352357

353358
@Override

hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveUnionSubclassEntityPersister.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -322,14 +322,19 @@ private CompletionStage<Object> doReactiveLoad(Object id, Object optionalObject,
322322

323323
@Override
324324
public CompletionStage<GeneratedValues> insertReactive(Object id, Object[] fields, Object entity, SharedSessionContractImplementor session) {
325+
return insertReactive( id, fields, entity, session, true );
326+
}
327+
328+
@Override
329+
public CompletionStage<GeneratedValues> insertReactive(Object id, Object[] fields, Object entity, SharedSessionContractImplementor session, boolean isIdentityInsert) {
325330
return ( (ReactiveInsertCoordinatorStandard) getInsertCoordinator() )
326-
.coordinateReactiveInsert( entity, id, fields, session );
331+
.coordinateReactiveInsert( entity, id, fields, session, isIdentityInsert );
327332
}
328333

329334
@Override
330335
public CompletionStage<GeneratedValues> insertReactive(Object[] fields, Object entity, SharedSessionContractImplementor session) {
331336
return ( (ReactiveInsertCoordinatorStandard) getInsertCoordinator() )
332-
.coordinateReactiveInsert( entity, null, fields, session );
337+
.coordinateReactiveInsert( entity, null, fields, session, true );
333338
}
334339

335340
@Override

hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/mutation/ReactiveInsertCoordinatorStandard.java

+12-8
Original file line numberDiff line numberDiff line change
@@ -117,20 +117,21 @@ public CompletionStage<GeneratedValues> reactiveInsert(
117117
Object id,
118118
Object[] values,
119119
SharedSessionContractImplementor session) {
120-
return coordinateReactiveInsert( entity, id, values, session );
120+
return coordinateReactiveInsert( entity, id, values, session, true );
121121
}
122122

123123
public CompletionStage<GeneratedValues> coordinateReactiveInsert(
124124
Object entity,
125125
Object id,
126126
Object[] values,
127-
SharedSessionContractImplementor session) {
127+
SharedSessionContractImplementor session,
128+
boolean isIdentityInsert) {
128129
return reactivePreInsertInMemoryValueGeneration( values, entity, session )
129130
.thenCompose( needsDynamicInsert -> {
130131
final boolean forceIdentifierBinding = entityPersister().getGenerator().generatedOnExecution() && id != null;
131132
return entityPersister().getEntityMetamodel().isDynamicInsert() || needsDynamicInsert || forceIdentifierBinding
132-
? doDynamicInserts( id, values, entity, session, forceIdentifierBinding )
133-
: doStaticInserts( id, values, entity, session );
133+
? doDynamicInserts( id, values, entity, session, forceIdentifierBinding, isIdentityInsert )
134+
: doStaticInserts( id, values, entity, session, isIdentityInsert );
134135
} );
135136
}
136137

@@ -207,7 +208,8 @@ protected CompletionStage<GeneratedValues> doDynamicInserts(
207208
Object[] values,
208209
Object object,
209210
SharedSessionContractImplementor session,
210-
boolean forceIdentifierBinding) {
211+
boolean forceIdentifierBinding,
212+
boolean isIdentityInsert) {
211213
final boolean[] insertability = getPropertiesToInsert( values );
212214
final MutationOperationGroup insertGroup = generateDynamicInsertSqlGroup( insertability, object, session, forceIdentifierBinding );
213215
final ReactiveMutationExecutor mutationExecutor = getReactiveMutationExecutor( session, insertGroup, true );
@@ -229,12 +231,13 @@ protected CompletionStage<GeneratedValues> doDynamicInserts(
229231
);
230232
return true;
231233
},
232-
session
234+
session,
235+
isIdentityInsert
233236
)
234237
.whenComplete( (o, t) -> mutationExecutor.release() ) );
235238
}
236239

237-
protected CompletionStage<GeneratedValues> doStaticInserts(Object id, Object[] values, Object object, SharedSessionContractImplementor session) {
240+
protected CompletionStage<GeneratedValues> doStaticInserts(Object id, Object[] values, Object object, SharedSessionContractImplementor session, boolean isIdentityInsert) {
238241
final InsertValuesAnalysis insertValuesAnalysis = new InsertValuesAnalysis( entityPersister(), values );
239242
final TableInclusionChecker tableInclusionChecker = getTableInclusionChecker( insertValuesAnalysis );
240243
final ReactiveMutationExecutor mutationExecutor = getReactiveMutationExecutor( session, staticInsertGroup, false );
@@ -248,7 +251,8 @@ protected CompletionStage<GeneratedValues> doStaticInserts(Object id, Object[] v
248251
statementDetails.getExpectation().verifyOutcome( affectedRowCount, statementDetails.getStatement(), batchPosition, statementDetails.getSqlString() );
249252
return true;
250253
},
251-
session
254+
session,
255+
isIdentityInsert
252256
) )
253257
.whenComplete( (generatedValues, throwable) -> mutationExecutor.release() );
254258
}

hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/exec/internal/ReactiveStandardMutationExecutorService.java

+9-7
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.hibernate.engine.jdbc.mutation.spi.BatchKeyAccess;
1414
import org.hibernate.engine.jdbc.mutation.spi.MutationExecutorService;
1515
import org.hibernate.engine.spi.SharedSessionContractImplementor;
16+
import org.hibernate.generator.values.GeneratedValuesMutationDelegate;
1617
import org.hibernate.internal.util.config.ConfigurationHelper;
1718
import org.hibernate.reactive.engine.jdbc.mutation.internal.ReactiveMutationExecutorSingleBatched;
1819
import org.hibernate.reactive.engine.jdbc.mutation.internal.ReactiveMutationExecutorSingleNonBatched;
@@ -64,15 +65,16 @@ public MutationExecutor createExecutor(
6465
return new ReactiveMutationExecutorSingleBatched( jdbcOperation, batchKey, batchSizeToUse, session );
6566
}
6667

67-
return new ReactiveMutationExecutorSingleNonBatched(
68-
jdbcOperation,
69-
operationGroup.asEntityMutationOperationGroup() != null
70-
? operationGroup.asEntityMutationOperationGroup().getMutationDelegate()
71-
: null,
72-
session
73-
);
68+
return new ReactiveMutationExecutorSingleNonBatched( jdbcOperation, generatedValuesDelegate( operationGroup ), session );
7469
}
7570

7671
return new ReactiveMutationExecutorStandard( operationGroup, batchKeySupplier, batchSizeToUse, session );
7772
}
73+
74+
private static GeneratedValuesMutationDelegate generatedValuesDelegate(MutationOperationGroup operationGroup) {
75+
GeneratedValuesMutationDelegate generatedValuesMutationDelegate = operationGroup.asEntityMutationOperationGroup() != null
76+
? operationGroup.asEntityMutationOperationGroup().getMutationDelegate()
77+
: null;
78+
return generatedValuesMutationDelegate;
79+
}
7880
}

0 commit comments

Comments
 (0)