diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan2/build/spi/LoadPlanTreePrinter.java b/hibernate-core/src/main/java/org/hibernate/loader/plan2/build/spi/LoadPlanTreePrinter.java index 3a33fdda1c..9e677ae55f 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan2/build/spi/LoadPlanTreePrinter.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan2/build/spi/LoadPlanTreePrinter.java @@ -84,8 +84,6 @@ public class LoadPlanTreePrinter { printWriter.flush(); printStream.flush(); log.debug( new String( byteArrayOutputStream.toByteArray() ) ); - -// log.debug( toString( loadPlan, aliasResolutionContext ) ); } private void logTree( diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan2/exec/internal/AliasResolutionContextImpl.java b/hibernate-core/src/main/java/org/hibernate/loader/plan2/exec/internal/AliasResolutionContextImpl.java index 67fa56a114..4770edcbaa 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan2/exec/internal/AliasResolutionContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan2/exec/internal/AliasResolutionContextImpl.java @@ -69,7 +69,7 @@ public class AliasResolutionContextImpl implements AliasResolutionContext { private Map entityReferenceAliasesMap; private Map collectionReferenceAliasesMap; - private Map querySpaceUidToSqlTableAliasMap; + private Map querySpaceUidToSqlTableAliasMap; private Map compositeQuerySpaceUidToSqlTableAliasMap; @@ -129,11 +129,11 @@ public class AliasResolutionContextImpl implements AliasResolutionContext { } public CollectionReferenceAliases generateCollectionReferenceAliases(String uid, CollectionPersister persister) { + final String manyToManyTableAlias = persister.isManyToMany()? createTableAlias( persister.getRole() ) : null; + final String tableAlias = createTableAlias( persister.getRole() ); final CollectionReferenceAliasesImpl aliases = new CollectionReferenceAliasesImpl( - createTableAlias( persister.getRole() ), - persister.isManyToMany() - ? createTableAlias( persister.getRole() ) - : null, + tableAlias, + manyToManyTableAlias, createCollectionAliases( persister ), createCollectionElementAliases( persister ) ); @@ -212,7 +212,7 @@ public class AliasResolutionContextImpl implements AliasResolutionContext { collectionReferenceAliasesMap = new HashMap(); } collectionReferenceAliasesMap.put( querySpaceUid, collectionReferenceAliases ); - registerSqlTableAliasMapping( querySpaceUid, collectionReferenceAliases.getElementTableAlias() ); + registerSqlTableAliasMapping( querySpaceUid, collectionReferenceAliases.getCollectionTableAlias() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan2/exec/internal/LoadQueryJoinAndFetchProcessor.java b/hibernate-core/src/main/java/org/hibernate/loader/plan2/exec/internal/LoadQueryJoinAndFetchProcessor.java index a03571b6c9..8550e668eb 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan2/exec/internal/LoadQueryJoinAndFetchProcessor.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan2/exec/internal/LoadQueryJoinAndFetchProcessor.java @@ -68,7 +68,7 @@ import org.hibernate.sql.JoinType; * @author Steve Ebersole */ public class LoadQueryJoinAndFetchProcessor { - private static final Logger log = CoreLogging.logger( LoadQueryJoinAndFetchProcessor.class ); + private static final Logger LOG = CoreLogging.logger( LoadQueryJoinAndFetchProcessor.class ); private final AliasResolutionContextImpl aliasResolutionContext; private final QueryBuildingParameters buildingParameters; @@ -91,6 +91,7 @@ public class LoadQueryJoinAndFetchProcessor { } public void processQuerySpaceJoins(QuerySpace querySpace, SelectStatementBuilder selectStatementBuilder) { + LOG.debug( "processing queryspace " + querySpace.getUid() ); final JoinFragment joinFragment = factory.getDialect().createOuterJoinFragment(); processQuerySpaceJoins( querySpace, joinFragment ); @@ -127,7 +128,16 @@ public class LoadQueryJoinAndFetchProcessor { else if ( EntityQuerySpace.class.isInstance( join.getRightHandSide() ) ) { // do not render the entity join for a one-to-many association, since the collection join // already joins to the associated entity table (see doc in renderCollectionJoin()). - if ( join.getLeftHandSide().getDisposition() != QuerySpace.Disposition.COLLECTION || + if ( join.getLeftHandSide().getDisposition() == QuerySpace.Disposition.COLLECTION && + CollectionQuerySpace.class.cast( join.getLeftHandSide() ).getCollectionPersister().isManyToMany() ) { + final CollectionQuerySpace leftHandSide = (CollectionQuerySpace) join.getLeftHandSide(); + final CollectionReferenceAliases aliases = aliasResolutionContext.resolveCollectionReferenceAliases( + leftHandSide.getUid() + ); + + renderManyToManyJoin(aliases, leftHandSide, join, joinFragment ); + } + else if ( join.getLeftHandSide().getDisposition() != QuerySpace.Disposition.COLLECTION || ! CollectionQuerySpace.class.cast( join.getLeftHandSide() ).getCollectionPersister().isOneToMany() ) { renderEntityJoin( join, joinFragment ); } @@ -371,34 +381,34 @@ public class LoadQueryJoinAndFetchProcessor { ); } -// private void renderManyToManyJoin( -// CollectionReferenceAliases aliases, -// CollectionQuerySpace rightHandSide, + private void renderManyToManyJoin( + CollectionReferenceAliases aliases, + CollectionQuerySpace rightHandSide, // String[] aliasedLhsColumnNames, -// Join join, -// JoinFragment joinFragment) { -// final CollectionPersister persister = rightHandSide.getCollectionPersister(); -// final QueryableCollection queryableCollection = (QueryableCollection) persister; -// -// // for many-to-many we have 3 table aliases. By way of example, consider a normal m-n: User<->Role -// // where User is the FetchOwner and Role (User.roles) is the Fetch. We'd have: -// // 1) the owner's table : user - in terms of rendering the joins (not the fetch select fragments), the -// // lhs table alias is only needed to qualify the lhs join columns, but we already have the qualified -// // columns here (aliasedLhsColumnNames) -// //final String ownerTableAlias = ...; -// // 2) the m-n table : user_role -// final String collectionTableAlias = aliases.getCollectionTableAlias(); -// // 3) the element table : role -// final String elementTableAlias = aliases.getElementTableAlias(); -// -// // somewhere, one of these being empty is causing trouble... -// if ( StringHelper.isEmpty( collectionTableAlias ) ) { -// throw new IllegalStateException( "Collection table alias cannot be empty" ); -// } -// if ( StringHelper.isEmpty( elementTableAlias ) ) { -// throw new IllegalStateException( "Collection element (many-to-many) table alias cannot be empty" ); -// } -// + Join join, + JoinFragment joinFragment) { + final CollectionPersister persister = rightHandSide.getCollectionPersister(); + final QueryableCollection queryableCollection = (QueryableCollection) persister; + + // for many-to-many we have 3 table aliases. By way of example, consider a normal m-n: User<->Role + // where User is the FetchOwner and Role (User.roles) is the Fetch. We'd have: + // 1) the owner's table : user - in terms of rendering the joins (not the fetch select fragments), the + // lhs table alias is only needed to qualify the lhs join columns, but we already have the qualified + // columns here (aliasedLhsColumnNames) + //final String ownerTableAlias = ...; + // 2) the m-n table : user_role + final String collectionTableAlias = aliases.getCollectionTableAlias(); + // 3) the element table : role + final String elementTableAlias = aliases.getElementTableAlias(); + + // somewhere, one of these being empty is causing trouble... + if ( StringHelper.isEmpty( collectionTableAlias ) ) { + throw new IllegalStateException( "Collection table alias cannot be empty" ); + } + if ( StringHelper.isEmpty( elementTableAlias ) ) { + throw new IllegalStateException( "Collection element (many-to-many) table alias cannot be empty" ); + } + // // { // // add join fragments from the owner table -> collection table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -420,45 +430,45 @@ public class LoadQueryJoinAndFetchProcessor { // queryableCollection.whereJoinFragment( collectionTableAlias, false, true ) // ); // } -// -// { -// // add join fragments from the collection table -> element entity table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// final String additionalJoinConditions = resolveAdditionalJoinCondition( -// elementTableAlias, -// join.getAnyAdditionalJoinConditions( elementTableAlias ), -// queryableCollection -// ); -// -// final String manyToManyFilter = persister.getManyToManyFilterFragment( -// collectionTableAlias, -// buildingParameters.getQueryInfluencers().getEnabledFilters() -// ); -// -// final String condition; -// if ( StringHelper.isEmpty( manyToManyFilter ) ) { -// condition = additionalJoinConditions; -// } -// else if ( StringHelper.isEmpty( additionalJoinConditions ) ) { -// condition = manyToManyFilter; -// } -// else { -// condition = additionalJoinConditions + " and " + manyToManyFilter; -// } -// -// final OuterJoinLoadable elementPersister = (OuterJoinLoadable) queryableCollection.getElementPersister(); -// -// addJoins( -// joinFragment, -// elementPersister, -// JoinType.LEFT_OUTER_JOIN, -// elementTableAlias, -// elementPersister.getIdentifierColumnNames(), -// StringHelper.qualify( collectionTableAlias, queryableCollection.getElementColumnNames() ), -// condition -// ); -// } -// } -// + + { + // add join fragments from the collection table -> element entity table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + final String additionalJoinConditions = resolveAdditionalJoinCondition( + elementTableAlias, + join.getAnyAdditionalJoinConditions( elementTableAlias ), + queryableCollection + ); + + final String manyToManyFilter = persister.getManyToManyFilterFragment( + collectionTableAlias, + buildingParameters.getQueryInfluencers().getEnabledFilters() + ); + + final String condition; + if ( StringHelper.isEmpty( manyToManyFilter ) ) { + condition = additionalJoinConditions; + } + else if ( StringHelper.isEmpty( additionalJoinConditions ) ) { + condition = manyToManyFilter; + } + else { + condition = additionalJoinConditions + " and " + manyToManyFilter; + } + + final OuterJoinLoadable elementPersister = (OuterJoinLoadable) queryableCollection.getElementPersister(); + + addJoins( + joinFragment, + elementPersister, + JoinType.LEFT_OUTER_JOIN, + elementTableAlias, + elementPersister.getIdentifierColumnNames(), + StringHelper.qualify( collectionTableAlias, queryableCollection.getElementColumnNames() ), + condition + ); + } + } + // private void renderOneToManyJoin( // CollectionReferenceAliases aliases, // CollectionQuerySpace rightHandSide, @@ -699,8 +709,9 @@ public class LoadQueryJoinAndFetchProcessor { selectStatementBuilder.appendSelectClauseFragment( joinableCollection.selectFragment( (Joinable) queryableCollection.getElementPersister(), - ownerTableAlias, + elementTableAlias, collectionTableAlias, + aliases.getEntityElementColumnAliases().getSuffix(), aliases.getCollectionColumnAliases().getSuffix(), true @@ -731,7 +742,7 @@ public class LoadQueryJoinAndFetchProcessor { final EntityReferenceAliases entityReferenceAliases = new EntityReferenceAliases() { @Override public String getTableAlias() { - return aliases.getElementTableAlias(); + return aliases.getCollectionTableAlias(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan2/exec/process/internal/ResultSetProcessingContextImpl.java b/hibernate-core/src/main/java/org/hibernate/loader/plan2/exec/process/internal/ResultSetProcessingContextImpl.java index 211b56116d..e61a2f2f19 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan2/exec/process/internal/ResultSetProcessingContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan2/exec/process/internal/ResultSetProcessingContextImpl.java @@ -84,8 +84,6 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex private Map> subselectLoadableEntityKeyMap; private List hydratedEntityRegistrationList; - private final LockModeResolver lockModeResolverDelegate; - /** * Builds a ResultSetProcessingContextImpl * @@ -132,16 +130,6 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex } } } - this.lockModeResolverDelegate = new LockModeResolver() { - @Override - public LockMode resolveLockMode(EntityReference entityReference) { - if ( queryParameters.getLockOptions() != null && queryParameters.getLockOptions() - .getLockMode() != null ) { - return queryParameters.getLockOptions().getLockMode(); - } - return LockMode.READ; - } - }; } @Override @@ -175,8 +163,11 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex @Override public LockMode resolveLockMode(EntityReference entityReference) { - final LockMode lockMode = lockModeResolverDelegate.resolveLockMode( entityReference ); - return LockMode.NONE == lockMode ? LockMode.NONE : lockMode; + if ( queryParameters.getLockOptions() != null && queryParameters.getLockOptions() + .getLockMode() != null ) { + return queryParameters.getLockOptions().getLockMode(); + } + return LockMode.READ; } private Map identifierResolutionContextMap; diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan2/exec/process/spi/AbstractRowReader.java b/hibernate-core/src/main/java/org/hibernate/loader/plan2/exec/process/spi/AbstractRowReader.java index 5ab95fd947..26cf88e6a3 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan2/exec/process/spi/AbstractRowReader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan2/exec/process/spi/AbstractRowReader.java @@ -34,6 +34,7 @@ import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.PostLoadEvent; import org.hibernate.event.spi.PreLoadEvent; import org.hibernate.internal.CoreLogging; +import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.loader.plan2.exec.process.internal.HydratedEntityRegistration; import org.hibernate.loader.plan2.exec.process.internal.ResultSetProcessingContextImpl; import org.hibernate.loader.spi.AfterLoadAction; @@ -58,7 +59,7 @@ public abstract class AbstractRowReader implements RowReader { final List arrayReferenceInitializers = getArrayReferenceInitializers(); final List collectionReferenceInitializers = getCollectionReferenceInitializers(); - final boolean hasEntityReferenceInitializers = entityReferenceInitializers != null && entityReferenceInitializers.size() > 0; + final boolean hasEntityReferenceInitializers = CollectionHelper.isNotEmpty( entityReferenceInitializers ); if ( hasEntityReferenceInitializers ) { // 1) allow entity references to resolve identifiers (in 2 steps)