Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
package org.hibernate.query.hql.internal;

import java.util.List;
import java.util.Locale;

import org.hibernate.query.SemanticException;
Expand Down Expand Up @@ -56,9 +57,9 @@ protected void validateAsRoot(SqmFrom<?, ?> pathRoot) {
final SqmFromClause fromClause = querySpec.getFromClause();
// If the current processing query contains the root of the current join,
// then the root of the processing path must be a root of one of the parent queries
if ( fromClause != null && fromClause.getRoots().contains( joinRoot ) ) {
if ( fromClause != null && contains( fromClause.getRoots(), joinRoot ) ) {
// It is allowed to use correlations from the same query
if ( !( root instanceof SqmCorrelation<?, ?> ) || !fromClause.getRoots().contains( root ) ) {
if ( !( root instanceof SqmCorrelation<?, ?> ) || !contains( fromClause.getRoots(), root ) ) {
validateAsRootOnParentQueryClosure( pathRoot, root,
processingState.getParentProcessingState() );
}
Expand Down Expand Up @@ -97,7 +98,7 @@ private void validateAsRootOnParentQueryClosure(
// If we are in a subquery, the "foreign" from element could be one of the subquery roots,
// which is totally fine. The aim of this check is to prevent uses of different "spaces"
// i.e. `from A a, B b join b.id = a.id` would be illegal
if ( fromClause != null && fromClause.getRoots().contains( root ) ) {
if ( fromClause != null && contains( fromClause.getRoots(), root ) ) {
super.validateAsRoot( pathRoot );
return;
}
Expand All @@ -113,6 +114,15 @@ private void validateAsRootOnParentQueryClosure(
)
);
}

private boolean contains(List<SqmRoot<?>> roots, SqmRoot<?> root) {
for ( SqmRoot<?> sqmRoot : roots ) {
if ( sqmRoot == root ) {
return true;
}
}
return false;
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Objects;
import java.util.Set;
Expand Down Expand Up @@ -516,7 +517,7 @@ public void validateFetchOwners() {
}
}
else {
selectedFromSet = new HashSet<>( selectClause.getSelections().size() );
selectedFromSet = Collections.newSetFromMap( new IdentityHashMap<>( selectClause.getSelections().size() ) );
for ( SqmSelection<?> selection : selectClause.getSelections() ) {
collectSelectedFromSet( selectedFromSet, selection.getSelectableNode() );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.HashSet;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand Down Expand Up @@ -580,7 +581,7 @@ public <X> JpaEntityJoin<T, X> correlate(JpaEntityJoin<T, X> parentEntityJoin) {

@Override
public Set<Join<?, ?>> getCorrelatedJoins() {
final Set<Join<?, ?>> correlatedJoins = new HashSet<>();
final Set<Join<?, ?>> correlatedJoins = Collections.newSetFromMap( new IdentityHashMap<>() );
final SqmFromClause fromClause = getQuerySpec().getFromClause();
if ( fromClause != null ) {
for ( SqmRoot<?> root : fromClause.getRoots() ) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.orm.test.query;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.Jira;
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;


@DomainModel(
annotatedClasses = {
SubQueryShadowingTest.TestEntity.class,
}
)
@SessionFactory
public class SubQueryShadowingTest {

@Test
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsOffsetInSubquery.class, comment = "The check is for both, limit and offset in subqueries")
@Jira("https://hibernate.atlassian.net/browse/HHH-19745")
public void testSelectCase(SessionFactoryScope scope) {
scope.inTransaction( session -> {
session.createQuery(
"""
from TestEntity t
left join TestEntity t2 on exists (
select 1
from TestEntity t
order by t.id
limit 1
)
""", TestEntity.class )
.list();
} );
}

@Entity(name = "TestEntity")
public static class TestEntity {

@Id
@GeneratedValue
private Long id;

private String name;

public TestEntity() {
}

public TestEntity(String name) {
this.name = name;
}
}
}
Loading