diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java index e231c4d34e..dd34af0ae5 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java @@ -128,7 +128,7 @@ public class EntityDeleteAction extends EntityAction { final Object ck = lockCacheItem(); if ( !isCascadeDeleteEnabled && !veto ) { - persister.delete( id, version, instance, session ); + persister.getDeleteCoordinator().delete( instance, id, version, session ); } if ( isInstanceLoaded() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java index 5de15f0493..9e224b3286 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java @@ -107,7 +107,12 @@ public class EntityInsertAction extends AbstractEntityInsertAction { if ( !veto ) { final EntityPersister persister = getPersister(); final Object instance = getInstance(); - final GeneratedValues generatedValues = persister.insertReturning( id, getState(), instance, session ); + final GeneratedValues generatedValues = persister.getInsertCoordinator().insert( + instance, + id, + getState(), + session + ); final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); final EntityEntry entry = persistenceContext.getEntry( instance ); if ( entry == null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java index 3ffaf89c29..96716febb3 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java @@ -166,15 +166,15 @@ public class EntityUpdateAction extends EntityAction { final Object instance = getInstance(); final Object previousVersion = getPreviousVersion(); final Object ck = lockCacheItem( previousVersion ); - final GeneratedValues generatedValues = persister.updateReturning( + final GeneratedValues generatedValues = persister.getUpdateCoordinator().update( + instance, id, + rowId, state, + previousVersion, + previousState, dirtyFields, hasDirtyCollection, - previousState, - previousVersion, - instance, - rowId, session ); final EntityEntry entry = session.getPersistenceContextInternal().getEntry( instance ); diff --git a/hibernate-core/src/main/java/org/hibernate/id/insert/UniqueKeySelectingDelegate.java b/hibernate-core/src/main/java/org/hibernate/id/insert/UniqueKeySelectingDelegate.java index b1680145c0..373118dd84 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/insert/UniqueKeySelectingDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/id/insert/UniqueKeySelectingDelegate.java @@ -77,6 +77,7 @@ public class UniqueKeySelectingDelegate extends AbstractSelectingDelegate { } } + @Override protected String getSelectSQL() { return selectString; } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java index 5d266a2ef9..5a994801e6 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java @@ -50,6 +50,7 @@ import static org.hibernate.engine.internal.Versioning.incrementVersion; import static org.hibernate.engine.internal.Versioning.seedVersion; import static org.hibernate.engine.internal.Versioning.setVersion; import static org.hibernate.generator.EventType.INSERT; +import static org.hibernate.internal.util.NullnessUtil.castNonNull; import static org.hibernate.pretty.MessageHelper.infoString; import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer; @@ -108,11 +109,11 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen persister.setValues( entity, state ); } } - persister.insertReturning( id, state, entity, this ); + persister.getInsertCoordinator().insert( entity, id, state, this ); } else { - final GeneratedValues generatedValues = persister.insertReturning( state, entity, this ); - id = generatedValues.getGeneratedValue( persister.getIdentifierMapping() ); + final GeneratedValues generatedValues = persister.getInsertCoordinator().insert( entity, state, this ); + id = castNonNull( generatedValues ).getGeneratedValue( persister.getIdentifierMapping() ); } persister.setIdentifier( entity, id, this ); return id; @@ -133,7 +134,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen final EntityPersister persister = getEntityPersister( entityName, entity ); final Object id = persister.getIdentifier( entity, this ); final Object version = persister.getVersion( entity ); - persister.delete( id, version, entity, this ); + persister.getDeleteCoordinator().delete( entity, id, version, this ); } @@ -167,7 +168,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen else { oldVersion = null; } - persister.updateReturning( id, state, null, false, null, oldVersion, entity, null, this ); + persister.getUpdateCoordinator().update( entity, id, null, state, oldVersion, null, null, false, this ); } @Override @@ -203,7 +204,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen else { oldVersion = null; } - persister.merge( id, state, null, false, null, oldVersion, entity, null, this ); + persister.getMergeCoordinator().update( entity, id, null, state, oldVersion, null, null, false, this ); // persister.setIdentifier( entity, id, this ); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 23fa38dc5f..b8e65b33a5 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -216,6 +216,7 @@ import org.hibernate.persister.entity.mutation.DeleteCoordinatorStandard; import org.hibernate.persister.entity.mutation.EntityMutationTarget; import org.hibernate.persister.entity.mutation.EntityTableMapping; import org.hibernate.persister.entity.mutation.InsertCoordinator; +import org.hibernate.persister.entity.mutation.InsertCoordinatorStandard; import org.hibernate.persister.entity.mutation.MergeCoordinator; import org.hibernate.persister.entity.mutation.UpdateCoordinator; import org.hibernate.persister.entity.mutation.UpdateCoordinatorNoOp; @@ -1050,22 +1051,22 @@ public abstract class AbstractEntityPersister return lazyLoadPlanByFetchGroup.get( fetchGroup ); } - @Internal + @Override public InsertCoordinator getInsertCoordinator() { return insertCoordinator; } - @Internal + @Override public UpdateCoordinator getUpdateCoordinator() { return updateCoordinator; } - @Internal + @Override public DeleteCoordinator getDeleteCoordinator() { return deleteCoordinator; } - @Internal + @Override public UpdateCoordinator getMergeCoordinator() { return mergeCoordinator; } @@ -2813,60 +2814,6 @@ public abstract class AbstractEntityPersister return select.toStatementString(); } - /** - * Update an object - */ - @Override - public GeneratedValues updateReturning( - final Object id, - final Object[] values, - int[] dirtyAttributeIndexes, - final boolean hasDirtyCollection, - final Object[] oldValues, - final Object oldVersion, - final Object object, - final Object rowId, - final SharedSessionContractImplementor session) throws HibernateException { - return updateCoordinator.coordinateUpdate( - object, - id, - rowId, - values, - oldVersion, - oldValues, - dirtyAttributeIndexes, - hasDirtyCollection, - session - ); - } - - /** - * Merge an object - */ - @Override - public void merge( - final Object id, - final Object[] values, - int[] dirtyAttributeIndexes, - final boolean hasDirtyCollection, - final Object[] oldValues, - final Object oldVersion, - final Object object, - final Object rowId, - final SharedSessionContractImplementor session) throws HibernateException { - mergeCoordinator.coordinateUpdate( - object, - id, - rowId, - values, - oldVersion, - oldValues, - dirtyAttributeIndexes, - hasDirtyCollection, - session - ); - } - @Internal public boolean hasLazyDirtyFields(int[] dirtyFields) { final boolean[] propertyLaziness = getPropertyLaziness(); @@ -2888,16 +2835,6 @@ public abstract class AbstractEntityPersister return updateDelegate; } - @Override - public GeneratedValues insertReturning(Object[] fields, Object object, SharedSessionContractImplementor session) { - return insertCoordinator.coordinateInsert( null, fields, object, session ); - } - - @Override - public GeneratedValues insertReturning(Object id, Object[] fields, Object object, SharedSessionContractImplementor session) { - return insertCoordinator.coordinateInsert( id, fields, object, session ); - } - protected EntityTableMapping[] getTableMappings() { return tableMappings; } @@ -3001,7 +2938,7 @@ public abstract class AbstractEntityPersister */ @Override public void delete(Object id, Object version, Object object, SharedSessionContractImplementor session) { - deleteCoordinator.coordinateDelete( object, id, version, session ); + deleteCoordinator.delete( object, id, version, session ); } /** @@ -3023,7 +2960,7 @@ public abstract class AbstractEntityPersister } { - final MutationOperationGroup staticInsertGroup = insertCoordinator.getStaticInsertGroup(); + final MutationOperationGroup staticInsertGroup = insertCoordinator.getStaticMutationOperationGroup(); if ( staticInsertGroup != null ) { for ( int i = 0; i < staticInsertGroup.getNumberOfOperations(); i++ ) { final MutationOperation mutation = staticInsertGroup.getOperation( i ); @@ -3035,7 +2972,7 @@ public abstract class AbstractEntityPersister } { - final MutationOperationGroup staticUpdateGroup = updateCoordinator.getStaticUpdateGroup(); + final MutationOperationGroup staticUpdateGroup = updateCoordinator.getStaticMutationOperationGroup(); if ( staticUpdateGroup != null ) { for ( int i = 0; i < staticUpdateGroup.getNumberOfOperations(); i++ ) { final MutationOperation mutation = staticUpdateGroup.getOperation( i ); @@ -3047,7 +2984,7 @@ public abstract class AbstractEntityPersister } { - final MutationOperationGroup staticDeleteGroup = deleteCoordinator.getStaticDeleteGroup(); + final MutationOperationGroup staticDeleteGroup = deleteCoordinator.getStaticMutationOperationGroup(); if ( staticDeleteGroup != null ) { for ( int i = 0; i < staticDeleteGroup.getNumberOfOperations(); i++ ) { final MutationOperation mutation = staticDeleteGroup.getOperation( i ); @@ -3672,7 +3609,7 @@ public abstract class AbstractEntityPersister protected abstract boolean isIdentifierTable(String tableExpression); protected InsertCoordinator buildInsertCoordinator() { - return new InsertCoordinator( this, factory ); + return new InsertCoordinatorStandard( this, factory ); } protected UpdateCoordinator buildUpdateCoordinator() { @@ -6409,7 +6346,7 @@ public abstract class AbstractEntityPersister @Deprecated(forRemoval = true) @Remove public String[] getSQLDeleteStrings() { - return extractSqlStrings( deleteCoordinator.getStaticDeleteGroup() ); + return extractSqlStrings( deleteCoordinator.getStaticMutationOperationGroup() ); } private String[] extractSqlStrings(MutationOperationGroup operationGroup) { @@ -6431,7 +6368,7 @@ public abstract class AbstractEntityPersister @Deprecated(forRemoval = true) @Remove public String[] getSQLUpdateStrings() { - return extractSqlStrings( updateCoordinator.getStaticUpdateGroup() ); + return extractSqlStrings( updateCoordinator.getStaticMutationOperationGroup() ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java index 8a21c7f58d..a85bbdd488 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java @@ -47,7 +47,10 @@ import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.internal.InFlightEntityMappingType; import org.hibernate.metamodel.spi.EntityRepresentationStrategy; +import org.hibernate.persister.entity.mutation.DeleteCoordinator; import org.hibernate.persister.entity.mutation.EntityMutationTarget; +import org.hibernate.persister.entity.mutation.InsertCoordinator; +import org.hibernate.persister.entity.mutation.UpdateCoordinator; import org.hibernate.persister.walking.spi.AttributeSource; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy; @@ -627,34 +630,45 @@ public interface EntityPersister extends EntityMappingType, EntityMutationTarget /** * Persist an instance + * + * @see #getInsertCoordinator() + * @deprecated Use {@link InsertCoordinator#insert(Object, Object, Object[], SharedSessionContractImplementor)} instead. */ + @Deprecated( forRemoval = true, since = "6.5" ) default void insert(Object id, Object[] fields, Object object, SharedSessionContractImplementor session) { - insertReturning( id, fields, object, session ); + getInsertCoordinator().insert( object, id, fields, session ); } /** * Persist an instance + * + * @see #getInsertCoordinator() + * @deprecated Use {@link InsertCoordinator#insert(Object, Object[], SharedSessionContractImplementor)} instead. */ - GeneratedValues insertReturning(Object id, Object[] fields, Object object, SharedSessionContractImplementor session); - - /** - * Persist an instance - */ + @Deprecated( forRemoval = true, since = "6.5" ) default Object insert(Object[] fields, Object object, SharedSessionContractImplementor session) { - final GeneratedValues generatedValues = insertReturning( fields, object, session ); - return generatedValues.getGeneratedValue( getIdentifierMapping() ); + final GeneratedValues generatedValues = getInsertCoordinator().insert( object, fields, session ); + return generatedValues == null ? null : generatedValues.getGeneratedValue( getIdentifierMapping() ); } - /** - * Persist an instance, using a natively generated identifier (optional operation) - */ - GeneratedValues insertReturning(Object[] fields, Object object, SharedSessionContractImplementor session); - /** * Delete a persistent instance + * + * @see #getDeleteCoordinator() + * @deprecated Use {@link DeleteCoordinator#delete} instead. */ - void delete(Object id, Object version, Object object, SharedSessionContractImplementor session); + @Deprecated( forRemoval = true, since = "6.5" ) + default void delete(Object id, Object version, Object object, SharedSessionContractImplementor session) { + getDeleteCoordinator().delete( object, id, version, session ); + } + /** + * Update a persistent instance + * + * @see #getUpdateCoordinator() + * @deprecated Use {@link UpdateCoordinator#update} instead. + */ + @Deprecated( forRemoval = true, since = "6.5" ) default void update( Object id, Object[] fields, @@ -665,26 +679,26 @@ public interface EntityPersister extends EntityMappingType, EntityMutationTarget Object object, Object rowId, SharedSessionContractImplementor session) { - updateReturning( id, fields, dirtyFields, hasDirtyCollection, oldFields, oldVersion, object, rowId, session ); + getUpdateCoordinator().update( + object, + id, + rowId, + fields, + oldVersion, + oldFields, + dirtyFields, + hasDirtyCollection, + session + ); } - /** - * Update a persistent instance - */ - GeneratedValues updateReturning( - Object id, - Object[] fields, - int[] dirtyFields, - boolean hasDirtyCollection, - Object[] oldFields, - Object oldVersion, - Object object, - Object rowId, - SharedSessionContractImplementor session); - /** * Merge a persistent instance + * + * @see #getMergeCoordinator() + * @deprecated Use {@link UpdateCoordinator#update} instead. */ + @Deprecated( forRemoval = true, since = "6.5" ) default void merge( Object id, Object[] fields, @@ -695,6 +709,46 @@ public interface EntityPersister extends EntityMappingType, EntityMutationTarget Object object, Object rowId, SharedSessionContractImplementor session) { + getMergeCoordinator().update( + object, + id, + rowId, + fields, + oldVersion, + oldFields, + dirtyFields, + hasDirtyCollection, + session + ); + } + + /** + * Get the insert coordinator instance. + * + * @since 6.5 + */ + InsertCoordinator getInsertCoordinator(); + + /** + * Get the update coordinator instance. + * + * @since 6.5 + */ + UpdateCoordinator getUpdateCoordinator(); + + /** + * Get the delete coordinator instance. + * + * @since 6.5 + */ + DeleteCoordinator getDeleteCoordinator(); + + /** + * Get the merge coordinator instance. + * + * @since 6.5 + */ + default UpdateCoordinator getMergeCoordinator() { throw new UnsupportedOperationException(); } @@ -811,7 +865,7 @@ public interface EntityPersister extends EntityMappingType, EntityMutationTarget /** * The batch size for batch loading. - * + * * @see org.hibernate.engine.spi.LoadQueryInfluencers#effectiveBatchSize(EntityPersister) */ default int getBatchSize() { diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/AbstractDeleteCoordinator.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/AbstractDeleteCoordinator.java index 0baee8c610..0e5f64267d 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/AbstractDeleteCoordinator.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/AbstractDeleteCoordinator.java @@ -52,7 +52,7 @@ public abstract class AbstractDeleteCoordinator } @Override - public MutationOperationGroup getStaticDeleteGroup() { + public MutationOperationGroup getStaticMutationOperationGroup() { return staticOperationGroup; } @@ -68,7 +68,7 @@ public abstract class AbstractDeleteCoordinator SharedSessionContractImplementor session); @Override - public void coordinateDelete( + public void delete( Object entity, Object id, Object version, diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/DeleteCoordinator.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/DeleteCoordinator.java index 72b1678030..eb7835cd93 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/DeleteCoordinator.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/DeleteCoordinator.java @@ -7,28 +7,16 @@ package org.hibernate.persister.entity.mutation; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.sql.model.MutationOperationGroup; /** * Coordinates the deleting of an entity. * - * @see #coordinateDelete - * * @author Steve Ebersole + * @see #delete */ -public interface DeleteCoordinator { +public interface DeleteCoordinator extends MutationCoordinator { /** - * The operation group used to perform the deletion unless some form - * of dynamic delete is necessary + * Delete a persistent instance. */ - MutationOperationGroup getStaticDeleteGroup(); - - /** - * Perform the deletions - */ - void coordinateDelete( - Object entity, - Object id, - Object version, - SharedSessionContractImplementor session); + void delete(Object entity, Object id, Object version, SharedSessionContractImplementor session); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/InsertCoordinator.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/InsertCoordinator.java index 78097a9fd9..c06d2a195d 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/InsertCoordinator.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/InsertCoordinator.java @@ -1,457 +1,39 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ package org.hibernate.persister.entity.mutation; -import java.util.ArrayList; -import java.util.List; - -import org.hibernate.Internal; -import org.hibernate.dialect.Dialect; -import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey; -import org.hibernate.engine.jdbc.batch.spi.BatchKey; -import org.hibernate.engine.jdbc.mutation.JdbcValueBindings; -import org.hibernate.engine.jdbc.mutation.MutationExecutor; -import org.hibernate.engine.jdbc.mutation.ParameterUsage; -import org.hibernate.engine.jdbc.mutation.TableInclusionChecker; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.generator.BeforeExecutionGenerator; -import org.hibernate.generator.Generator; -import org.hibernate.generator.OnExecutionGenerator; import org.hibernate.generator.values.GeneratedValues; -import org.hibernate.generator.values.GeneratedValuesMutationDelegate; -import org.hibernate.metamodel.mapping.AttributeMapping; -import org.hibernate.metamodel.mapping.AttributeMappingsList; -import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping; -import org.hibernate.metamodel.mapping.PluralAttributeMapping; -import org.hibernate.persister.entity.AbstractEntityPersister; -import org.hibernate.sql.model.MutationOperation; -import org.hibernate.sql.model.MutationOperationGroup; -import org.hibernate.sql.model.MutationType; -import org.hibernate.sql.model.TableMapping; -import org.hibernate.sql.model.ValuesAnalysis; -import org.hibernate.sql.model.ast.builder.MutationGroupBuilder; -import org.hibernate.sql.model.ast.builder.TableInsertBuilder; -import org.hibernate.sql.model.ast.builder.TableInsertBuilderStandard; -import org.hibernate.sql.model.ast.builder.TableMutationBuilder; -import org.hibernate.tuple.entity.EntityMetamodel; -import static org.hibernate.generator.EventType.INSERT; +import org.checkerframework.checker.nullness.qual.Nullable; /** - * Coordinates the insertion of an entity. + * Coordinates the inserting of an entity. * - * @see #coordinateInsert - * - * @author Steve Ebersole + * @author Marco Belladelli + * @see #insert(Object, Object[], SharedSessionContractImplementor) + * @see #insert(Object, Object, Object[], SharedSessionContractImplementor) */ -@Internal -public class InsertCoordinator extends AbstractMutationCoordinator { - private final MutationOperationGroup staticInsertGroup; - private final BasicBatchKey batchKey; - - public InsertCoordinator(AbstractEntityPersister entityPersister, SessionFactoryImplementor factory) { - super( entityPersister, factory ); - - if ( entityPersister.isIdentifierAssignedByInsert() || entityPersister.hasInsertGeneratedProperties() ) { - // disable batching in case of insert generated identifier or properties - batchKey = null; - } - else { - batchKey = new BasicBatchKey( - entityPersister.getEntityName() + "#INSERT", - null - ); - } - - if ( entityPersister.getEntityMetamodel().isDynamicInsert() ) { - // the entity specified dynamic-insert - skip generating the - // static inserts as we will create them every time - staticInsertGroup = null; - } - else { - staticInsertGroup = generateStaticOperationGroup(); - } - } - - public MutationOperationGroup getStaticInsertGroup() { - return staticInsertGroup; - } - - @Override - protected BatchKey getBatchKey() { - return batchKey; - } +public interface InsertCoordinator extends MutationCoordinator { + /** + * Persist an entity instance with a generated identifier. + * + * @return The {@linkplain GeneratedValues generated values} if any, {@code null} otherwise. + */ + @Nullable GeneratedValues insert(Object entity, Object[] values, SharedSessionContractImplementor session); /** - * Perform the insert(s). + * Persist an entity instance using the provided identifier. * - * @param id This is the id as known in memory. For post-insert id generation (IDENTITY, etc) - * this will be null. - * @param values The extracted attribute values - * @param entity The entity instance being persisted - * @param session The originating context - * - * @return The id + * @return The {@linkplain GeneratedValues generated values} if any, {@code null} otherwise. */ - public GeneratedValues coordinateInsert( - Object id, - Object[] values, + @Nullable GeneratedValues insert( Object entity, - SharedSessionContractImplementor session) { - // apply any pre-insert in-memory value generation - final boolean needsDynamicInsert = preInsertInMemoryValueGeneration( values, entity, session ); - - final EntityMetamodel entityMetamodel = entityPersister().getEntityMetamodel(); - final boolean forceIdentifierBinding = entityPersister().getGenerator().generatedOnExecution() && id != null; - if ( entityMetamodel.isDynamicInsert() || needsDynamicInsert || forceIdentifierBinding ) { - return doDynamicInserts( id, values, entity, session, forceIdentifierBinding ); - } - else { - return doStaticInserts( id, values, entity, session ); - } - } - - protected boolean preInsertInMemoryValueGeneration(Object[] values, Object entity, SharedSessionContractImplementor session) { - final AbstractEntityPersister persister = entityPersister(); - final EntityMetamodel entityMetamodel = persister.getEntityMetamodel(); - boolean foundStateDependentGenerator = false; - if ( entityMetamodel.hasPreInsertGeneratedValues() ) { - final Generator[] generators = entityMetamodel.getGenerators(); - for ( int i = 0; i < generators.length; i++ ) { - final Generator generator = generators[i]; - if ( generator != null - && !generator.generatedOnExecution( entity, session ) - && generator.generatesOnInsert() ) { - values[i] = ( (BeforeExecutionGenerator) generator ).generate( session, entity, values[i], INSERT ); - persister.setPropertyValue( entity, i, values[i] ); - foundStateDependentGenerator = foundStateDependentGenerator || generator.generatedOnExecution(); - } - } - } - return foundStateDependentGenerator; - } - - protected static class InsertValuesAnalysis implements ValuesAnalysis { - private final List tablesWithNonNullValues = new ArrayList<>(); - - public InsertValuesAnalysis(EntityMutationTarget mutationTarget, Object[] values) { - mutationTarget.forEachMutableTable( (tableMapping) -> { - final int[] tableAttributeIndexes = tableMapping.getAttributeIndexes(); - for ( int i = 0; i < tableAttributeIndexes.length; i++ ) { - if ( values[tableAttributeIndexes[i]] != null ) { - tablesWithNonNullValues.add( tableMapping ); - break; - } - } - } ); - } - - public boolean hasNonNullBindings(TableMapping tableMapping) { - return tablesWithNonNullValues.contains( tableMapping ); - } - } - - protected GeneratedValues doStaticInserts(Object id, Object[] values, Object object, SharedSessionContractImplementor session) { - final InsertValuesAnalysis insertValuesAnalysis = new InsertValuesAnalysis( entityPersister(), values ); - - final TableInclusionChecker tableInclusionChecker = getTableInclusionChecker( insertValuesAnalysis ); - - final MutationExecutor mutationExecutor = executor( session, staticInsertGroup, false ); - - decomposeForInsert( - mutationExecutor, - id, - values, - staticInsertGroup, - entityPersister().getPropertyInsertability(), - tableInclusionChecker, - session - ); - - try { - return mutationExecutor.execute( - object, - insertValuesAnalysis, - tableInclusionChecker, - (statementDetails, affectedRowCount, batchPosition) -> { - statementDetails.getExpectation().verifyOutcome( - affectedRowCount, - statementDetails.getStatement(), - batchPosition, - statementDetails.getSqlString() - ); - return true; - }, - session - ); - } - finally { - mutationExecutor.release(); - } - } - - protected void decomposeForInsert( - MutationExecutor mutationExecutor, Object id, Object[] values, - MutationOperationGroup mutationGroup, - boolean[] propertyInclusions, - TableInclusionChecker tableInclusionChecker, - SharedSessionContractImplementor session) { - final JdbcValueBindings jdbcValueBindings = mutationExecutor.getJdbcValueBindings(); - final AttributeMappingsList attributeMappings = entityPersister().getAttributeMappings(); - - for ( int position = 0; position < mutationGroup.getNumberOfOperations(); position++ ) { - final MutationOperation operation = mutationGroup.getOperation( position ); - final EntityTableMapping tableDetails = (EntityTableMapping) operation.getTableDetails(); - if ( tableInclusionChecker.include( tableDetails ) ) { - final int[] attributeIndexes = tableDetails.getAttributeIndexes(); - for ( int i = 0; i < attributeIndexes.length; i++ ) { - final int attributeIndex = attributeIndexes[ i ]; - if ( propertyInclusions[attributeIndex] ) { - final AttributeMapping mapping = attributeMappings.get( attributeIndex ); - decomposeAttribute( values[attributeIndex], session, jdbcValueBindings, mapping ); - } - } - } - } - - if ( id == null ) { - assert entityPersister().getInsertDelegate() != null; - } - else { - for ( int position = 0; position < mutationGroup.getNumberOfOperations(); position++ ) { - final MutationOperation jdbcOperation = mutationGroup.getOperation( position ); - final EntityTableMapping tableDetails = (EntityTableMapping) jdbcOperation.getTableDetails(); - breakDownJdbcValue( id, session, jdbcValueBindings, tableDetails ); - } - } - } - - protected void breakDownJdbcValue( - Object id, - SharedSessionContractImplementor session, - JdbcValueBindings jdbcValueBindings, - EntityTableMapping tableDetails) { - final String tableName = tableDetails.getTableName(); - tableDetails.getKeyMapping().breakDownKeyJdbcValues( - id, - (jdbcValue, columnMapping) -> { - jdbcValueBindings.bindValue( - jdbcValue, - tableName, - columnMapping.getColumnName(), - ParameterUsage.SET - ); - }, - session - ); - } - - protected void decomposeAttribute( - Object value, - SharedSessionContractImplementor session, - JdbcValueBindings jdbcValueBindings, - AttributeMapping mapping) { - if ( !(mapping instanceof PluralAttributeMapping) ) { - mapping.decompose( - value, - 0, - jdbcValueBindings, - null, - (valueIndex, bindings, noop, jdbcValue, selectableMapping) -> { - if ( selectableMapping.isInsertable() ) { - bindings.bindValue( - jdbcValue, - entityPersister().physicalTableNameForMutation( selectableMapping ), - selectableMapping.getSelectionExpression(), - ParameterUsage.SET - ); - } - }, - session - ); - } - } - - protected GeneratedValues doDynamicInserts( - Object id, - Object[] values, - Object object, - SharedSessionContractImplementor session, - boolean forceIdentifierBinding) { - final boolean[] insertability = getPropertiesToInsert( values ); - final MutationOperationGroup insertGroup = generateDynamicInsertSqlGroup( insertability, object, session, forceIdentifierBinding ); - - final MutationExecutor mutationExecutor = executor( session, insertGroup, true ); - - final InsertValuesAnalysis insertValuesAnalysis = new InsertValuesAnalysis( entityPersister(), values ); - - final TableInclusionChecker tableInclusionChecker = getTableInclusionChecker( insertValuesAnalysis ); - - decomposeForInsert( mutationExecutor, id, values, insertGroup, insertability, tableInclusionChecker, session ); - - try { - return mutationExecutor.execute( - object, - insertValuesAnalysis, - tableInclusionChecker, - (statementDetails, affectedRowCount, batchPosition) -> { - statementDetails.getExpectation().verifyOutcome( - affectedRowCount, - statementDetails.getStatement(), - batchPosition, - statementDetails.getSqlString() - ); - return true; - }, - session - ); - } - finally { - mutationExecutor.release(); - } - } - - private MutationExecutor executor(SharedSessionContractImplementor session, MutationOperationGroup group, boolean dynamicUpdate) { - return mutationExecutorService - .createExecutor( resolveBatchKeyAccess( dynamicUpdate, session ), group, session ); - } - - protected static TableInclusionChecker getTableInclusionChecker(InsertValuesAnalysis insertValuesAnalysis) { - return tableMapping -> !tableMapping.isOptional() || insertValuesAnalysis.hasNonNullBindings( tableMapping ); - } - - - /** - * Transform the array of property indexes to an array of booleans, - * true when the property is insertable and non-null - */ - public boolean[] getPropertiesToInsert(Object[] fields) { - boolean[] notNull = new boolean[fields.length]; - boolean[] insertable = entityPersister().getPropertyInsertability(); - for ( int i = 0; i < fields.length; i++ ) { - notNull[i] = insertable[i] && fields[i] != null; - } - return notNull; - } - - protected MutationOperationGroup generateDynamicInsertSqlGroup( - boolean[] insertable, - Object object, - SharedSessionContractImplementor session, - boolean forceIdentifierBinding) { - final MutationGroupBuilder insertGroupBuilder = new MutationGroupBuilder( MutationType.INSERT, entityPersister() ); - entityPersister().forEachMutableTable( - (tableMapping) -> insertGroupBuilder.addTableDetailsBuilder( createTableInsertBuilder( tableMapping, forceIdentifierBinding ) ) - ); - applyTableInsertDetails( insertGroupBuilder, insertable, object, session, forceIdentifierBinding ); - return createOperationGroup( null, insertGroupBuilder.buildMutationGroup() ); - } - - public MutationOperationGroup generateStaticOperationGroup() { - final MutationGroupBuilder insertGroupBuilder = new MutationGroupBuilder( MutationType.INSERT, entityPersister() ); - entityPersister().forEachMutableTable( - (tableMapping) -> insertGroupBuilder.addTableDetailsBuilder( createTableInsertBuilder( tableMapping, false ) ) - ); - applyTableInsertDetails( insertGroupBuilder, entityPersister().getPropertyInsertability(), null, null, false ); - return createOperationGroup( null, insertGroupBuilder.buildMutationGroup() ); - } - - private TableMutationBuilder createTableInsertBuilder(EntityTableMapping tableMapping, boolean forceIdentifierBinding) { - final GeneratedValuesMutationDelegate delegate = entityPersister().getInsertDelegate(); - if ( tableMapping.isIdentifierTable() && delegate != null && !forceIdentifierBinding ) { - return delegate.createTableMutationBuilder( tableMapping.getInsertExpectation(), factory() ); - } - else { - return new TableInsertBuilderStandard( entityPersister(), tableMapping, factory() ); - } - } - - private void applyTableInsertDetails( - MutationGroupBuilder insertGroupBuilder, - boolean[] attributeInclusions, - Object object, - SharedSessionContractImplementor session, - boolean forceIdentifierBinding) { - final AttributeMappingsList attributeMappings = entityPersister().getAttributeMappings(); - - insertGroupBuilder.forEachTableMutationBuilder( (builder) -> { - final EntityTableMapping tableMapping = (EntityTableMapping) builder.getMutatingTable().getTableMapping(); - assert !tableMapping.isInverse(); - - // `attributeIndexes` represents the indexes (relative to `attributeMappings`) of - // the attributes mapped to the table - final int[] attributeIndexes = tableMapping.getAttributeIndexes(); - for ( int i = 0; i < attributeIndexes.length; i++ ) { - final int attributeIndex = attributeIndexes[ i ]; - final AttributeMapping attributeMapping = attributeMappings.get( attributeIndex ); - if ( attributeInclusions[attributeIndex] ) { - attributeMapping.forEachInsertable( insertGroupBuilder ); - } - else { - final Generator generator = attributeMapping.getGenerator(); - if ( isValueGenerated( generator ) ) { - if ( session != null && !generator.generatedOnExecution( object, session ) ) { - attributeInclusions[attributeIndex] = true; - attributeMapping.forEachInsertable( insertGroupBuilder ); - } - else if ( isValueGenerationInSql( generator, factory().getJdbcServices().getDialect() ) ) { - handleValueGeneration( attributeMapping, insertGroupBuilder, (OnExecutionGenerator) generator ); - } - } - } - } - } ); - - // add the discriminator - entityPersister().addDiscriminatorToInsertGroup( insertGroupBuilder ); - entityPersister().addSoftDeleteToInsertGroup( insertGroupBuilder ); - - // add the keys - insertGroupBuilder.forEachTableMutationBuilder( (tableMutationBuilder) -> { - final TableInsertBuilder tableInsertBuilder = (TableInsertBuilder) tableMutationBuilder; - final EntityTableMapping tableMapping = (EntityTableMapping) tableInsertBuilder.getMutatingTable().getTableMapping(); - if ( tableMapping.isIdentifierTable() && entityPersister().isIdentifierAssignedByInsert() && !forceIdentifierBinding ) { - assert entityPersister().getInsertDelegate() != null; - final OnExecutionGenerator generator = (OnExecutionGenerator) entityPersister().getGenerator(); - if ( generator.referenceColumnsInSql( dialect() ) ) { - final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityPersister().getIdentifierMapping(); - final String[] columnValues = generator.getReferencedColumnValues( dialect ); - tableMapping.getKeyMapping().forEachKeyColumn( (i, column) -> tableInsertBuilder.addKeyColumn( - column.getColumnName(), - columnValues[i], - identifierMapping.getJdbcMapping() - ) ); - } - } - else { - tableMapping.getKeyMapping().forEachKeyColumn( tableInsertBuilder::addKeyColumn ); - } - } ); - } - - private static boolean isValueGenerated(Generator generator) { - return generator != null - && generator.generatesOnInsert() - && generator.generatedOnExecution(); - } - - private static boolean isValueGenerationInSql(Generator generator, Dialect dialect) { - assert isValueGenerated( generator ); - return ( (OnExecutionGenerator) generator ).referenceColumnsInSql(dialect); - } - - /** - * @deprecated Use {@link #getBatchKey()} - */ - @Deprecated - public BasicBatchKey getInsertBatchKey() { - return batchKey; - } + SharedSessionContractImplementor session); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/InsertCoordinatorStandard.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/InsertCoordinatorStandard.java new file mode 100644 index 0000000000..212ae8dd3c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/InsertCoordinatorStandard.java @@ -0,0 +1,474 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. + */ +package org.hibernate.persister.entity.mutation; + +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.Internal; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey; +import org.hibernate.engine.jdbc.batch.spi.BatchKey; +import org.hibernate.engine.jdbc.mutation.JdbcValueBindings; +import org.hibernate.engine.jdbc.mutation.MutationExecutor; +import org.hibernate.engine.jdbc.mutation.ParameterUsage; +import org.hibernate.engine.jdbc.mutation.TableInclusionChecker; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.generator.BeforeExecutionGenerator; +import org.hibernate.generator.Generator; +import org.hibernate.generator.OnExecutionGenerator; +import org.hibernate.generator.values.GeneratedValues; +import org.hibernate.generator.values.GeneratedValuesMutationDelegate; +import org.hibernate.metamodel.mapping.AttributeMapping; +import org.hibernate.metamodel.mapping.AttributeMappingsList; +import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping; +import org.hibernate.metamodel.mapping.PluralAttributeMapping; +import org.hibernate.persister.entity.AbstractEntityPersister; +import org.hibernate.sql.model.MutationOperation; +import org.hibernate.sql.model.MutationOperationGroup; +import org.hibernate.sql.model.MutationType; +import org.hibernate.sql.model.TableMapping; +import org.hibernate.sql.model.ValuesAnalysis; +import org.hibernate.sql.model.ast.builder.MutationGroupBuilder; +import org.hibernate.sql.model.ast.builder.TableInsertBuilder; +import org.hibernate.sql.model.ast.builder.TableInsertBuilderStandard; +import org.hibernate.sql.model.ast.builder.TableMutationBuilder; +import org.hibernate.tuple.entity.EntityMetamodel; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import static org.hibernate.generator.EventType.INSERT; + +/** + * Coordinates the insertion of an entity. + * + * @see #coordinateInsert + * + * @author Steve Ebersole + */ +@Internal +public class InsertCoordinatorStandard extends AbstractMutationCoordinator implements InsertCoordinator { + private final MutationOperationGroup staticInsertGroup; + private final BasicBatchKey batchKey; + + public InsertCoordinatorStandard(AbstractEntityPersister entityPersister, SessionFactoryImplementor factory) { + super( entityPersister, factory ); + + if ( entityPersister.isIdentifierAssignedByInsert() || entityPersister.hasInsertGeneratedProperties() ) { + // disable batching in case of insert generated identifier or properties + batchKey = null; + } + else { + batchKey = new BasicBatchKey( + entityPersister.getEntityName() + "#INSERT", + null + ); + } + + if ( entityPersister.getEntityMetamodel().isDynamicInsert() ) { + // the entity specified dynamic-insert - skip generating the + // static inserts as we will create them every time + staticInsertGroup = null; + } + else { + staticInsertGroup = generateStaticOperationGroup(); + } + } + + @Override + public MutationOperationGroup getStaticMutationOperationGroup() { + return staticInsertGroup; + } + + @Override + protected BatchKey getBatchKey() { + return batchKey; + } + + @Override + public @Nullable GeneratedValues insert(Object entity, Object[] values, SharedSessionContractImplementor session) { + return coordinateInsert( null, values, entity, session ); + } + + @Override + public @Nullable GeneratedValues insert( + Object entity, + Object id, + Object[] values, + SharedSessionContractImplementor session) { + return coordinateInsert( id, values, entity, session ); + } + + /** + * Perform the insert(s). + * + * @param id This is the id as known in memory. For post-insert id generation (IDENTITY, etc) + * this will be null. + * @param values The extracted attribute values + * @param entity The entity instance being persisted + * @param session The originating context + * + * @return The {@linkplain GeneratedValues generated values} if any, {@code null} otherwise. + */ + public GeneratedValues coordinateInsert( + Object id, + Object[] values, + Object entity, + SharedSessionContractImplementor session) { + // apply any pre-insert in-memory value generation + final boolean needsDynamicInsert = preInsertInMemoryValueGeneration( values, entity, session ); + + final EntityMetamodel entityMetamodel = entityPersister().getEntityMetamodel(); + final boolean forceIdentifierBinding = entityPersister().getGenerator().generatedOnExecution() && id != null; + if ( entityMetamodel.isDynamicInsert() || needsDynamicInsert || forceIdentifierBinding ) { + return doDynamicInserts( id, values, entity, session, forceIdentifierBinding ); + } + else { + return doStaticInserts( id, values, entity, session ); + } + } + + protected boolean preInsertInMemoryValueGeneration(Object[] values, Object entity, SharedSessionContractImplementor session) { + final AbstractEntityPersister persister = entityPersister(); + final EntityMetamodel entityMetamodel = persister.getEntityMetamodel(); + boolean foundStateDependentGenerator = false; + if ( entityMetamodel.hasPreInsertGeneratedValues() ) { + final Generator[] generators = entityMetamodel.getGenerators(); + for ( int i = 0; i < generators.length; i++ ) { + final Generator generator = generators[i]; + if ( generator != null + && !generator.generatedOnExecution( entity, session ) + && generator.generatesOnInsert() ) { + values[i] = ( (BeforeExecutionGenerator) generator ).generate( session, entity, values[i], INSERT ); + persister.setPropertyValue( entity, i, values[i] ); + foundStateDependentGenerator = foundStateDependentGenerator || generator.generatedOnExecution(); + } + } + } + return foundStateDependentGenerator; + } + + protected static class InsertValuesAnalysis implements ValuesAnalysis { + private final List tablesWithNonNullValues = new ArrayList<>(); + + public InsertValuesAnalysis(EntityMutationTarget mutationTarget, Object[] values) { + mutationTarget.forEachMutableTable( (tableMapping) -> { + final int[] tableAttributeIndexes = tableMapping.getAttributeIndexes(); + for ( int i = 0; i < tableAttributeIndexes.length; i++ ) { + if ( values[tableAttributeIndexes[i]] != null ) { + tablesWithNonNullValues.add( tableMapping ); + break; + } + } + } ); + } + + public boolean hasNonNullBindings(TableMapping tableMapping) { + return tablesWithNonNullValues.contains( tableMapping ); + } + } + + protected GeneratedValues doStaticInserts(Object id, Object[] values, Object object, SharedSessionContractImplementor session) { + final InsertValuesAnalysis insertValuesAnalysis = new InsertValuesAnalysis( entityPersister(), values ); + + final TableInclusionChecker tableInclusionChecker = getTableInclusionChecker( insertValuesAnalysis ); + + final MutationExecutor mutationExecutor = executor( session, staticInsertGroup, false ); + + decomposeForInsert( + mutationExecutor, + id, + values, + staticInsertGroup, + entityPersister().getPropertyInsertability(), + tableInclusionChecker, + session + ); + + try { + return mutationExecutor.execute( + object, + insertValuesAnalysis, + tableInclusionChecker, + (statementDetails, affectedRowCount, batchPosition) -> { + statementDetails.getExpectation().verifyOutcome( + affectedRowCount, + statementDetails.getStatement(), + batchPosition, + statementDetails.getSqlString() + ); + return true; + }, + session + ); + } + finally { + mutationExecutor.release(); + } + } + + protected void decomposeForInsert( + MutationExecutor mutationExecutor, + Object id, + Object[] values, + MutationOperationGroup mutationGroup, + boolean[] propertyInclusions, + TableInclusionChecker tableInclusionChecker, + SharedSessionContractImplementor session) { + final JdbcValueBindings jdbcValueBindings = mutationExecutor.getJdbcValueBindings(); + final AttributeMappingsList attributeMappings = entityPersister().getAttributeMappings(); + + for ( int position = 0; position < mutationGroup.getNumberOfOperations(); position++ ) { + final MutationOperation operation = mutationGroup.getOperation( position ); + final EntityTableMapping tableDetails = (EntityTableMapping) operation.getTableDetails(); + if ( tableInclusionChecker.include( tableDetails ) ) { + final int[] attributeIndexes = tableDetails.getAttributeIndexes(); + for ( int i = 0; i < attributeIndexes.length; i++ ) { + final int attributeIndex = attributeIndexes[ i ]; + if ( propertyInclusions[attributeIndex] ) { + final AttributeMapping mapping = attributeMappings.get( attributeIndex ); + decomposeAttribute( values[attributeIndex], session, jdbcValueBindings, mapping ); + } + } + } + } + + if ( id == null ) { + assert entityPersister().getInsertDelegate() != null; + } + else { + for ( int position = 0; position < mutationGroup.getNumberOfOperations(); position++ ) { + final MutationOperation jdbcOperation = mutationGroup.getOperation( position ); + final EntityTableMapping tableDetails = (EntityTableMapping) jdbcOperation.getTableDetails(); + breakDownJdbcValue( id, session, jdbcValueBindings, tableDetails ); + } + } + } + + protected void breakDownJdbcValue( + Object id, + SharedSessionContractImplementor session, + JdbcValueBindings jdbcValueBindings, + EntityTableMapping tableDetails) { + final String tableName = tableDetails.getTableName(); + tableDetails.getKeyMapping().breakDownKeyJdbcValues( + id, + (jdbcValue, columnMapping) -> { + jdbcValueBindings.bindValue( + jdbcValue, + tableName, + columnMapping.getColumnName(), + ParameterUsage.SET + ); + }, + session + ); + } + + protected void decomposeAttribute( + Object value, + SharedSessionContractImplementor session, + JdbcValueBindings jdbcValueBindings, + AttributeMapping mapping) { + if ( !(mapping instanceof PluralAttributeMapping) ) { + mapping.decompose( + value, + 0, + jdbcValueBindings, + null, + (valueIndex, bindings, noop, jdbcValue, selectableMapping) -> { + if ( selectableMapping.isInsertable() ) { + bindings.bindValue( + jdbcValue, + entityPersister().physicalTableNameForMutation( selectableMapping ), + selectableMapping.getSelectionExpression(), + ParameterUsage.SET + ); + } + }, + session + ); + } + } + + protected GeneratedValues doDynamicInserts( + Object id, + Object[] values, + Object object, + SharedSessionContractImplementor session, + boolean forceIdentifierBinding) { + final boolean[] insertability = getPropertiesToInsert( values ); + final MutationOperationGroup insertGroup = generateDynamicInsertSqlGroup( insertability, object, session, forceIdentifierBinding ); + + final MutationExecutor mutationExecutor = executor( session, insertGroup, true ); + + final InsertValuesAnalysis insertValuesAnalysis = new InsertValuesAnalysis( entityPersister(), values ); + + final TableInclusionChecker tableInclusionChecker = getTableInclusionChecker( insertValuesAnalysis ); + + decomposeForInsert( mutationExecutor, id, values, insertGroup, insertability, tableInclusionChecker, session ); + + try { + return mutationExecutor.execute( + object, + insertValuesAnalysis, + tableInclusionChecker, + (statementDetails, affectedRowCount, batchPosition) -> { + statementDetails.getExpectation().verifyOutcome( + affectedRowCount, + statementDetails.getStatement(), + batchPosition, + statementDetails.getSqlString() + ); + return true; + }, + session + ); + } + finally { + mutationExecutor.release(); + } + } + + private MutationExecutor executor(SharedSessionContractImplementor session, MutationOperationGroup group, boolean dynamicUpdate) { + return mutationExecutorService + .createExecutor( resolveBatchKeyAccess( dynamicUpdate, session ), group, session ); + } + + protected static TableInclusionChecker getTableInclusionChecker(InsertValuesAnalysis insertValuesAnalysis) { + return tableMapping -> !tableMapping.isOptional() || insertValuesAnalysis.hasNonNullBindings( tableMapping ); + } + + + /** + * Transform the array of property indexes to an array of booleans, + * true when the property is insertable and non-null + */ + public boolean[] getPropertiesToInsert(Object[] fields) { + boolean[] notNull = new boolean[fields.length]; + boolean[] insertable = entityPersister().getPropertyInsertability(); + for ( int i = 0; i < fields.length; i++ ) { + notNull[i] = insertable[i] && fields[i] != null; + } + return notNull; + } + + protected MutationOperationGroup generateDynamicInsertSqlGroup( + boolean[] insertable, + Object object, + SharedSessionContractImplementor session, + boolean forceIdentifierBinding) { + final MutationGroupBuilder insertGroupBuilder = new MutationGroupBuilder( MutationType.INSERT, entityPersister() ); + entityPersister().forEachMutableTable( + (tableMapping) -> insertGroupBuilder.addTableDetailsBuilder( createTableInsertBuilder( tableMapping, forceIdentifierBinding ) ) + ); + applyTableInsertDetails( insertGroupBuilder, insertable, object, session, forceIdentifierBinding ); + return createOperationGroup( null, insertGroupBuilder.buildMutationGroup() ); + } + + public MutationOperationGroup generateStaticOperationGroup() { + final MutationGroupBuilder insertGroupBuilder = new MutationGroupBuilder( MutationType.INSERT, entityPersister() ); + entityPersister().forEachMutableTable( + (tableMapping) -> insertGroupBuilder.addTableDetailsBuilder( createTableInsertBuilder( tableMapping, false ) ) + ); + applyTableInsertDetails( insertGroupBuilder, entityPersister().getPropertyInsertability(), null, null, false ); + return createOperationGroup( null, insertGroupBuilder.buildMutationGroup() ); + } + + private TableMutationBuilder createTableInsertBuilder(EntityTableMapping tableMapping, boolean forceIdentifierBinding) { + final GeneratedValuesMutationDelegate delegate = entityPersister().getInsertDelegate(); + if ( tableMapping.isIdentifierTable() && delegate != null && !forceIdentifierBinding ) { + return delegate.createTableMutationBuilder( tableMapping.getInsertExpectation(), factory() ); + } + else { + return new TableInsertBuilderStandard( entityPersister(), tableMapping, factory() ); + } + } + + private void applyTableInsertDetails( + MutationGroupBuilder insertGroupBuilder, + boolean[] attributeInclusions, + Object object, + SharedSessionContractImplementor session, + boolean forceIdentifierBinding) { + final AttributeMappingsList attributeMappings = entityPersister().getAttributeMappings(); + + insertGroupBuilder.forEachTableMutationBuilder( (builder) -> { + final EntityTableMapping tableMapping = (EntityTableMapping) builder.getMutatingTable().getTableMapping(); + assert !tableMapping.isInverse(); + + // `attributeIndexes` represents the indexes (relative to `attributeMappings`) of + // the attributes mapped to the table + final int[] attributeIndexes = tableMapping.getAttributeIndexes(); + for ( int i = 0; i < attributeIndexes.length; i++ ) { + final int attributeIndex = attributeIndexes[ i ]; + final AttributeMapping attributeMapping = attributeMappings.get( attributeIndex ); + if ( attributeInclusions[attributeIndex] ) { + attributeMapping.forEachInsertable( insertGroupBuilder ); + } + else { + final Generator generator = attributeMapping.getGenerator(); + if ( isValueGenerated( generator ) ) { + if ( session != null && !generator.generatedOnExecution( object, session ) ) { + attributeInclusions[attributeIndex] = true; + attributeMapping.forEachInsertable( insertGroupBuilder ); + } + else if ( isValueGenerationInSql( generator, factory().getJdbcServices().getDialect() ) ) { + handleValueGeneration( attributeMapping, insertGroupBuilder, (OnExecutionGenerator) generator ); + } + } + } + } + } ); + + // add the discriminator + entityPersister().addDiscriminatorToInsertGroup( insertGroupBuilder ); + entityPersister().addSoftDeleteToInsertGroup( insertGroupBuilder ); + + // add the keys + insertGroupBuilder.forEachTableMutationBuilder( (tableMutationBuilder) -> { + final TableInsertBuilder tableInsertBuilder = (TableInsertBuilder) tableMutationBuilder; + final EntityTableMapping tableMapping = (EntityTableMapping) tableInsertBuilder.getMutatingTable().getTableMapping(); + if ( tableMapping.isIdentifierTable() && entityPersister().isIdentifierAssignedByInsert() && !forceIdentifierBinding ) { + assert entityPersister().getInsertDelegate() != null; + final OnExecutionGenerator generator = (OnExecutionGenerator) entityPersister().getGenerator(); + if ( generator.referenceColumnsInSql( dialect() ) ) { + final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityPersister().getIdentifierMapping(); + final String[] columnValues = generator.getReferencedColumnValues( dialect ); + tableMapping.getKeyMapping().forEachKeyColumn( (i, column) -> tableInsertBuilder.addKeyColumn( + column.getColumnName(), + columnValues[i], + identifierMapping.getJdbcMapping() + ) ); + } + } + else { + tableMapping.getKeyMapping().forEachKeyColumn( tableInsertBuilder::addKeyColumn ); + } + } ); + } + + private static boolean isValueGenerated(Generator generator) { + return generator != null + && generator.generatesOnInsert() + && generator.generatedOnExecution(); + } + + private static boolean isValueGenerationInSql(Generator generator, Dialect dialect) { + assert isValueGenerated( generator ); + return ( (OnExecutionGenerator) generator ).referenceColumnsInSql(dialect); + } + + /** + * @deprecated Use {@link #getBatchKey()} + */ + @Deprecated + public BasicBatchKey getInsertBatchKey() { + return batchKey; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/MergeCoordinator.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/MergeCoordinator.java index 1313b3a8ac..7db29d7385 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/MergeCoordinator.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/MergeCoordinator.java @@ -11,7 +11,6 @@ import org.hibernate.persister.entity.AbstractEntityPersister; import org.hibernate.sql.model.MutationOperation; import org.hibernate.sql.model.ast.builder.AbstractTableUpdateBuilder; import org.hibernate.sql.model.ast.builder.TableMergeBuilder; -import org.hibernate.sql.model.ast.builder.TableUpdateBuilder; /** * Specialized {@link UpdateCoordinator} for {@code merge into}. diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/MutationCoordinator.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/MutationCoordinator.java new file mode 100644 index 0000000000..79f1e723ca --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/MutationCoordinator.java @@ -0,0 +1,27 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.persister.entity.mutation; + +import org.hibernate.sql.model.MutationOperationGroup; + +/** + * Coordinates the mutation operations of an entity. + * + * @see InsertCoordinator + * @see DeleteCoordinator + * @see UpdateCoordinator + * @see MergeCoordinator + * + * @author Marco Belladelli + */ +public interface MutationCoordinator { + /** + * The operation group used to perform the mutation unless some form + * of dynamic mutation is necessary. + */ + MutationOperationGroup getStaticMutationOperationGroup(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinator.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinator.java index f7b635451c..3673800ac4 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinator.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinator.java @@ -6,23 +6,24 @@ */ package org.hibernate.persister.entity.mutation; -import org.hibernate.Internal; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.generator.values.GeneratedValues; -import org.hibernate.sql.model.MutationOperationGroup; + +import org.checkerframework.checker.nullness.qual.Nullable; /** * Coordinates the updating of an entity. * - * @see #coordinateUpdate - * * @author Steve Ebersole + * @see #update */ -@Internal -public interface UpdateCoordinator { - MutationOperationGroup getStaticUpdateGroup(); - - GeneratedValues coordinateUpdate( +public interface UpdateCoordinator extends MutationCoordinator { + /** + * Update a persistent instance. + * + * @return The {@linkplain GeneratedValues generated values} if any, {@code null} otherwise. + */ + @Nullable GeneratedValues update( Object entity, Object id, Object rowId, @@ -44,7 +45,7 @@ public interface UpdateCoordinator { Object currentVersion, Object nextVersion, boolean batching, - SharedSessionContractImplementor session){ + SharedSessionContractImplementor session) { forceVersionIncrement( id, currentVersion, nextVersion, session ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorNoOp.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorNoOp.java index c68165550d..ae50f15d2e 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorNoOp.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorNoOp.java @@ -24,12 +24,12 @@ public class UpdateCoordinatorNoOp implements UpdateCoordinator { } @Override - public MutationOperationGroup getStaticUpdateGroup() { + public MutationOperationGroup getStaticMutationOperationGroup() { return operationGroup; } @Override - public GeneratedValues coordinateUpdate(Object entity, Object id, Object rowId, Object[] values, Object oldVersion, Object[] incomingOldValues, int[] dirtyAttributeIndexes, boolean hasDirtyCollection, SharedSessionContractImplementor session) { + public GeneratedValues update(Object entity, Object id, Object rowId, Object[] values, Object oldVersion, Object[] incomingOldValues, int[] dirtyAttributeIndexes, boolean hasDirtyCollection, SharedSessionContractImplementor session) { // nothing to do return null; } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java index 7b3bacbaf9..d50a2dd400 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java @@ -68,7 +68,7 @@ import static org.hibernate.internal.util.collections.ArrayHelper.trim; /** * Coordinates the updating of an entity. * - * @see #coordinateUpdate + * @see #update * * @author Steve Ebersole */ @@ -125,7 +125,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple } @Override - public MutationOperationGroup getStaticUpdateGroup() { + public MutationOperationGroup getStaticMutationOperationGroup() { return staticUpdateGroup; } @@ -167,7 +167,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple } @Override - public GeneratedValues coordinateUpdate( + public GeneratedValues update( Object entity, Object id, Object rowId, diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java index 1fd60bd7ba..9a0b383913 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java @@ -408,7 +408,7 @@ public class DefaultCatalogAndSchemaTest { // because ID generators table/sequence names are prefixed with the owning entity name. { - final MutationOperationGroup staticSqlInsertGroup = persister.getInsertCoordinator().getStaticInsertGroup(); + final MutationOperationGroup staticSqlInsertGroup = persister.getInsertCoordinator().getStaticMutationOperationGroup(); final String[] insertSqls = new String[staticSqlInsertGroup.getNumberOfOperations()]; for ( int tablePosition = 0; tablePosition < staticSqlInsertGroup.getNumberOfOperations(); @@ -427,7 +427,7 @@ public class DefaultCatalogAndSchemaTest { } { - final MutationOperationGroup staticSqlUpdateGroup = persister.getUpdateCoordinator().getStaticUpdateGroup(); + final MutationOperationGroup staticSqlUpdateGroup = persister.getUpdateCoordinator().getStaticMutationOperationGroup(); final String[] sqlUpdateStrings = new String[staticSqlUpdateGroup.getNumberOfOperations()]; for ( int tablePosition = 0; tablePosition < staticSqlUpdateGroup.getNumberOfOperations(); @@ -442,7 +442,7 @@ public class DefaultCatalogAndSchemaTest { { - final MutationOperationGroup staticDeleteGroup = persister.getDeleteCoordinator().getStaticDeleteGroup(); + final MutationOperationGroup staticDeleteGroup = persister.getDeleteCoordinator().getStaticMutationOperationGroup(); final String[] sqlDeleteStrings = new String[staticDeleteGroup.getNumberOfOperations()]; for ( int tablePosition = 0; tablePosition < staticDeleteGroup.getNumberOfOperations(); tablePosition++ ) { final MutationOperation operation = staticDeleteGroup.getOperation( tablePosition ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/cfg/persister/GoofyPersisterClassProvider.java b/hibernate-core/src/test/java/org/hibernate/orm/test/cfg/persister/GoofyPersisterClassProvider.java index b3506f3a52..383f9a8447 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/cfg/persister/GoofyPersisterClassProvider.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/cfg/persister/GoofyPersisterClassProvider.java @@ -64,7 +64,10 @@ import org.hibernate.metamodel.spi.EntityRepresentationStrategy; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.UniqueKeyEntry; +import org.hibernate.persister.entity.mutation.DeleteCoordinator; import org.hibernate.persister.entity.mutation.EntityTableMapping; +import org.hibernate.persister.entity.mutation.InsertCoordinator; +import org.hibernate.persister.entity.mutation.UpdateCoordinator; import org.hibernate.persister.spi.PersisterClassResolver; import org.hibernate.persister.spi.PersisterCreationContext; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy; @@ -403,30 +406,17 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver { } @Override - public GeneratedValues insertReturning(Object id, Object[] fields, Object object, SharedSessionContractImplementor session) { + public InsertCoordinator getInsertCoordinator() { return null; } @Override - public GeneratedValues insertReturning(Object[] fields, Object object, SharedSessionContractImplementor session) { + public UpdateCoordinator getUpdateCoordinator() { return null; } @Override - public void delete(Object id, Object version, Object object, SharedSessionContractImplementor session) { - } - - @Override - public GeneratedValues updateReturning( - Object id, - Object[] fields, - int[] dirtyFields, - boolean hasDirtyCollection, - Object[] oldFields, - Object oldVersion, - Object object, - Object rowId, - SharedSessionContractImplementor session) { + public DeleteCoordinator getDeleteCoordinator() { return null; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ejb3configuration/PersisterClassProviderTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ejb3configuration/PersisterClassProviderTest.java index ef0735a57b..6c4e6528e3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ejb3configuration/PersisterClassProviderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ejb3configuration/PersisterClassProviderTest.java @@ -61,7 +61,10 @@ import org.hibernate.orm.test.jpa.SettingsGenerator; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.UniqueKeyEntry; +import org.hibernate.persister.entity.mutation.DeleteCoordinator; import org.hibernate.persister.entity.mutation.EntityTableMapping; +import org.hibernate.persister.entity.mutation.InsertCoordinator; +import org.hibernate.persister.entity.mutation.UpdateCoordinator; import org.hibernate.persister.internal.PersisterClassResolverInitiator; import org.hibernate.persister.spi.PersisterClassResolver; import org.hibernate.persister.spi.PersisterCreationContext; @@ -445,21 +448,17 @@ public class PersisterClassProviderTest { } @Override - public GeneratedValues insertReturning(Object id, Object[] fields, Object object, SharedSessionContractImplementor session) { + public InsertCoordinator getInsertCoordinator() { return null; } @Override - public GeneratedValues insertReturning(Object[] fields, Object object, SharedSessionContractImplementor session) { + public UpdateCoordinator getUpdateCoordinator() { return null; } @Override - public void delete(Object id, Object version, Object object, SharedSessionContractImplementor session) { - } - - @Override - public GeneratedValues updateReturning(Object id, Object[] fields, int[] dirtyFields, boolean hasDirtyCollection, Object[] oldFields, Object oldVersion, Object object, Object rowId, SharedSessionContractImplementor session) { + public DeleteCoordinator getDeleteCoordinator() { return null; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/legacy/CustomPersister.java b/hibernate-core/src/test/java/org/hibernate/orm/test/legacy/CustomPersister.java index cc5b5dbbec..07697be22a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/legacy/CustomPersister.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/legacy/CustomPersister.java @@ -60,13 +60,17 @@ import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.metamodel.spi.EntityRepresentationStrategy; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.UniqueKeyEntry; +import org.hibernate.persister.entity.mutation.DeleteCoordinator; import org.hibernate.persister.entity.mutation.EntityTableMapping; +import org.hibernate.persister.entity.mutation.InsertCoordinator; +import org.hibernate.persister.entity.mutation.UpdateCoordinator; import org.hibernate.persister.spi.PersisterCreationContext; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.from.TableGroup; +import org.hibernate.sql.model.MutationOperationGroup; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.tuple.entity.EntityMetamodel; @@ -77,6 +81,8 @@ import org.hibernate.type.descriptor.java.StringJavaType; import org.hibernate.type.descriptor.jdbc.VarcharJdbcType; import org.hibernate.type.internal.BasicTypeImpl; +import org.checkerframework.checker.nullness.qual.Nullable; + public class CustomPersister implements EntityPersister { private static final Hashtable INSTANCES = new Hashtable<>(); @@ -503,52 +509,80 @@ public class CustomPersister implements EntityPersister { throw new UnsupportedOperationException(); } - public GeneratedValues insertReturning( - Object id, - Object[] fields, - Object object, - SharedSessionContractImplementor session - ) throws HibernateException { + @Override + public InsertCoordinator getInsertCoordinator() { + return new InsertCoordinator() { + @Override + public @Nullable GeneratedValues insert( + Object entity, + Object[] values, + SharedSessionContractImplementor session) { + throw new UnsupportedOperationException(); + } - INSTANCES.put(id, ( (Custom) object ).clone() ); + @Override + public @Nullable GeneratedValues insert( + Object entity, + Object id, + Object[] values, + SharedSessionContractImplementor session) { + INSTANCES.put( id, ( (Custom) entity ).clone() ); + return null; + } - return null; + @Override + public MutationOperationGroup getStaticMutationOperationGroup() { + return null; + } + }; } - public GeneratedValues insertReturning(Object[] fields, Object object, SharedSessionContractImplementor session) - throws HibernateException { + @Override + public UpdateCoordinator getUpdateCoordinator() { + return new UpdateCoordinator() { + @Override + public @Nullable GeneratedValues update( + Object entity, + Object id, + Object rowId, + Object[] values, + Object oldVersion, + Object[] incomingOldValues, + int[] dirtyAttributeIndexes, + boolean hasDirtyCollection, + SharedSessionContractImplementor session) { + INSTANCES.put( id, ( (Custom) entity ).clone() ); + return null; + } - throw new UnsupportedOperationException(); + @Override + public void forceVersionIncrement( + Object id, + Object currentVersion, + Object nextVersion, + SharedSessionContractImplementor session) { + } + + @Override + public MutationOperationGroup getStaticMutationOperationGroup() { + return null; + } + }; } - public void delete( - Object id, - Object version, - Object object, - SharedSessionContractImplementor session - ) throws HibernateException { + @Override + public DeleteCoordinator getDeleteCoordinator() { + return new DeleteCoordinator() { + @Override + public void delete(Object entity, Object id, Object version, SharedSessionContractImplementor session) { + INSTANCES.remove( id ); + } - INSTANCES.remove(id); - } - - /** - * @see EntityPersister - */ - public GeneratedValues updateReturning( - Object id, - Object[] fields, - int[] dirtyFields, - boolean hasDirtyCollection, - Object[] oldFields, - Object oldVersion, - Object object, - Object rowId, - SharedSessionContractImplementor session - ) throws HibernateException { - - INSTANCES.put( id, ( (Custom) object ).clone() ); - - return null; + @Override + public MutationOperationGroup getStaticMutationOperationGroup() { + return null; + } + }; } private static final BasicType STRING_TYPE = new BasicTypeImpl<>( diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlSchemaResolvingIdentityTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlSchemaResolvingIdentityTest.java index ec4d85fbbb..81ef0b3968 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlSchemaResolvingIdentityTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlSchemaResolvingIdentityTest.java @@ -50,9 +50,9 @@ public class CustomSqlSchemaResolvingIdentityTest { String className = CustomEntity.class.getName(); final AbstractEntityPersister persister = (AbstractEntityPersister) scope.getSessionFactory().getMappingMetamodel().getEntityDescriptor(className); - String insertQuery = ( (JdbcMutationOperation) persister.getInsertCoordinator().getStaticInsertGroup().getSingleOperation() ).getSqlString(); - String updateQuery = ( (JdbcMutationOperation) persister.getUpdateCoordinator().getStaticUpdateGroup().getSingleOperation() ).getSqlString(); - String deleteQuery = ( (JdbcMutationOperation) persister.getDeleteCoordinator().getStaticDeleteGroup().getSingleOperation() ).getSqlString(); + String insertQuery = ( (JdbcMutationOperation) persister.getInsertCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString(); + String updateQuery = ( (JdbcMutationOperation) persister.getUpdateCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString(); + String deleteQuery = ( (JdbcMutationOperation) persister.getDeleteCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString(); assertEquals( "Incorrect custom SQL for insert in Entity: " + className, "INSERT INTO FOO (name) VALUES (?)", insertQuery ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlSchemaResolvingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlSchemaResolvingTest.java index c5acf1025e..b0c9804562 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlSchemaResolvingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlSchemaResolvingTest.java @@ -45,9 +45,9 @@ public class CustomSqlSchemaResolvingTest { String className = CustomEntity.class.getName(); final AbstractEntityPersister persister = (AbstractEntityPersister) scope.getSessionFactory().getMappingMetamodel().getEntityDescriptor(className); - String insertQuery = ( (JdbcMutationOperation) persister.getInsertCoordinator().getStaticInsertGroup().getSingleOperation() ).getSqlString(); - String updateQuery = ( (JdbcMutationOperation) persister.getUpdateCoordinator().getStaticUpdateGroup().getSingleOperation() ).getSqlString(); - String deleteQuery = ( (JdbcMutationOperation) persister.getDeleteCoordinator().getStaticDeleteGroup().getSingleOperation() ).getSqlString(); + String insertQuery = ( (JdbcMutationOperation) persister.getInsertCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString(); + String updateQuery = ( (JdbcMutationOperation) persister.getUpdateCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString(); + String deleteQuery = ( (JdbcMutationOperation) persister.getDeleteCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString(); assertEquals( "Incorrect custom SQL for insert in Entity: " + className, "INSERT INTO FOO (name, id) VALUES (?, ?)", insertQuery );