From 1905e8bba32c0198bdf4b5002e2bb7561504789d Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Mon, 8 Mar 2021 19:10:26 +0100 Subject: [PATCH] HHH-14482 Do not discard prior implicit join by key --- .../query/hql/internal/DomainPathPart.java | 6 +++++ .../sqm/tree/domain/AbstractSqmPath.java | 14 ++++++++-- .../query/sqm/tree/domain/SqmPath.java | 2 ++ .../SubQueryImplicitJoinReferenceTest.java | 27 ++++++++++++++++--- 4 files changed, 44 insertions(+), 5 deletions(-) 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 48ce90fefa..52c1a05eb7 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 class DomainPathPart implements SemanticPathPart { 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 3ccbd645e8..3a941c48fe 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,11 +125,21 @@ public abstract class AbstractSqmPath extends AbstractSqmExpression implem } 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 public String getExplicitAlias() { return getAlias(); 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 1f7ed1f8eb..eccd2f1c2b 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 3d4a551cb6..62a731ff97 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 class SubQueryImplicitJoinReferenceTest { 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;