HHH-12594 Properly share AliasResolutionContextImpl between EntityLoadQueryDetails instances

In particular, avoid contributing the aliases twice for the same
context: this would just trigger exceptions.
This commit is contained in:
Yoann Rodière 2018-06-25 16:07:20 +02:00 committed by Guillaume Smet
parent 665110452e
commit a19fc84320
3 changed files with 97 additions and 38 deletions

View File

@ -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() {

View File

@ -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() {

View File

@ -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 {