diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/DomainPathPart.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/DomainPathPart.java index 48ce90fefa3b..52c1a05eb7f7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/DomainPathPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/DomainPathPart.java @@ -45,6 +45,12 @@ public SemanticPathPart resolvePathPart( throw new SemanticException( "Cannot resolve path (`" + name + "`) relative to `" + lhs.getNavigablePath() + "`" ); } //noinspection unchecked + final SqmPath existingImplicitJoinPath = lhs.getImplicitJoinPath( name ); + if ( existingImplicitJoinPath != null ) { + currentPath = existingImplicitJoinPath; + return this; + } + currentPath = subPathSource.createSqmPath( lhs, creationState ); if ( isTerminal ) { return currentPath; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPath.java index 3ccbd645e8d1..3a941c48fed0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPath.java @@ -125,9 +125,19 @@ public void registerImplicitJoinPath(SqmPath path) { } final String relativeName = path.getNavigablePath().getLocalName(); - if ( !implicitJoinPaths.containsKey( relativeName ) ) { - implicitJoinPaths.put( relativeName, path ); + + final SqmPath previous = implicitJoinPaths.put( relativeName, path ); + if ( previous != null && previous != path ) { + throw new IllegalStateException( "Implicit-join path registration unexpectedly overrode previous registration - " + relativeName ); + } + } + + @Override + public SqmPath getImplicitJoinPath(String name) { + if ( implicitJoinPaths == null ) { + return null; } + return implicitJoinPaths.get( name ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPath.java index 1f7ed1f8eb72..eccd2f1c2be3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPath.java @@ -77,6 +77,8 @@ public interface SqmPath extends SqmExpression, SemanticPathPart, JpaPath< */ void registerImplicitJoinPath(SqmPath path); + SqmPath getImplicitJoinPath(String name); + /** * This node's type is its "referenced path source" */ diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/sqm/exec/SubQueryImplicitJoinReferenceTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/sqm/exec/SubQueryImplicitJoinReferenceTest.java index 3d4a551cb644..62a731ff9798 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/sqm/exec/SubQueryImplicitJoinReferenceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/sqm/exec/SubQueryImplicitJoinReferenceTest.java @@ -54,14 +54,35 @@ public void performDataPreparation(SessionFactoryScope scope) { public void performHqlTest(SessionFactoryScope scope) { // Now simulate running an audit query scope.inSession( session -> { - session.createQuery( "select e__ FROM org.hibernate.orm.test.SubQueryImplicitJoinReferenceTest$TheEntity e__ " + session.createQuery( "select e__ FROM TheEntity e__ " + "WHERE e__.originalId.rev.id = (select max(e2__.originalId.rev.id) FROM " - + "org.hibernate.orm.test.SubQueryImplicitJoinReferenceTest$TheEntity e2__ WHERE " + + + "TheEntity e2__ WHERE " + "e2__.originalId.rev.id <= 2 and e__.originalId.id = e2__.originalId.id)" ).list(); } ); } - @Entity + @Test + public void performHqlTest2(SessionFactoryScope scope) { + // Now simulate running an audit query + scope.inSession( session -> { + session.createQuery( "select e__ FROM TheEntity e__ " + + "WHERE e__.originalId.id = (select max(e2__.originalId.id) FROM " + + "TheEntity e2__ WHERE " + + "e__.originalId.id = e2__.originalId.id and e2__.originalId.rev.id <= 2)" ).list(); + } ); + } + + @Test + public void performHqlTest3(SessionFactoryScope scope) { + // Now simulate running an audit query + scope.inSession( session -> { + session.createQuery( "select e2__.originalId.id, e2__.originalId.rev.id FROM " + + "TheEntity e2__ WHERE " + + " e2__.originalId.rev.id <= 2" ).list(); + } ); + } + + @Entity(name = "TheEntity") public static class TheEntity { @EmbeddedId private OriginalId originalId;