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 54b9083eaa09..3e1736f829d0 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 @@ -16,6 +16,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; @@ -173,6 +175,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 6dbc75c8eaf2..aa226f056d74 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 @@ -148,6 +148,7 @@ public SqmPathSource getModel() { @Override public SqmPathSource getResolvedModel() { final SqmPathSource pathSource = getReferencedPathSource(); + if ( pathSource.isGeneric() && getLhs().getResolvedModel().getPathType() instanceof SqmManagedDomainType lhsType ) { final var concreteAttribute = 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..3f8fea40eb6f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedCteJoin.java @@ -0,0 +1,98 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +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, SqmCorrelatedSingularValuedJoin { + + 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..a38c06c07b74 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedDerivedJoin.java @@ -0,0 +1,103 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +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, SqmCorrelatedSingularValuedJoin { + + 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..aabbc4170fd4 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedDerivedRoot.java @@ -0,0 +1,66 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.query.sqm.tree.domain; + +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 SqmEntityDomainType 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..6335fe1b3333 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedDerivedRootJoin.java @@ -0,0 +1,90 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.query.sqm.tree.domain; + +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 SqmEntityDomainType 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 67cb6d1c99b0..a909e476fb88 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 @@ -5,9 +5,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 @@ -26,6 +31,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 ); @@ -80,4 +90,16 @@ public SqmRoot getCorrelatedRoot() { public X accept(SemanticQueryWalker walker) { return walker.visitCorrelatedRoot( this ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmCorrelatedRoot that + && super.equals( object ) + && Objects.equals( this.correlationParent, that.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 df5defc533f9..d5c41073118b 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 @@ -97,6 +97,6 @@ public SqmPathSource getResolvedModel() { @Override public SqmCorrelatedRoot createCorrelation() { - throw new UnsupportedOperationException(); + return new SqmCorrelatedDerivedRoot<>( this ); } } 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 316088534271..7e4c1061598f 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 @@ -101,7 +101,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 6b7819ba0d90..f2a9797fb1b3 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 @@ -14,7 +14,8 @@ import org.hibernate.query.sqm.tree.SqmJoinType; import org.hibernate.query.sqm.tree.cte.SqmCteStatement; import org.hibernate.query.sqm.tree.domain.AbstractSqmJoin; -import org.hibernate.query.sqm.tree.domain.SqmCorrelatedEntityJoin; +import org.hibernate.query.sqm.tree.domain.SqmCorrelatedCteJoin; +import org.hibernate.query.sqm.tree.domain.SqmSingularValuedJoin; import org.hibernate.query.sqm.tree.domain.SqmTreatedJoin; import org.hibernate.spi.NavigablePath; @@ -24,7 +25,7 @@ * @author Christian Beikov */ @Incubating -public class SqmCteJoin extends AbstractSqmJoin { +public class SqmCteJoin extends AbstractSqmJoin implements SqmSingularValuedJoin { private final SqmCteStatement cte; public SqmCteJoin( @@ -116,8 +117,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 1e9d310f0eb8..eebd9990f8f4 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 @@ -10,6 +10,8 @@ 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.sqm.tree.domain.SqmSingularValuedJoin; import org.hibernate.query.sqm.tuple.internal.AnonymousTupleType; import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SqmPathSource; @@ -17,7 +19,6 @@ import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmJoinType; import org.hibernate.query.sqm.tree.domain.AbstractSqmJoin; -import org.hibernate.query.sqm.tree.domain.SqmCorrelatedEntityJoin; import org.hibernate.query.sqm.tree.domain.SqmTreatedJoin; import org.hibernate.query.sqm.tree.select.SqmSubQuery; import org.hibernate.spi.NavigablePath; @@ -30,7 +31,7 @@ * @author Christian Beikov */ @Incubating -public class SqmDerivedJoin extends AbstractSqmJoin implements JpaDerivedJoin { +public class SqmDerivedJoin extends AbstractSqmJoin implements JpaDerivedJoin, SqmSingularValuedJoin { private final SqmSubQuery subQuery; private final boolean lateral; @@ -166,8 +167,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..201f33aeee0a --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/CorrelationCteDerivedJoinTest.java @@ -0,0 +1,62 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.jpa.query; + +import org.hibernate.testing.orm.domain.StandardDomainModel; +import org.hibernate.testing.orm.junit.DialectFeatureChecks; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.RequiresDialectFeature; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +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..448b4ea58b47 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/CorrelationCteDerivedRootTest.java @@ -0,0 +1,60 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.jpa.query; + +import org.hibernate.testing.orm.domain.StandardDomainModel; +import org.hibernate.testing.orm.junit.DialectFeatureChecks; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.RequiresDialectFeature; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +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(); + }); + } + +}