Skip to content

Commit 469ffda

Browse files
oscarfanchinbeikov
authored andcommitted
HHH-17522 Test and fix correlation of CTE and derived roots and joins
1 parent f6c1b8c commit 469ffda

13 files changed

+524
-10
lines changed

hibernate-core/src/main/java/org/hibernate/query/sqm/SemanticQueryWalker.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
1717
import org.hibernate.query.sqm.tree.domain.SqmCorrelatedBagJoin;
1818
import org.hibernate.query.sqm.tree.domain.SqmCorrelatedCrossJoin;
19+
import org.hibernate.query.sqm.tree.domain.SqmCorrelatedCteJoin;
20+
import org.hibernate.query.sqm.tree.domain.SqmCorrelatedDerivedJoin;
1921
import org.hibernate.query.sqm.tree.domain.SqmCorrelatedEntityJoin;
2022
import org.hibernate.query.sqm.tree.domain.SqmCorrelatedListJoin;
2123
import org.hibernate.query.sqm.tree.domain.SqmCorrelatedMapJoin;
@@ -173,6 +175,14 @@ public interface SemanticQueryWalker<T> {
173175

174176
T visitQualifiedAttributeJoin(SqmAttributeJoin<?, ?> joinedFromElement);
175177

178+
default T visitCorrelatedCteJoin(SqmCorrelatedCteJoin<?> join){
179+
return visitQualifiedCteJoin( join );
180+
}
181+
182+
default T visitCorrelatedDerivedJoin(SqmCorrelatedDerivedJoin<?> join){
183+
return visitQualifiedDerivedJoin( join );
184+
}
185+
176186
default T visitCorrelatedCrossJoin(SqmCorrelatedCrossJoin<?> join) {
177187
return visitCrossJoin( join );
178188
}

hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPath.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ public SqmPathSource<T> getModel() {
149149
@Override
150150
public SqmPathSource<T> getResolvedModel() {
151151
final SqmPathSource<T> pathSource = getReferencedPathSource();
152+
152153
if ( pathSource.isGeneric()
153154
&& getLhs().getResolvedModel().getPathType() instanceof SqmManagedDomainType<?> lhsType ) {
154155
final var concreteAttribute = lhsType.findConcreteGenericAttribute( pathSource.getPathName() );
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.query.sqm.tree.domain;
6+
7+
import org.hibernate.query.sqm.SemanticQueryWalker;
8+
import org.hibernate.query.sqm.SqmPathSource;
9+
import org.hibernate.query.sqm.tree.SqmCopyContext;
10+
import org.hibernate.query.sqm.tree.SqmJoinType;
11+
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
12+
import org.hibernate.query.sqm.tree.from.SqmCteJoin;
13+
import org.hibernate.query.sqm.tree.from.SqmRoot;
14+
import org.hibernate.spi.NavigablePath;
15+
16+
/**
17+
* @author Christian Beikov
18+
*/
19+
public class SqmCorrelatedCteJoin<T> extends SqmCteJoin<T> implements SqmCorrelation<T, T>, SqmCorrelatedSingularValuedJoin<T, T> {
20+
21+
private final SqmCorrelatedRootJoin<T> correlatedRootJoin;
22+
private final SqmCteJoin<T> correlationParent;
23+
24+
public SqmCorrelatedCteJoin(SqmCteJoin<T> correlationParent) {
25+
//noinspection unchecked
26+
super(
27+
correlationParent.getCte(),
28+
correlationParent.getExplicitAlias(),
29+
correlationParent.getSqmJoinType(),
30+
(SqmRoot<T>) correlationParent.getRoot()
31+
);
32+
this.correlatedRootJoin = SqmCorrelatedDerivedRootJoin.create( correlationParent, this );
33+
this.correlationParent = correlationParent;
34+
}
35+
36+
private SqmCorrelatedCteJoin(
37+
NavigablePath navigablePath,
38+
SqmCteStatement<T> cte,
39+
SqmPathSource<T> pathSource,
40+
String alias,
41+
SqmJoinType joinType,
42+
SqmRoot<T> sqmRoot,
43+
SqmCorrelatedRootJoin<T> correlatedRootJoin,
44+
SqmCteJoin<T> correlationParent) {
45+
super( navigablePath, cte, pathSource, alias, joinType, sqmRoot );
46+
this.correlatedRootJoin = correlatedRootJoin;
47+
this.correlationParent = correlationParent;
48+
}
49+
50+
@Override
51+
public SqmCorrelatedCteJoin<T> copy(SqmCopyContext context) {
52+
final SqmCorrelatedCteJoin<T> existing = context.getCopy( this );
53+
if ( existing != null ) {
54+
return existing;
55+
}
56+
final SqmCorrelatedCteJoin<T> path = context.registerCopy(
57+
this,
58+
new SqmCorrelatedCteJoin<>(
59+
getNavigablePath(),
60+
getCte().copy( context ),
61+
getReferencedPathSource(),
62+
getExplicitAlias(),
63+
getSqmJoinType(),
64+
(SqmRoot<T>) findRoot().copy( context ),
65+
correlatedRootJoin.copy( context ),
66+
correlationParent.copy( context )
67+
)
68+
);
69+
copyTo( path, context );
70+
return path;
71+
}
72+
73+
@Override
74+
public SqmCteJoin<T> getCorrelationParent() {
75+
return correlationParent;
76+
}
77+
78+
@Override
79+
public SqmPath<T> getWrappedPath() {
80+
return correlationParent;
81+
}
82+
83+
@Override
84+
public boolean isCorrelated() {
85+
return true;
86+
}
87+
88+
@Override
89+
public SqmRoot<T> getCorrelatedRoot() {
90+
return correlatedRootJoin;
91+
}
92+
93+
@Override
94+
public <X> X accept(SemanticQueryWalker<X> walker) {
95+
return walker.visitCorrelatedCteJoin( this );
96+
}
97+
98+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.query.sqm.tree.domain;
6+
7+
import org.hibernate.query.sqm.SemanticQueryWalker;
8+
import org.hibernate.query.sqm.SqmPathSource;
9+
import org.hibernate.query.sqm.tree.SqmCopyContext;
10+
import org.hibernate.query.sqm.tree.SqmJoinType;
11+
import org.hibernate.query.sqm.tree.from.SqmDerivedJoin;
12+
import org.hibernate.query.sqm.tree.from.SqmRoot;
13+
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
14+
import org.hibernate.spi.NavigablePath;
15+
16+
/**
17+
* @author Christian Beikov
18+
*/
19+
public class SqmCorrelatedDerivedJoin<T> extends SqmDerivedJoin<T> implements SqmCorrelation<T, T>, SqmCorrelatedSingularValuedJoin<T, T> {
20+
21+
private final SqmCorrelatedRootJoin<T> correlatedRootJoin;
22+
private final SqmDerivedJoin<T> correlationParent;
23+
24+
public SqmCorrelatedDerivedJoin(SqmDerivedJoin<T> correlationParent) {
25+
//noinspection unchecked
26+
super(
27+
correlationParent.getNavigablePath(),
28+
correlationParent.getQueryPart(),
29+
correlationParent.isLateral(),
30+
correlationParent.getReferencedPathSource(),
31+
correlationParent.getExplicitAlias(),
32+
correlationParent.getSqmJoinType(),
33+
(SqmRoot<T>) correlationParent.getRoot()
34+
);
35+
this.correlatedRootJoin = SqmCorrelatedDerivedRootJoin.create( correlationParent, this );
36+
this.correlationParent = correlationParent;
37+
}
38+
39+
private SqmCorrelatedDerivedJoin(
40+
NavigablePath navigablePath,
41+
SqmSubQuery<T> subQuery,
42+
boolean lateral,
43+
SqmPathSource<T> pathSource,
44+
String alias,
45+
SqmJoinType joinType,
46+
SqmRoot<T> sqmRoot,
47+
SqmCorrelatedRootJoin<T> correlatedRootJoin,
48+
SqmDerivedJoin<T> correlationParent) {
49+
super( navigablePath, subQuery, lateral, pathSource, alias, joinType, sqmRoot );
50+
this.correlatedRootJoin = correlatedRootJoin;
51+
this.correlationParent = correlationParent;
52+
}
53+
54+
@Override
55+
public SqmCorrelatedDerivedJoin<T> copy(SqmCopyContext context) {
56+
final SqmCorrelatedDerivedJoin<T> existing = context.getCopy( this );
57+
if ( existing != null ) {
58+
return existing;
59+
}
60+
final SqmCorrelatedDerivedJoin<T> path = context.registerCopy(
61+
this,
62+
new SqmCorrelatedDerivedJoin<>(
63+
getNavigablePath(),
64+
getQueryPart(),
65+
isLateral(),
66+
getReferencedPathSource(),
67+
getExplicitAlias(),
68+
getSqmJoinType(),
69+
(SqmRoot<T>) findRoot().copy( context ),
70+
correlatedRootJoin.copy( context ),
71+
correlationParent.copy( context )
72+
)
73+
);
74+
copyTo( path, context );
75+
return path;
76+
}
77+
78+
@Override
79+
public SqmDerivedJoin<T> getCorrelationParent() {
80+
return correlationParent;
81+
}
82+
83+
@Override
84+
public SqmPath<T> getWrappedPath() {
85+
return correlationParent;
86+
}
87+
88+
@Override
89+
public boolean isCorrelated() {
90+
return true;
91+
}
92+
93+
@Override
94+
public SqmRoot<T> getCorrelatedRoot() {
95+
return correlatedRootJoin;
96+
}
97+
98+
@Override
99+
public <X> X accept(SemanticQueryWalker<X> walker) {
100+
return walker.visitCorrelatedDerivedJoin( this );
101+
}
102+
103+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.query.sqm.tree.domain;
6+
7+
import org.hibernate.query.sqm.SqmPathSource;
8+
import org.hibernate.query.sqm.tree.SqmCopyContext;
9+
import org.hibernate.query.sqm.tree.from.SqmRoot;
10+
11+
/**
12+
* @author Steve Ebersole
13+
*/
14+
public class SqmCorrelatedDerivedRoot<T> extends SqmCorrelatedRoot<T> implements SqmPathWrapper<T, T>, SqmCorrelation<T, T> {
15+
16+
public SqmCorrelatedDerivedRoot(SqmDerivedRoot<T> correlationParent) {
17+
this( (SqmRoot<T>) correlationParent );
18+
}
19+
20+
public SqmCorrelatedDerivedRoot(SqmCteRoot<T> correlationParent) {
21+
this( (SqmRoot<T>) correlationParent );
22+
}
23+
24+
private SqmCorrelatedDerivedRoot(SqmRoot<T> correlationParent) {
25+
super(
26+
correlationParent.getNavigablePath(),
27+
correlationParent.getReferencedPathSource(),
28+
correlationParent.nodeBuilder(),
29+
correlationParent
30+
);
31+
}
32+
33+
@Override
34+
public SqmCorrelatedDerivedRoot<T> copy(SqmCopyContext context) {
35+
final SqmCorrelatedDerivedRoot<T> existing = context.getCopy( this );
36+
if ( existing != null ) {
37+
return existing;
38+
}
39+
final SqmCorrelatedDerivedRoot<T> path = context.registerCopy(
40+
this,
41+
new SqmCorrelatedDerivedRoot<>( getCorrelationParent().copy( context ) )
42+
);
43+
copyTo( path, context );
44+
return path;
45+
}
46+
47+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
48+
// JPA
49+
50+
@Override
51+
public SqmEntityDomainType<T> getModel() {
52+
// Or should we throw an exception instead?
53+
return null;
54+
}
55+
56+
@Override
57+
public String getEntityName() {
58+
return null;
59+
}
60+
61+
@Override
62+
public SqmPathSource<T> getResolvedModel() {
63+
return getReferencedPathSource();
64+
}
65+
66+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.query.sqm.tree.domain;
6+
7+
import org.hibernate.query.sqm.NodeBuilder;
8+
import org.hibernate.query.sqm.SqmPathSource;
9+
import org.hibernate.query.sqm.tree.SqmCopyContext;
10+
import org.hibernate.query.sqm.tree.from.SqmFrom;
11+
import org.hibernate.query.sqm.tree.from.SqmJoin;
12+
import org.hibernate.spi.NavigablePath;
13+
14+
/**
15+
* @author Steve Ebersole
16+
*/
17+
public class SqmCorrelatedDerivedRootJoin<T> extends SqmCorrelatedRootJoin<T> {
18+
19+
public SqmCorrelatedDerivedRootJoin(
20+
NavigablePath navigablePath,
21+
SqmPathSource<T> referencedNavigable,
22+
NodeBuilder nodeBuilder) {
23+
super( navigablePath, referencedNavigable, nodeBuilder );
24+
}
25+
26+
@Override
27+
public SqmCorrelatedDerivedRootJoin<T> copy(SqmCopyContext context) {
28+
final SqmCorrelatedDerivedRootJoin<T> existing = context.getCopy( this );
29+
if ( existing != null ) {
30+
return existing;
31+
}
32+
final SqmCorrelatedDerivedRootJoin<T> path = context.registerCopy(
33+
this,
34+
new SqmCorrelatedDerivedRootJoin<>(
35+
getNavigablePath(),
36+
getReferencedPathSource(),
37+
nodeBuilder()
38+
)
39+
);
40+
copyTo( path, context );
41+
return path;
42+
}
43+
44+
@SuppressWarnings("unchecked")
45+
public static <X, J extends SqmJoin<X, ?>> SqmCorrelatedDerivedRootJoin<X> create(J correlationParent, J correlatedJoin) {
46+
final SqmFrom<?, X> parentPath = (SqmFrom<?, X>) correlationParent.getParentPath();
47+
final SqmCorrelatedDerivedRootJoin<X> rootJoin;
48+
if ( parentPath == null ) {
49+
rootJoin = new SqmCorrelatedDerivedRootJoin<>(
50+
correlationParent.getNavigablePath(),
51+
(SqmPathSource<X>) correlationParent.getReferencedPathSource(),
52+
correlationParent.nodeBuilder()
53+
);
54+
}
55+
else {
56+
rootJoin = new SqmCorrelatedDerivedRootJoin<>(
57+
parentPath.getNavigablePath(),
58+
parentPath.getReferencedPathSource(),
59+
correlationParent.nodeBuilder()
60+
);
61+
}
62+
rootJoin.addSqmJoin( correlatedJoin );
63+
return rootJoin;
64+
}
65+
66+
@Override
67+
public boolean containsOnlyInnerJoins() {
68+
// The derived join is just referenced, no need to create any table groups
69+
return true;
70+
}
71+
72+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
73+
// JPA
74+
75+
@Override
76+
public SqmEntityDomainType<T> getModel() {
77+
// Or should we throw an exception instead?
78+
return null;
79+
}
80+
81+
@Override
82+
public String getEntityName() {
83+
return null;
84+
}
85+
86+
@Override
87+
public SqmPathSource<T> getResolvedModel() {
88+
return getReferencedPathSource();
89+
}
90+
}

0 commit comments

Comments
 (0)