Skip to content

Commit 7639ae3

Browse files
oscarfanchinbeikov
authored andcommitted
HHH-17522 Test and fix correlation of CTE and derived roots and joins
1 parent 8d7d84f commit 7639ae3

14 files changed

+524
-8
lines changed

hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmPathRegistryImpl.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import org.hibernate.query.sqm.ParsingException;
2424
import org.hibernate.query.sqm.SqmPathSource;
2525
import org.hibernate.query.sqm.SqmTreeCreationLogger;
26+
import org.hibernate.query.sqm.tree.domain.AbstractSqmFrom;
27+
import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
2628
import org.hibernate.query.sqm.tree.domain.SqmPath;
2729
import org.hibernate.query.sqm.tree.from.SqmCrossJoin;
2830
import org.hibernate.query.sqm.tree.from.SqmEntityJoin;
@@ -167,6 +169,12 @@ else if ( parentRegistered instanceof SqmCrossJoin<?> ) {
167169
else if ( parentRegistered instanceof SqmEntityJoin<?> ) {
168170
correlated = selectQuery.correlate( (SqmEntityJoin<?>) parentRegistered );
169171
}
172+
else if ( parentRegistered instanceof AbstractSqmFrom<?, ?>) {
173+
final SqmCorrelation<?, ?> correlation =
174+
((AbstractSqmFrom<?, ?>) parentRegistered).createCorrelation();
175+
selectQuery.getQuerySpec().addRoot( correlation.getCorrelatedRoot() );
176+
correlated = correlation;
177+
}
170178
else {
171179
throw new UnsupportedOperationException( "Can't correlate from node: " + parentRegistered );
172180
}

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
@@ -19,6 +19,8 @@
1919
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
2020
import org.hibernate.query.sqm.tree.domain.SqmCorrelatedBagJoin;
2121
import org.hibernate.query.sqm.tree.domain.SqmCorrelatedCrossJoin;
22+
import org.hibernate.query.sqm.tree.domain.SqmCorrelatedCteJoin;
23+
import org.hibernate.query.sqm.tree.domain.SqmCorrelatedDerivedJoin;
2224
import org.hibernate.query.sqm.tree.domain.SqmCorrelatedEntityJoin;
2325
import org.hibernate.query.sqm.tree.domain.SqmCorrelatedListJoin;
2426
import org.hibernate.query.sqm.tree.domain.SqmCorrelatedMapJoin;
@@ -162,6 +164,14 @@ public interface SemanticQueryWalker<T> {
162164

163165
T visitQualifiedAttributeJoin(SqmAttributeJoin<?, ?> joinedFromElement);
164166

167+
default T visitCorrelatedCteJoin(SqmCorrelatedCteJoin<?> join){
168+
return visitQualifiedCteJoin( join );
169+
}
170+
171+
default T visitCorrelatedDerivedJoin(SqmCorrelatedDerivedJoin<?> join){
172+
return visitQualifiedDerivedJoin( join );
173+
}
174+
165175
default T visitCorrelatedCrossJoin(SqmCorrelatedCrossJoin<?> join) {
166176
return visitCrossJoin( join );
167177
}

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
@@ -161,6 +161,7 @@ public SqmPathSource<T> getModel() {
161161
public SqmPathSource<?> getResolvedModel() {
162162
final DomainType<?> lhsType;
163163
final SqmPathSource<T> pathSource = getReferencedPathSource();
164+
164165
if ( pathSource.isGeneric() && ( lhsType = getLhs().getResolvedModel().getSqmPathType() ) instanceof ManagedDomainType ) {
165166
final PersistentAttribute<?, ?> concreteAttribute = ( (ManagedDomainType<?>) lhsType ).findConcreteGenericAttribute(
166167
pathSource.getPathName()
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
6+
*/
7+
package org.hibernate.query.sqm.tree.domain;
8+
9+
import org.hibernate.query.sqm.SemanticQueryWalker;
10+
import org.hibernate.query.sqm.SqmPathSource;
11+
import org.hibernate.query.sqm.tree.SqmCopyContext;
12+
import org.hibernate.query.sqm.tree.SqmJoinType;
13+
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
14+
import org.hibernate.query.sqm.tree.from.SqmCteJoin;
15+
import org.hibernate.query.sqm.tree.from.SqmRoot;
16+
import org.hibernate.spi.NavigablePath;
17+
18+
/**
19+
* @author Christian Beikov
20+
*/
21+
public class SqmCorrelatedCteJoin<T> extends SqmCteJoin<T> implements SqmCorrelation<T, T> {
22+
23+
private final SqmCorrelatedRootJoin<T> correlatedRootJoin;
24+
private final SqmCteJoin<T> correlationParent;
25+
26+
public SqmCorrelatedCteJoin(SqmCteJoin<T> correlationParent) {
27+
//noinspection unchecked
28+
super(
29+
correlationParent.getCte(),
30+
correlationParent.getExplicitAlias(),
31+
correlationParent.getSqmJoinType(),
32+
(SqmRoot<T>) correlationParent.getRoot()
33+
);
34+
this.correlatedRootJoin = SqmCorrelatedDerivedRootJoin.create( correlationParent, this );
35+
this.correlationParent = correlationParent;
36+
}
37+
38+
private SqmCorrelatedCteJoin(
39+
NavigablePath navigablePath,
40+
SqmCteStatement<T> cte,
41+
SqmPathSource<T> pathSource,
42+
String alias,
43+
SqmJoinType joinType,
44+
SqmRoot<T> sqmRoot,
45+
SqmCorrelatedRootJoin<T> correlatedRootJoin,
46+
SqmCteJoin<T> correlationParent) {
47+
super( navigablePath, cte, pathSource, alias, joinType, sqmRoot );
48+
this.correlatedRootJoin = correlatedRootJoin;
49+
this.correlationParent = correlationParent;
50+
}
51+
52+
@Override
53+
public SqmCorrelatedCteJoin<T> copy(SqmCopyContext context) {
54+
final SqmCorrelatedCteJoin<T> existing = context.getCopy( this );
55+
if ( existing != null ) {
56+
return existing;
57+
}
58+
final SqmCorrelatedCteJoin<T> path = context.registerCopy(
59+
this,
60+
new SqmCorrelatedCteJoin<>(
61+
getNavigablePath(),
62+
getCte().copy( context ),
63+
getReferencedPathSource(),
64+
getExplicitAlias(),
65+
getSqmJoinType(),
66+
(SqmRoot<T>) findRoot().copy( context ),
67+
correlatedRootJoin.copy( context ),
68+
correlationParent.copy( context )
69+
)
70+
);
71+
copyTo( path, context );
72+
return path;
73+
}
74+
75+
@Override
76+
public SqmCteJoin<T> getCorrelationParent() {
77+
return correlationParent;
78+
}
79+
80+
@Override
81+
public SqmPath<T> getWrappedPath() {
82+
return correlationParent;
83+
}
84+
85+
@Override
86+
public boolean isCorrelated() {
87+
return true;
88+
}
89+
90+
@Override
91+
public SqmRoot<T> getCorrelatedRoot() {
92+
return correlatedRootJoin;
93+
}
94+
95+
@Override
96+
public <X> X accept(SemanticQueryWalker<X> walker) {
97+
return walker.visitCorrelatedCteJoin( this );
98+
}
99+
100+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
6+
*/
7+
package org.hibernate.query.sqm.tree.domain;
8+
9+
import org.hibernate.query.sqm.SemanticQueryWalker;
10+
import org.hibernate.query.sqm.SqmPathSource;
11+
import org.hibernate.query.sqm.tree.SqmCopyContext;
12+
import org.hibernate.query.sqm.tree.SqmJoinType;
13+
import org.hibernate.query.sqm.tree.from.SqmDerivedJoin;
14+
import org.hibernate.query.sqm.tree.from.SqmRoot;
15+
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
16+
import org.hibernate.spi.NavigablePath;
17+
18+
/**
19+
* @author Christian Beikov
20+
*/
21+
public class SqmCorrelatedDerivedJoin<T> extends SqmDerivedJoin<T> implements SqmCorrelation<T, T> {
22+
23+
private final SqmCorrelatedRootJoin<T> correlatedRootJoin;
24+
private final SqmDerivedJoin<T> correlationParent;
25+
26+
public SqmCorrelatedDerivedJoin(SqmDerivedJoin<T> correlationParent) {
27+
//noinspection unchecked
28+
super(
29+
correlationParent.getNavigablePath(),
30+
correlationParent.getQueryPart(),
31+
correlationParent.isLateral(),
32+
correlationParent.getReferencedPathSource(),
33+
correlationParent.getExplicitAlias(),
34+
correlationParent.getSqmJoinType(),
35+
(SqmRoot<T>) correlationParent.getRoot()
36+
);
37+
this.correlatedRootJoin = SqmCorrelatedDerivedRootJoin.create( correlationParent, this );
38+
this.correlationParent = correlationParent;
39+
}
40+
41+
private SqmCorrelatedDerivedJoin(
42+
NavigablePath navigablePath,
43+
SqmSubQuery<T> subQuery,
44+
boolean lateral,
45+
SqmPathSource<T> pathSource,
46+
String alias,
47+
SqmJoinType joinType,
48+
SqmRoot<T> sqmRoot,
49+
SqmCorrelatedRootJoin<T> correlatedRootJoin,
50+
SqmDerivedJoin<T> correlationParent) {
51+
super( navigablePath, subQuery, lateral, pathSource, alias, joinType, sqmRoot );
52+
this.correlatedRootJoin = correlatedRootJoin;
53+
this.correlationParent = correlationParent;
54+
}
55+
56+
@Override
57+
public SqmCorrelatedDerivedJoin<T> copy(SqmCopyContext context) {
58+
final SqmCorrelatedDerivedJoin<T> existing = context.getCopy( this );
59+
if ( existing != null ) {
60+
return existing;
61+
}
62+
final SqmCorrelatedDerivedJoin<T> path = context.registerCopy(
63+
this,
64+
new SqmCorrelatedDerivedJoin<>(
65+
getNavigablePath(),
66+
getQueryPart(),
67+
isLateral(),
68+
getReferencedPathSource(),
69+
getExplicitAlias(),
70+
getSqmJoinType(),
71+
(SqmRoot<T>) findRoot().copy( context ),
72+
correlatedRootJoin.copy( context ),
73+
correlationParent.copy( context )
74+
)
75+
);
76+
copyTo( path, context );
77+
return path;
78+
}
79+
80+
@Override
81+
public SqmDerivedJoin<T> getCorrelationParent() {
82+
return correlationParent;
83+
}
84+
85+
@Override
86+
public SqmPath<T> getWrappedPath() {
87+
return correlationParent;
88+
}
89+
90+
@Override
91+
public boolean isCorrelated() {
92+
return true;
93+
}
94+
95+
@Override
96+
public SqmRoot<T> getCorrelatedRoot() {
97+
return correlatedRootJoin;
98+
}
99+
100+
@Override
101+
public <X> X accept(SemanticQueryWalker<X> walker) {
102+
return walker.visitCorrelatedDerivedJoin( this );
103+
}
104+
105+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
6+
*/
7+
package org.hibernate.query.sqm.tree.domain;
8+
9+
import org.hibernate.metamodel.model.domain.EntityDomainType;
10+
import org.hibernate.query.sqm.SqmPathSource;
11+
import org.hibernate.query.sqm.tree.SqmCopyContext;
12+
import org.hibernate.query.sqm.tree.from.SqmRoot;
13+
14+
/**
15+
* @author Steve Ebersole
16+
*/
17+
public class SqmCorrelatedDerivedRoot<T> extends SqmCorrelatedRoot<T> implements SqmPathWrapper<T, T>, SqmCorrelation<T, T> {
18+
19+
public SqmCorrelatedDerivedRoot(SqmDerivedRoot<T> correlationParent) {
20+
this( (SqmRoot<T>) correlationParent );
21+
}
22+
23+
public SqmCorrelatedDerivedRoot(SqmCteRoot<T> correlationParent) {
24+
this( (SqmRoot<T>) correlationParent );
25+
}
26+
27+
private SqmCorrelatedDerivedRoot(SqmRoot<T> correlationParent) {
28+
super(
29+
correlationParent.getNavigablePath(),
30+
correlationParent.getReferencedPathSource(),
31+
correlationParent.nodeBuilder(),
32+
correlationParent
33+
);
34+
}
35+
36+
@Override
37+
public SqmCorrelatedDerivedRoot<T> copy(SqmCopyContext context) {
38+
final SqmCorrelatedDerivedRoot<T> existing = context.getCopy( this );
39+
if ( existing != null ) {
40+
return existing;
41+
}
42+
final SqmCorrelatedDerivedRoot<T> path = context.registerCopy(
43+
this,
44+
new SqmCorrelatedDerivedRoot<>( getCorrelationParent().copy( context ) )
45+
);
46+
copyTo( path, context );
47+
return path;
48+
}
49+
50+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
51+
// JPA
52+
53+
@Override
54+
public EntityDomainType<T> getModel() {
55+
// Or should we throw an exception instead?
56+
return null;
57+
}
58+
59+
@Override
60+
public String getEntityName() {
61+
return null;
62+
}
63+
64+
@Override
65+
public SqmPathSource<T> getResolvedModel() {
66+
return getReferencedPathSource();
67+
}
68+
69+
}

0 commit comments

Comments
 (0)