Skip to content

Commit 228eabe

Browse files
committed
HHH-15527 Make sure that only a single query is executed when running an insert-select with an assigned id
1 parent 77806f4 commit 228eabe

File tree

1 file changed

+50
-5
lines changed

1 file changed

+50
-5
lines changed

hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,17 @@
4141
import org.hibernate.graph.RootGraph;
4242
import org.hibernate.graph.spi.AppliedGraph;
4343
import org.hibernate.graph.spi.RootGraphImplementor;
44+
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
45+
import org.hibernate.id.IdentifierGenerator;
46+
import org.hibernate.id.OptimizableGenerator;
47+
import org.hibernate.id.enhanced.Optimizer;
4448
import org.hibernate.internal.CoreLogging;
4549
import org.hibernate.internal.CoreMessageLogger;
4650
import org.hibernate.internal.util.collections.IdentitySet;
51+
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
52+
import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping;
4753
import org.hibernate.metamodel.model.domain.EntityDomainType;
54+
import org.hibernate.persister.entity.AbstractEntityPersister;
4855
import org.hibernate.persister.entity.EntityPersister;
4956
import org.hibernate.query.BindableType;
5057
import org.hibernate.query.IllegalQueryOperationException;
@@ -76,6 +83,7 @@
7683
import org.hibernate.query.spi.QueryParameterBindings;
7784
import org.hibernate.query.spi.ScrollableResultsImplementor;
7885
import org.hibernate.query.spi.SelectQueryPlan;
86+
import org.hibernate.query.sqm.SqmPathSource;
7987
import org.hibernate.query.sqm.internal.SqmInterpretationsKey.InterpretationsKeySource;
8088
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
8189
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
@@ -88,6 +96,7 @@
8896
import org.hibernate.query.sqm.tree.expression.SqmExpression;
8997
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
9098
import org.hibernate.query.sqm.tree.expression.SqmParameter;
99+
import org.hibernate.query.sqm.tree.from.SqmRoot;
91100
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
92101
import org.hibernate.query.sqm.tree.insert.SqmInsertStatement;
93102
import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement;
@@ -820,20 +829,56 @@ private NonSelectQueryPlan buildInsertQueryPlan() {
820829
final SqmInsertStatement sqmInsert = (SqmInsertStatement) getSqmStatement();
821830

822831
final String entityNameToInsert = sqmInsert.getTarget().getModel().getHibernateEntityName();
823-
final EntityPersister entityDescriptor = getSessionFactory().getRuntimeMetamodels()
832+
final AbstractEntityPersister entityDescriptor = (AbstractEntityPersister) getSessionFactory().getRuntimeMetamodels()
824833
.getMappingMetamodel()
825834
.getEntityDescriptor( entityNameToInsert );
826835

827-
final SqmMultiTableInsertStrategy multiTableStrategy = entityDescriptor.getSqmMultiTableInsertStrategy();
828-
if ( multiTableStrategy == null || isSimpleValuesInsert( sqmInsert, entityDescriptor ) ) {
836+
boolean useMultiTableInsert = entityDescriptor.isMultiTable();
837+
if ( !useMultiTableInsert && !isSimpleValuesInsert( sqmInsert, entityDescriptor ) ) {
838+
final IdentifierGenerator identifierGenerator = entityDescriptor.getIdentifierGenerator();
839+
if ( identifierGenerator instanceof BulkInsertionCapableIdentifierGenerator && identifierGenerator instanceof OptimizableGenerator ) {
840+
final Optimizer optimizer = ( (OptimizableGenerator) identifierGenerator ).getOptimizer();
841+
if ( optimizer != null && optimizer.getIncrementSize() > 1 ) {
842+
useMultiTableInsert = !hasIdentifierAssigned( sqmInsert, entityDescriptor );
843+
}
844+
}
845+
}
846+
if ( !useMultiTableInsert ) {
829847
return new SimpleInsertQueryPlan( sqmInsert, domainParameterXref );
830848
}
831849
else {
832-
return new MultiTableInsertQueryPlan( sqmInsert, domainParameterXref, multiTableStrategy );
850+
return new MultiTableInsertQueryPlan(
851+
sqmInsert,
852+
domainParameterXref,
853+
entityDescriptor.getSqmMultiTableInsertStrategy()
854+
);
855+
}
856+
}
857+
858+
private boolean hasIdentifierAssigned(SqmInsertStatement<?> sqmInsert, EntityPersister entityDescriptor) {
859+
final EntityIdentifierMapping identifierMapping = entityDescriptor.getIdentifierMapping();
860+
final String partName;
861+
if ( identifierMapping instanceof SingleAttributeIdentifierMapping ) {
862+
partName = ( (SingleAttributeIdentifierMapping) identifierMapping ).getAttributeName();
863+
}
864+
else {
865+
partName = EntityIdentifierMapping.ROLE_LOCAL_NAME;
866+
}
867+
for ( SqmPath<?> insertionTargetPath : sqmInsert.getInsertionTargetPaths() ) {
868+
final SqmPath<?> lhs = insertionTargetPath.getLhs();
869+
if ( !( lhs instanceof SqmRoot<?> ) ) {
870+
continue;
871+
}
872+
final SqmPathSource<?> referencedPathSource = insertionTargetPath.getReferencedPathSource();
873+
if ( referencedPathSource.getPathName().equals( partName ) ) {
874+
return true;
875+
}
833876
}
877+
878+
return false;
834879
}
835880

836-
private boolean isSimpleValuesInsert(@SuppressWarnings("rawtypes") SqmInsertStatement sqmInsert, EntityPersister entityDescriptor) {
881+
private boolean isSimpleValuesInsert(SqmInsertStatement<?> sqmInsert, EntityPersister entityDescriptor) {
837882
// Simple means that we can translate the statement to a single plain insert
838883
return sqmInsert instanceof SqmInsertValuesStatement
839884
// An insert is only simple if no SqmMultiTableMutation strategy is available,

0 commit comments

Comments
 (0)