Skip to content

Commit d79c739

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

14 files changed

+526
-13
lines changed

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,18 @@
1717
import org.hibernate.metamodel.model.domain.BasicDomainType;
1818
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
1919
import org.hibernate.query.SemanticException;
20+
import org.hibernate.query.criteria.JpaJoinedFrom;
2021
import org.hibernate.query.hql.HqlLogging;
2122
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
2223
import org.hibernate.query.hql.spi.SqmPathRegistry;
2324
import org.hibernate.query.sqm.AliasCollisionException;
2425
import org.hibernate.query.sqm.ParsingException;
2526
import org.hibernate.query.sqm.SqmPathSource;
2627
import org.hibernate.query.sqm.SqmTreeCreationLogger;
28+
import org.hibernate.query.sqm.tree.domain.AbstractSqmFrom;
29+
import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
2730
import org.hibernate.query.sqm.tree.domain.SqmPath;
28-
import org.hibernate.query.sqm.tree.from.SqmCrossJoin;
29-
import org.hibernate.query.sqm.tree.from.SqmEntityJoin;
30-
import org.hibernate.query.sqm.tree.from.SqmFrom;
31-
import org.hibernate.query.sqm.tree.from.SqmJoin;
32-
import org.hibernate.query.sqm.tree.from.SqmRoot;
31+
import org.hibernate.query.sqm.tree.from.*;
3332
import org.hibernate.query.sqm.tree.select.SqmAliasedNode;
3433
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
3534
import org.hibernate.spi.NavigablePath;
@@ -244,6 +243,12 @@ else if ( parentRegistered instanceof SqmCrossJoin<?> ) {
244243
else if ( parentRegistered instanceof SqmEntityJoin<?> ) {
245244
correlated = selectQuery.correlate( (SqmEntityJoin<?>) parentRegistered );
246245
}
246+
else if ( parentRegistered instanceof AbstractSqmFrom<?, ?>) {
247+
final SqmCorrelation<?, ?> correlation =
248+
((AbstractSqmFrom<?, ?>) parentRegistered).createCorrelation();
249+
selectQuery.getQuerySpec().addRoot( correlation.getCorrelatedRoot() );
250+
correlated = correlation;
251+
}
247252
else {
248253
throw new UnsupportedOperationException( "Can't correlate from node: " + parentRegistered );
249254
}

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;
@@ -170,6 +172,14 @@ public interface SemanticQueryWalker<T> {
170172

171173
T visitQualifiedAttributeJoin(SqmAttributeJoin<?, ?> joinedFromElement);
172174

175+
default T visitCorrelatedCteJoin(SqmCorrelatedCteJoin<?> join){
176+
return visitQualifiedCteJoin( join );
177+
}
178+
179+
default T visitCorrelatedDerivedJoin(SqmCorrelatedDerivedJoin<?> join){
180+
return visitQualifiedDerivedJoin( join );
181+
}
182+
173183
default T visitCorrelatedCrossJoin(SqmCorrelatedCrossJoin<?> join) {
174184
return visitCrossJoin( join );
175185
}

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
@@ -158,6 +158,7 @@ public SqmPathSource<T> getModel() {
158158
public SqmPathSource<?> getResolvedModel() {
159159
final DomainType<?> lhsType;
160160
final SqmPathSource<T> pathSource = getReferencedPathSource();
161+
161162
if ( pathSource.isGeneric() && ( lhsType = getLhs().getResolvedModel().getSqmPathType() ) instanceof ManagedDomainType ) {
162163
final PersistentAttribute<?, ?> concreteAttribute = ( (ManagedDomainType<?>) lhsType ).findConcreteGenericAttribute(
163164
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)