77
88import org .hibernate .HibernateException ;
99import org .hibernate .Internal ;
10+ import org .hibernate .dialect .CockroachDialect ;
1011import org .hibernate .dialect .Dialect ;
12+ import org .hibernate .dialect .MariaDBDialect ;
13+ import org .hibernate .dialect .MySQLDialect ;
14+ import org .hibernate .dialect .OracleDialect ;
1115import org .hibernate .engine .spi .SharedSessionContractImplementor ;
1216import org .hibernate .generator .EventType ;
1317import org .hibernate .generator .values .GeneratedValueBasicResultBuilder ;
1721import org .hibernate .generator .values .internal .GeneratedValuesImpl ;
1822import org .hibernate .generator .values .internal .GeneratedValuesMappingProducer ;
1923import org .hibernate .id .IdentifierGeneratorHelper ;
20- import org .hibernate .id .insert .GetGeneratedKeysDelegate ;
21- import org .hibernate .id .insert .UniqueKeySelectingDelegate ;
2224import org .hibernate .internal .CoreLogging ;
2325import org .hibernate .internal .CoreMessageLogger ;
2426import org .hibernate .metamodel .mapping .ModelPart ;
27+ import org .hibernate .metamodel .mapping .SelectableMapping ;
2528import org .hibernate .persister .entity .EntityPersister ;
2629import org .hibernate .pretty .MessageHelper ;
2730import org .hibernate .query .spi .QueryOptions ;
31+ import org .hibernate .reactive .id .insert .ReactiveGetGeneratedKeysDelegate ;
2832import org .hibernate .reactive .id .insert .ReactiveInsertReturningDelegate ;
33+ import org .hibernate .reactive .id .insert .ReactiveUniqueKeySelectingDelegate ;
2934import org .hibernate .reactive .sql .exec .spi .ReactiveRowProcessingState ;
3035import org .hibernate .reactive .sql .exec .spi .ReactiveValuesResultSet ;
3136import org .hibernate .reactive .sql .results .internal .ReactiveDirectResultSetAccess ;
3843import org .hibernate .sql .results .internal .RowTransformerArrayImpl ;
3944import org .hibernate .sql .results .jdbc .internal .JdbcValuesSourceProcessingStateStandardImpl ;
4045import org .hibernate .sql .results .jdbc .spi .JdbcValuesMappingProducer ;
41- import org .hibernate .sql .results .jdbc .spi .JdbcValuesSourceProcessingOptions ;
4246import org .hibernate .type .descriptor .WrapperOptions ;
4347
4448import java .sql .PreparedStatement ;
5155import static org .hibernate .generator .values .internal .GeneratedValuesHelper .noCustomSql ;
5256import static org .hibernate .internal .NaturalIdHelper .getNaturalIdPropertyNames ;
5357import 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 () );
0 commit comments