diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/AbstractLoadQueryDetails.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/AbstractLoadQueryDetails.java index ee0e648208..106c2c9e31 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/AbstractLoadQueryDetails.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/AbstractLoadQueryDetails.java @@ -40,6 +40,7 @@ public abstract class AbstractLoadQueryDetails implements LoadQueryDetails { private final String[] keyColumnNames; private final Return rootReturn; private final LoadQueryJoinAndFetchProcessor queryProcessor; + private final QueryBuildingParameters buildingParameters; private String sqlStatement; private ResultSetProcessor resultSetProcessor; @@ -58,7 +59,30 @@ public abstract class AbstractLoadQueryDetails implements LoadQueryDetails { this.keyColumnNames = keyColumnNames; this.rootReturn = rootReturn; this.loadPlan = loadPlan; - this.queryProcessor = new LoadQueryJoinAndFetchProcessor( aliasResolutionContext, buildingParameters, factory ); + this.queryProcessor = new LoadQueryJoinAndFetchProcessor( + aliasResolutionContext, buildingParameters.getQueryInfluencers(), factory + ); + this.buildingParameters = buildingParameters; + } + + /** + * Constructs an AbstractLoadQueryDetails object from an initial object and new building parameters, + * with the guarantee that only batch size changed between the initial parameters and the new ones. + * + * @param initialLoadQueryDetails The initial object to be copied + * @param buildingParameters The new building parameters, with only the batch size being different + * from the parameters used in the initial object. + */ + protected AbstractLoadQueryDetails( + AbstractLoadQueryDetails initialLoadQueryDetails, + QueryBuildingParameters buildingParameters) { + this.keyColumnNames = initialLoadQueryDetails.keyColumnNames; + this.rootReturn = initialLoadQueryDetails.rootReturn; + this.loadPlan = initialLoadQueryDetails.loadPlan; + this.queryProcessor = new LoadQueryJoinAndFetchProcessor( + initialLoadQueryDetails.queryProcessor, buildingParameters.getQueryInfluencers() + ); + this.buildingParameters = buildingParameters; } protected QuerySpace getQuerySpace(String querySpaceUid) { @@ -84,7 +108,7 @@ public abstract class AbstractLoadQueryDetails implements LoadQueryDetails { } protected final QueryBuildingParameters getQueryBuildingParameters() { - return queryProcessor.getQueryBuildingParameters(); + return buildingParameters; } protected final SessionFactoryImplementor getSessionFactory() { diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/EntityLoadQueryDetails.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/EntityLoadQueryDetails.java index 08a0dd15ae..f7052d5ac8 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/EntityLoadQueryDetails.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/EntityLoadQueryDetails.java @@ -84,17 +84,24 @@ public class EntityLoadQueryDetails extends AbstractLoadQueryDetails { generate(); } + /** + * Constructs an EntityLoadQueryDetails object from an initial object and new building parameters, + * with the guarantee that only batch size changed between the initial parameters and the new ones. + * + * @param initialEntityLoadQueryDetails The initial object to be copied + * @param buildingParameters The new building parameters, with only the batch size being different + * from the parameters used in the initial object. + */ protected EntityLoadQueryDetails( EntityLoadQueryDetails initialEntityLoadQueryDetails, QueryBuildingParameters buildingParameters) { - this( - initialEntityLoadQueryDetails.getLoadPlan(), - initialEntityLoadQueryDetails.getKeyColumnNames(), - new AliasResolutionContextImpl( initialEntityLoadQueryDetails.getSessionFactory() ), - (EntityReturn) initialEntityLoadQueryDetails.getRootReturn(), - buildingParameters, - initialEntityLoadQueryDetails.getSessionFactory() + super( + initialEntityLoadQueryDetails, + buildingParameters ); + this.entityReferenceAliases = initialEntityLoadQueryDetails.entityReferenceAliases; + this.readerCollector = initialEntityLoadQueryDetails.readerCollector; + generate(); } private EntityReturn getRootEntityReturn() { diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/LoadQueryJoinAndFetchProcessor.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/LoadQueryJoinAndFetchProcessor.java index 67633cbe00..070b8c5bb1 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/LoadQueryJoinAndFetchProcessor.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/LoadQueryJoinAndFetchProcessor.java @@ -13,6 +13,7 @@ import java.util.Set; import org.hibernate.AssertionFailure; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; +import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.util.StringHelper; @@ -20,7 +21,6 @@ import org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitia import org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl; import org.hibernate.loader.plan.exec.process.spi.ReaderCollector; import org.hibernate.loader.plan.exec.query.internal.SelectStatementBuilder; -import org.hibernate.loader.plan.exec.query.spi.QueryBuildingParameters; import org.hibernate.loader.plan.exec.spi.AliasResolutionContext; import org.hibernate.loader.plan.exec.spi.CollectionReferenceAliases; import org.hibernate.loader.plan.exec.spi.EntityReferenceAliases; @@ -66,34 +66,51 @@ import org.jboss.logging.Logger; public class LoadQueryJoinAndFetchProcessor { private static final Logger LOG = CoreLogging.logger( LoadQueryJoinAndFetchProcessor.class ); - private final AliasResolutionContextImpl aliasResolutionContext; - private final QueryBuildingParameters buildingParameters; + private final AliasResolutionContext aliasResolutionContext; + private final AliasResolutionContextImpl mutableAliasResolutionContext; + private final LoadQueryInfluencers queryInfluencers; private final SessionFactoryImplementor factory; /** - * Instantiates a LoadQueryBuilderHelper with the given information + * Instantiates a LoadQueryJoinAndFetchProcessor with the given information * - * @param aliasResolutionContext - * @param buildingParameters + * @param mutableAliasResolutionContext + * @param queryInfluencers * @param factory */ public LoadQueryJoinAndFetchProcessor( - AliasResolutionContextImpl aliasResolutionContext, - QueryBuildingParameters buildingParameters, + AliasResolutionContextImpl mutableAliasResolutionContext, + LoadQueryInfluencers queryInfluencers, SessionFactoryImplementor factory) { - this.aliasResolutionContext = aliasResolutionContext; - this.buildingParameters = buildingParameters; + this.aliasResolutionContext = mutableAliasResolutionContext; + this.mutableAliasResolutionContext = mutableAliasResolutionContext; + this.queryInfluencers = queryInfluencers; this.factory = factory; } + /** + * Instantiates a LoadQueryJoinAndFetchProcessor from an initial object and new query influencers. + * + * Aliases are considered already contributed to the initial objects alias resolution context + * and won't be added again. + * + * @param initialLoadQueryJoinAndFetchProcessor The initial object to be copied + * @param queryInfluencers The new query influencers + */ + public LoadQueryJoinAndFetchProcessor( + LoadQueryJoinAndFetchProcessor initialLoadQueryJoinAndFetchProcessor, + LoadQueryInfluencers queryInfluencers) { + this.aliasResolutionContext = initialLoadQueryJoinAndFetchProcessor.aliasResolutionContext; + // Do not change the alias resolution context, it should be pre-populated + this.mutableAliasResolutionContext = null; + this.queryInfluencers = queryInfluencers; + this.factory = initialLoadQueryJoinAndFetchProcessor.factory; + } + public AliasResolutionContext getAliasResolutionContext() { return aliasResolutionContext; } - public QueryBuildingParameters getQueryBuildingParameters() { - return buildingParameters; - } - public SessionFactoryImplementor getSessionFactory() { return factory; } @@ -165,7 +182,12 @@ public class LoadQueryJoinAndFetchProcessor { ); } - aliasResolutionContext.registerCompositeQuerySpaceUidResolution( rightHandSideUid, leftHandSideTableAlias ); + if ( mutableAliasResolutionContext != null ) { + mutableAliasResolutionContext.registerCompositeQuerySpaceUidResolution( + rightHandSideUid, + leftHandSideTableAlias + ); + } } private void renderEntityJoin(Join join, JoinFragment joinFragment) { @@ -173,8 +195,8 @@ public class LoadQueryJoinAndFetchProcessor { // see if there is already aliases registered for this entity query space (collection joins) EntityReferenceAliases aliases = aliasResolutionContext.resolveEntityReferenceAliases( rightHandSide.getUid() ); - if ( aliases == null ) { - aliasResolutionContext.generateEntityReferenceAliases( + if ( aliases == null && mutableAliasResolutionContext != null ) { + mutableAliasResolutionContext.generateEntityReferenceAliases( rightHandSide.getUid(), rightHandSide.getEntityPersister() ); @@ -205,10 +227,10 @@ public class LoadQueryJoinAndFetchProcessor { // calls to the Joinable.filterFragment() method where the Joinable is either the entity or // collection persister final String filter = associationType!=null? - associationType.getOnCondition( rhsTableAlias, factory, buildingParameters.getQueryInfluencers().getEnabledFilters() ): + associationType.getOnCondition( rhsTableAlias, factory, queryInfluencers.getEnabledFilters() ): joinable.filterFragment( rhsTableAlias, - buildingParameters.getQueryInfluencers().getEnabledFilters() + queryInfluencers.getEnabledFilters() ); if ( StringHelper.isEmpty( withClause ) && StringHelper.isEmpty( filter ) ) { @@ -295,7 +317,19 @@ public class LoadQueryJoinAndFetchProcessor { private void renderCollectionJoin(Join join, JoinFragment joinFragment) { final CollectionQuerySpace rightHandSide = (CollectionQuerySpace) join.getRightHandSide(); + if ( mutableAliasResolutionContext != null ) { + registerCollectionJoinAliases( mutableAliasResolutionContext, rightHandSide ); + } + addJoins( + join, + joinFragment, + (Joinable) rightHandSide.getCollectionPersister(), + null + ); + } + private void registerCollectionJoinAliases(AliasResolutionContextImpl mutableAliasResolutionContext, + CollectionQuerySpace rightHandSide) { // The SQL join to the "collection table" needs to be rendered. // // In the case of a basic collection, that's the only join needed. @@ -351,14 +385,14 @@ public class LoadQueryJoinAndFetchProcessor { ) ); } - aliasResolutionContext.generateCollectionReferenceAliases( + mutableAliasResolutionContext.generateCollectionReferenceAliases( rightHandSide.getUid(), rightHandSide.getCollectionPersister(), collectionElementJoin.getRightHandSide().getUid() ); } else { - aliasResolutionContext.generateCollectionReferenceAliases( + mutableAliasResolutionContext.generateCollectionReferenceAliases( rightHandSide.getUid(), rightHandSide.getCollectionPersister(), null @@ -378,17 +412,11 @@ public class LoadQueryJoinAndFetchProcessor { ) ); } - aliasResolutionContext.generateEntityReferenceAliases( + mutableAliasResolutionContext.generateEntityReferenceAliases( collectionIndexJoin.getRightHandSide().getUid(), rightHandSide.getCollectionPersister().getIndexDefinition().toEntityDefinition().getEntityPersister() ); } - addJoins( - join, - joinFragment, - (Joinable) rightHandSide.getCollectionPersister(), - null - ); } private void renderManyToManyJoin( @@ -419,7 +447,7 @@ public class LoadQueryJoinAndFetchProcessor { final CollectionPersister persister = leftHandSide.getCollectionPersister(); manyToManyFilter = persister.getManyToManyFilterFragment( entityTableAlias, - buildingParameters.getQueryInfluencers().getEnabledFilters() + queryInfluencers.getEnabledFilters() ); } else {