diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmPathRegistryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmPathRegistryImpl.java index 66df7acc85ae..5f2d34097ae4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmPathRegistryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmPathRegistryImpl.java @@ -17,6 +17,7 @@ import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor; import org.hibernate.query.SemanticException; +import org.hibernate.query.criteria.JpaJoinedFrom; import org.hibernate.query.hql.HqlLogging; import org.hibernate.query.hql.spi.SqmCreationProcessingState; import org.hibernate.query.hql.spi.SqmPathRegistry; @@ -24,12 +25,10 @@ import org.hibernate.query.sqm.ParsingException; import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.SqmTreeCreationLogger; +import org.hibernate.query.sqm.tree.domain.AbstractSqmFrom; +import org.hibernate.query.sqm.tree.domain.SqmCorrelation; import org.hibernate.query.sqm.tree.domain.SqmPath; -import org.hibernate.query.sqm.tree.from.SqmCrossJoin; -import org.hibernate.query.sqm.tree.from.SqmEntityJoin; -import org.hibernate.query.sqm.tree.from.SqmFrom; -import org.hibernate.query.sqm.tree.from.SqmJoin; -import org.hibernate.query.sqm.tree.from.SqmRoot; +import org.hibernate.query.sqm.tree.from.*; import org.hibernate.query.sqm.tree.select.SqmAliasedNode; import org.hibernate.query.sqm.tree.select.SqmSubQuery; import org.hibernate.spi.NavigablePath; @@ -244,6 +243,12 @@ else if ( parentRegistered instanceof SqmCrossJoin ) { else if ( parentRegistered instanceof SqmEntityJoin ) { correlated = selectQuery.correlate( (SqmEntityJoin) parentRegistered ); } + else if ( parentRegistered instanceof AbstractSqmFrom) { + final SqmCorrelation correlation = + ((AbstractSqmFrom) parentRegistered).createCorrelation(); + selectQuery.getQuerySpec().addRoot( correlation.getCorrelatedRoot() ); + correlated = correlation; + } else { throw new UnsupportedOperationException( "Can't correlate from node: " + parentRegistered ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/SemanticQueryWalker.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/SemanticQueryWalker.java index 60fdb465ae59..785abb1ccad8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/SemanticQueryWalker.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/SemanticQueryWalker.java @@ -19,6 +19,8 @@ import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath; import org.hibernate.query.sqm.tree.domain.SqmCorrelatedBagJoin; import org.hibernate.query.sqm.tree.domain.SqmCorrelatedCrossJoin; +import org.hibernate.query.sqm.tree.domain.SqmCorrelatedCteJoin; +import org.hibernate.query.sqm.tree.domain.SqmCorrelatedDerivedJoin; import org.hibernate.query.sqm.tree.domain.SqmCorrelatedEntityJoin; import org.hibernate.query.sqm.tree.domain.SqmCorrelatedListJoin; import org.hibernate.query.sqm.tree.domain.SqmCorrelatedMapJoin; @@ -170,6 +172,14 @@ public interface SemanticQueryWalker { T visitQualifiedAttributeJoin(SqmAttributeJoin joinedFromElement); + default T visitCorrelatedCteJoin(SqmCorrelatedCteJoin join){ + return visitQualifiedCteJoin( join ); + } + + default T visitCorrelatedDerivedJoin(SqmCorrelatedDerivedJoin join){ + return visitQualifiedDerivedJoin( join ); + } + default T visitCorrelatedCrossJoin(SqmCorrelatedCrossJoin join) { return visitCrossJoin( join ); } 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 e283e5d5a960..b212cc8092ad 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 @@ -158,6 +158,7 @@ public SqmPathSource getModel() { public SqmPathSource getResolvedModel() { final DomainType lhsType; final SqmPathSource pathSource = getReferencedPathSource(); + if ( pathSource.isGeneric() && ( lhsType = getLhs().getResolvedModel().getSqmPathType() ) instanceof ManagedDomainType ) { final PersistentAttribute concreteAttribute = ( (ManagedDomainType) lhsType ).findConcreteGenericAttribute( pathSource.getPathName() diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedCteJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedCteJoin.java new file mode 100644 index 000000000000..4c409e92625d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedCteJoin.java @@ -0,0 +1,100 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.query.sqm.tree.domain; + +import org.hibernate.query.sqm.SemanticQueryWalker; +import org.hibernate.query.sqm.SqmPathSource; +import org.hibernate.query.sqm.tree.SqmCopyContext; +import org.hibernate.query.sqm.tree.SqmJoinType; +import org.hibernate.query.sqm.tree.cte.SqmCteStatement; +import org.hibernate.query.sqm.tree.from.SqmCteJoin; +import org.hibernate.query.sqm.tree.from.SqmRoot; +import org.hibernate.spi.NavigablePath; + +/** + * @author Christian Beikov + */ +public class SqmCorrelatedCteJoin extends SqmCteJoin implements SqmCorrelation { + + private final SqmCorrelatedRootJoin correlatedRootJoin; + private final SqmCteJoin correlationParent; + + public SqmCorrelatedCteJoin(SqmCteJoin correlationParent) { + //noinspection unchecked + super( + correlationParent.getCte(), + correlationParent.getExplicitAlias(), + correlationParent.getSqmJoinType(), + (SqmRoot) correlationParent.getRoot() + ); + this.correlatedRootJoin = SqmCorrelatedDerivedRootJoin.create( correlationParent, this ); + this.correlationParent = correlationParent; + } + + private SqmCorrelatedCteJoin( + NavigablePath navigablePath, + SqmCteStatement cte, + SqmPathSource pathSource, + String alias, + SqmJoinType joinType, + SqmRoot sqmRoot, + SqmCorrelatedRootJoin correlatedRootJoin, + SqmCteJoin correlationParent) { + super( navigablePath, cte, pathSource, alias, joinType, sqmRoot ); + this.correlatedRootJoin = correlatedRootJoin; + this.correlationParent = correlationParent; + } + + @Override + public SqmCorrelatedCteJoin copy(SqmCopyContext context) { + final SqmCorrelatedCteJoin existing = context.getCopy( this ); + if ( existing != null ) { + return existing; + } + final SqmCorrelatedCteJoin path = context.registerCopy( + this, + new SqmCorrelatedCteJoin<>( + getNavigablePath(), + getCte().copy( context ), + getReferencedPathSource(), + getExplicitAlias(), + getSqmJoinType(), + (SqmRoot) findRoot().copy( context ), + correlatedRootJoin.copy( context ), + correlationParent.copy( context ) + ) + ); + copyTo( path, context ); + return path; + } + + @Override + public SqmCteJoin getCorrelationParent() { + return correlationParent; + } + + @Override + public SqmPath getWrappedPath() { + return correlationParent; + } + + @Override + public boolean isCorrelated() { + return true; + } + + @Override + public SqmRoot getCorrelatedRoot() { + return correlatedRootJoin; + } + + @Override + public X accept(SemanticQueryWalker walker) { + return walker.visitCorrelatedCteJoin( this ); + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedDerivedJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedDerivedJoin.java new file mode 100644 index 000000000000..ecf42b319956 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedDerivedJoin.java @@ -0,0 +1,105 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.query.sqm.tree.domain; + +import org.hibernate.query.sqm.SemanticQueryWalker; +import org.hibernate.query.sqm.SqmPathSource; +import org.hibernate.query.sqm.tree.SqmCopyContext; +import org.hibernate.query.sqm.tree.SqmJoinType; +import org.hibernate.query.sqm.tree.from.SqmDerivedJoin; +import org.hibernate.query.sqm.tree.from.SqmRoot; +import org.hibernate.query.sqm.tree.select.SqmSubQuery; +import org.hibernate.spi.NavigablePath; + +/** + * @author Christian Beikov + */ +public class SqmCorrelatedDerivedJoin extends SqmDerivedJoin implements SqmCorrelation { + + private final SqmCorrelatedRootJoin correlatedRootJoin; + private final SqmDerivedJoin correlationParent; + + public SqmCorrelatedDerivedJoin(SqmDerivedJoin correlationParent) { + //noinspection unchecked + super( + correlationParent.getNavigablePath(), + correlationParent.getQueryPart(), + correlationParent.isLateral(), + correlationParent.getReferencedPathSource(), + correlationParent.getExplicitAlias(), + correlationParent.getSqmJoinType(), + (SqmRoot) correlationParent.getRoot() + ); + this.correlatedRootJoin = SqmCorrelatedDerivedRootJoin.create( correlationParent, this ); + this.correlationParent = correlationParent; + } + + private SqmCorrelatedDerivedJoin( + NavigablePath navigablePath, + SqmSubQuery subQuery, + boolean lateral, + SqmPathSource pathSource, + String alias, + SqmJoinType joinType, + SqmRoot sqmRoot, + SqmCorrelatedRootJoin correlatedRootJoin, + SqmDerivedJoin correlationParent) { + super( navigablePath, subQuery, lateral, pathSource, alias, joinType, sqmRoot ); + this.correlatedRootJoin = correlatedRootJoin; + this.correlationParent = correlationParent; + } + + @Override + public SqmCorrelatedDerivedJoin copy(SqmCopyContext context) { + final SqmCorrelatedDerivedJoin existing = context.getCopy( this ); + if ( existing != null ) { + return existing; + } + final SqmCorrelatedDerivedJoin path = context.registerCopy( + this, + new SqmCorrelatedDerivedJoin<>( + getNavigablePath(), + getQueryPart(), + isLateral(), + getReferencedPathSource(), + getExplicitAlias(), + getSqmJoinType(), + (SqmRoot) findRoot().copy( context ), + correlatedRootJoin.copy( context ), + correlationParent.copy( context ) + ) + ); + copyTo( path, context ); + return path; + } + + @Override + public SqmDerivedJoin getCorrelationParent() { + return correlationParent; + } + + @Override + public SqmPath getWrappedPath() { + return correlationParent; + } + + @Override + public boolean isCorrelated() { + return true; + } + + @Override + public SqmRoot getCorrelatedRoot() { + return correlatedRootJoin; + } + + @Override + public X accept(SemanticQueryWalker walker) { + return walker.visitCorrelatedDerivedJoin( this ); + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedDerivedRoot.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedDerivedRoot.java new file mode 100644 index 000000000000..43e125f5d907 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedDerivedRoot.java @@ -0,0 +1,69 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.query.sqm.tree.domain; + +import org.hibernate.metamodel.model.domain.EntityDomainType; +import org.hibernate.query.sqm.SqmPathSource; +import org.hibernate.query.sqm.tree.SqmCopyContext; +import org.hibernate.query.sqm.tree.from.SqmRoot; + +/** + * @author Steve Ebersole + */ +public class SqmCorrelatedDerivedRoot extends SqmCorrelatedRoot implements SqmPathWrapper, SqmCorrelation { + + public SqmCorrelatedDerivedRoot(SqmDerivedRoot correlationParent) { + this( (SqmRoot) correlationParent ); + } + + public SqmCorrelatedDerivedRoot(SqmCteRoot correlationParent) { + this( (SqmRoot) correlationParent ); + } + + private SqmCorrelatedDerivedRoot(SqmRoot correlationParent) { + super( + correlationParent.getNavigablePath(), + correlationParent.getReferencedPathSource(), + correlationParent.nodeBuilder(), + correlationParent + ); + } + + @Override + public SqmCorrelatedDerivedRoot copy(SqmCopyContext context) { + final SqmCorrelatedDerivedRoot existing = context.getCopy( this ); + if ( existing != null ) { + return existing; + } + final SqmCorrelatedDerivedRoot path = context.registerCopy( + this, + new SqmCorrelatedDerivedRoot<>( getCorrelationParent().copy( context ) ) + ); + copyTo( path, context ); + return path; + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // JPA + + @Override + public EntityDomainType getModel() { + // Or should we throw an exception instead? + return null; + } + + @Override + public String getEntityName() { + return null; + } + + @Override + public SqmPathSource getResolvedModel() { + return getReferencedPathSource(); + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedDerivedRootJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedDerivedRootJoin.java new file mode 100644 index 000000000000..89d627eb8577 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedDerivedRootJoin.java @@ -0,0 +1,93 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.query.sqm.tree.domain; + +import org.hibernate.metamodel.model.domain.EntityDomainType; +import org.hibernate.query.sqm.NodeBuilder; +import org.hibernate.query.sqm.SqmPathSource; +import org.hibernate.query.sqm.tree.SqmCopyContext; +import org.hibernate.query.sqm.tree.from.SqmFrom; +import org.hibernate.query.sqm.tree.from.SqmJoin; +import org.hibernate.spi.NavigablePath; + +/** + * @author Steve Ebersole + */ +public class SqmCorrelatedDerivedRootJoin extends SqmCorrelatedRootJoin { + + public SqmCorrelatedDerivedRootJoin( + NavigablePath navigablePath, + SqmPathSource referencedNavigable, + NodeBuilder nodeBuilder) { + super( navigablePath, referencedNavigable, nodeBuilder ); + } + + @Override + public SqmCorrelatedDerivedRootJoin copy(SqmCopyContext context) { + final SqmCorrelatedDerivedRootJoin existing = context.getCopy( this ); + if ( existing != null ) { + return existing; + } + final SqmCorrelatedDerivedRootJoin path = context.registerCopy( + this, + new SqmCorrelatedDerivedRootJoin<>( + getNavigablePath(), + getReferencedPathSource(), + nodeBuilder() + ) + ); + copyTo( path, context ); + return path; + } + + @SuppressWarnings("unchecked") + public static > SqmCorrelatedDerivedRootJoin create(J correlationParent, J correlatedJoin) { + final SqmFrom parentPath = (SqmFrom) correlationParent.getParentPath(); + final SqmCorrelatedDerivedRootJoin rootJoin; + if ( parentPath == null ) { + rootJoin = new SqmCorrelatedDerivedRootJoin<>( + correlationParent.getNavigablePath(), + (SqmPathSource) correlationParent.getReferencedPathSource(), + correlationParent.nodeBuilder() + ); + } + else { + rootJoin = new SqmCorrelatedDerivedRootJoin<>( + parentPath.getNavigablePath(), + parentPath.getReferencedPathSource(), + correlationParent.nodeBuilder() + ); + } + rootJoin.addSqmJoin( correlatedJoin ); + return rootJoin; + } + + @Override + public boolean containsOnlyInnerJoins() { + // The derived join is just referenced, no need to create any table groups + return true; + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // JPA + + @Override + public EntityDomainType getModel() { + // Or should we throw an exception instead? + return null; + } + + @Override + public String getEntityName() { + return null; + } + + @Override + public SqmPathSource getResolvedModel() { + return getReferencedPathSource(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedRoot.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedRoot.java index 46b6a2e6cccc..07421314dea6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedRoot.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedRoot.java @@ -7,9 +7,14 @@ package org.hibernate.query.sqm.tree.domain; import org.hibernate.query.criteria.JpaSelection; +import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SemanticQueryWalker; +import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.from.SqmRoot; +import org.hibernate.spi.NavigablePath; + +import java.util.Objects; /** * @author Steve Ebersole @@ -28,6 +33,11 @@ public SqmCorrelatedRoot(SqmRoot correlationParent) { this.correlationParent = correlationParent; } + protected SqmCorrelatedRoot(NavigablePath navigablePath, SqmPathSource referencedNavigable, NodeBuilder nodeBuilder, SqmRoot correlationParent) { + super( navigablePath, referencedNavigable, nodeBuilder ); + this.correlationParent = correlationParent; + } + @Override public SqmCorrelatedRoot copy(SqmCopyContext context) { final SqmCorrelatedRoot existing = context.getCopy( this ); @@ -82,4 +92,16 @@ public SqmRoot getCorrelatedRoot() { public X accept(SemanticQueryWalker walker) { return walker.visitCorrelatedRoot( this ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmCorrelatedRoot + && super.equals( object ) + && Objects.equals( this.correlationParent, ((SqmCorrelatedRoot) object).correlationParent ); + } + + @Override + public int hashCode() { + return Objects.hash( super.hashCode(), correlationParent ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCteRoot.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCteRoot.java index b5ad796921ed..db11cdaf805b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCteRoot.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCteRoot.java @@ -102,7 +102,7 @@ public SqmPathSource getResolvedModel() { @Override public SqmCorrelatedRoot createCorrelation() { - throw new UnsupportedOperationException(); + return new SqmCorrelatedDerivedRoot<>( this ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmDerivedRoot.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmDerivedRoot.java index 11088294e3f9..180d6e75ba02 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmDerivedRoot.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmDerivedRoot.java @@ -104,7 +104,7 @@ public SqmPathSource getResolvedModel() { @Override public SqmCorrelatedRoot createCorrelation() { - throw new UnsupportedOperationException(); + return new SqmCorrelatedDerivedRoot<>( this ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmCteJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmCteJoin.java index 8f392bc896cf..d6c1fa758020 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmCteJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmCteJoin.java @@ -17,7 +17,7 @@ import org.hibernate.query.sqm.tree.SqmJoinType; import org.hibernate.query.sqm.tree.cte.SqmCteStatement; import org.hibernate.query.sqm.tree.domain.AbstractSqmQualifiedJoin; -import org.hibernate.query.sqm.tree.domain.SqmCorrelatedEntityJoin; +import org.hibernate.query.sqm.tree.domain.SqmCorrelatedCteJoin; import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.spi.NavigablePath; @@ -115,8 +115,8 @@ public X accept(SemanticQueryWalker walker) { // JPA @Override - public SqmCorrelatedEntityJoin createCorrelation() { - throw new UnsupportedOperationException(); + public SqmCorrelatedCteJoin createCorrelation() { + return new SqmCorrelatedCteJoin<>( this ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmDerivedJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmDerivedJoin.java index beb87f5c6534..16e696bdf735 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmDerivedJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmDerivedJoin.java @@ -12,6 +12,7 @@ import org.hibernate.query.criteria.JpaDerivedJoin; import org.hibernate.query.criteria.JpaExpression; import org.hibernate.query.criteria.JpaPredicate; +import org.hibernate.query.sqm.tree.domain.SqmCorrelatedDerivedJoin; import org.hibernate.query.derived.AnonymousTupleType; import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SqmPathSource; @@ -19,7 +20,6 @@ import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmJoinType; import org.hibernate.query.sqm.tree.domain.AbstractSqmQualifiedJoin; -import org.hibernate.query.sqm.tree.domain.SqmCorrelatedEntityJoin; import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.query.sqm.tree.select.SqmSubQuery; import org.hibernate.spi.NavigablePath; @@ -166,8 +166,8 @@ public X accept(SemanticQueryWalker walker) { // JPA @Override - public SqmCorrelatedEntityJoin createCorrelation() { - throw new UnsupportedOperationException(); + public SqmCorrelatedDerivedJoin createCorrelation() { + return new SqmCorrelatedDerivedJoin<>( this ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/CorrelationCteDerivedJoinTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/CorrelationCteDerivedJoinTest.java new file mode 100644 index 000000000000..0d0e3c40d0a5 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/CorrelationCteDerivedJoinTest.java @@ -0,0 +1,55 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.jpa.query; + +import org.hibernate.testing.orm.domain.StandardDomainModel; +import org.hibernate.testing.orm.junit.*; +import org.junit.jupiter.api.Test; + +@SessionFactory +@DomainModel(standardModels = StandardDomainModel.GAMBIT) +@JiraKey("HHH-17522") +@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsSubqueryInOnClause.class) +@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsOrderByInCorrelatedSubquery.class) +public class CorrelationCteDerivedJoinTest { + + @Test + public void tesDerivedJoin(SessionFactoryScope scope) { + scope.inTransaction(s -> { + s.createSelectionQuery("select corrSub.id " + + "from EntityOfBasics e " + + "left join ( " + + " select 1 as id " + + " from EntityOfBasics eSub " + + ") sub on true " + + "left join lateral ( " + + " select 1 as id " + + " from EntityOfBasics eSub " + + " where eSub.id = sub.id " + + ") corrSub on true", Integer.class ).getResultList(); + }); + } + + @Test + public void tesCte(SessionFactoryScope scope) { + scope.inTransaction(s -> { + s.createSelectionQuery("with mycte as ( " + + " select 1 as id " + + " from EntityOfBasics eSub " + + ") " + + "select corrSub.id " + + "from EntityOfBasics e " + + "left join mycte sub on true " + + "left join lateral ( " + + " select 1 as id " + + " from EntityOfBasics eSub " + + " where eSub.id = sub.id " + + ") corrSub on true", Integer.class ).getResultList(); + }); + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/CorrelationCteDerivedRootTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/CorrelationCteDerivedRootTest.java new file mode 100644 index 000000000000..8651ab42a97c --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/CorrelationCteDerivedRootTest.java @@ -0,0 +1,53 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.jpa.query; + +import org.hibernate.testing.orm.domain.StandardDomainModel; +import org.hibernate.testing.orm.junit.*; +import org.junit.jupiter.api.Test; + +@SessionFactory +@DomainModel(standardModels = StandardDomainModel.GAMBIT) +@JiraKey("HHH-17522") +@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsSubqueryInOnClause.class) +@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsOrderByInCorrelatedSubquery.class) +public class CorrelationCteDerivedRootTest { + + @Test + public void tesDerivedRoot(SessionFactoryScope scope) { + scope.inTransaction(s -> { + s.createSelectionQuery("select corrSub.id " + + "from ( " + + " select 1 as id " + + " from EntityOfBasics eSub " + + ") sub " + + "left join lateral ( " + + " select 1 as id " + + " from EntityOfBasics eSub " + + " where eSub.id = sub.id " + + ") corrSub on true", Integer.class ).getResultList(); + }); + } + + @Test + public void tesCte(SessionFactoryScope scope) { + scope.inTransaction(s -> { + s.createSelectionQuery("with mycte as ( " + + " select 1 as id " + + " from EntityOfBasics eSub " + + ") " + + "select corrSub.id " + + "from mycte sub " + + "left join lateral ( " + + " select 1 as id " + + " from EntityOfBasics eSub " + + " where eSub.id = sub.id " + + ") corrSub on true", Integer.class ).getResultList(); + }); + } + +}