Skip to content

Commit 2f1b47d

Browse files
committed
HHH-19745 Use identity sensitive collections/operations where necessary after introducing equals implementation for SqmPath
1 parent 279a206 commit 2f1b47d

File tree

4 files changed

+80
-6
lines changed

4 files changed

+80
-6
lines changed

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
package org.hibernate.query.hql.internal;
66

7+
import java.util.List;
78
import java.util.Locale;
89

910
import org.hibernate.query.SemanticException;
@@ -56,9 +57,9 @@ protected void validateAsRoot(SqmFrom<?, ?> pathRoot) {
5657
final SqmFromClause fromClause = querySpec.getFromClause();
5758
// If the current processing query contains the root of the current join,
5859
// then the root of the processing path must be a root of one of the parent queries
59-
if ( fromClause != null && fromClause.getRoots().contains( joinRoot ) ) {
60+
if ( fromClause != null && contains( fromClause.getRoots(), joinRoot ) ) {
6061
// It is allowed to use correlations from the same query
61-
if ( !( root instanceof SqmCorrelation<?, ?> ) || !fromClause.getRoots().contains( root ) ) {
62+
if ( !( root instanceof SqmCorrelation<?, ?> ) || !contains( fromClause.getRoots(), root ) ) {
6263
validateAsRootOnParentQueryClosure( pathRoot, root,
6364
processingState.getParentProcessingState() );
6465
}
@@ -97,7 +98,7 @@ private void validateAsRootOnParentQueryClosure(
9798
// If we are in a subquery, the "foreign" from element could be one of the subquery roots,
9899
// which is totally fine. The aim of this check is to prevent uses of different "spaces"
99100
// i.e. `from A a, B b join b.id = a.id` would be illegal
100-
if ( fromClause != null && fromClause.getRoots().contains( root ) ) {
101+
if ( fromClause != null && contains( fromClause.getRoots(), root ) ) {
101102
super.validateAsRoot( pathRoot );
102103
return;
103104
}
@@ -113,6 +114,15 @@ private void validateAsRootOnParentQueryClosure(
113114
)
114115
);
115116
}
117+
118+
private boolean contains(List<SqmRoot<?>> roots, SqmRoot<?> root) {
119+
for ( SqmRoot<?> sqmRoot : roots ) {
120+
if ( sqmRoot == root ) {
121+
return true;
122+
}
123+
}
124+
return false;
125+
}
116126
};
117127
}
118128
}

hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQuerySpec.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.util.ArrayList;
88
import java.util.Collections;
99
import java.util.HashSet;
10+
import java.util.IdentityHashMap;
1011
import java.util.List;
1112
import java.util.Objects;
1213
import java.util.Set;
@@ -516,7 +517,7 @@ public void validateFetchOwners() {
516517
}
517518
}
518519
else {
519-
selectedFromSet = new HashSet<>( selectClause.getSelections().size() );
520+
selectedFromSet = Collections.newSetFromMap( new IdentityHashMap<>( selectClause.getSelections().size() ) );
520521
for ( SqmSelection<?> selection : selectClause.getSelections() ) {
521522
collectSelectedFromSet( selectedFromSet, selection.getSelectableNode() );
522523
}

hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSubQuery.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
import java.math.BigDecimal;
88
import java.math.BigInteger;
99
import java.util.Collection;
10-
import java.util.HashSet;
10+
import java.util.Collections;
11+
import java.util.IdentityHashMap;
1112
import java.util.List;
1213
import java.util.Map;
1314
import java.util.Objects;
@@ -580,7 +581,7 @@ public <X> JpaEntityJoin<T, X> correlate(JpaEntityJoin<T, X> parentEntityJoin) {
580581

581582
@Override
582583
public Set<Join<?, ?>> getCorrelatedJoins() {
583-
final Set<Join<?, ?>> correlatedJoins = new HashSet<>();
584+
final Set<Join<?, ?>> correlatedJoins = Collections.newSetFromMap( new IdentityHashMap<>() );
584585
final SqmFromClause fromClause = getQuerySpec().getFromClause();
585586
if ( fromClause != null ) {
586587
for ( SqmRoot<?> root : fromClause.getRoots() ) {
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.query;
6+
7+
import jakarta.persistence.Entity;
8+
import jakarta.persistence.GeneratedValue;
9+
import jakarta.persistence.Id;
10+
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
11+
import org.hibernate.testing.orm.junit.DomainModel;
12+
import org.hibernate.testing.orm.junit.Jira;
13+
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
14+
import org.hibernate.testing.orm.junit.SessionFactory;
15+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
16+
import org.junit.jupiter.api.Test;
17+
18+
19+
@DomainModel(
20+
annotatedClasses = {
21+
SubQueryShadowingTest.TestEntity.class,
22+
}
23+
)
24+
@SessionFactory
25+
public class SubQueryShadowingTest {
26+
27+
@Test
28+
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsOffsetInSubquery.class, comment = "The check is for both, limit and offset in subqueries")
29+
@Jira("https://hibernate.atlassian.net/browse/HHH-19745")
30+
public void testSelectCase(SessionFactoryScope scope) {
31+
scope.inTransaction( session -> {
32+
session.createQuery(
33+
"""
34+
from TestEntity t
35+
left join TestEntity t2 on exists (
36+
select 1
37+
from TestEntity t
38+
order by t.id
39+
limit 1
40+
)
41+
""", TestEntity.class )
42+
.list();
43+
} );
44+
}
45+
46+
@Entity(name = "TestEntity")
47+
public static class TestEntity {
48+
49+
@Id
50+
@GeneratedValue
51+
private Long id;
52+
53+
private String name;
54+
55+
public TestEntity() {
56+
}
57+
58+
public TestEntity(String name) {
59+
this.name = name;
60+
}
61+
}
62+
}

0 commit comments

Comments
 (0)