HHH-17898 Throw error if non-lateral from-clause subquery uses outer from node
This commit is contained in:
parent
d6bc041dff
commit
7ecbc07d4d
|
@ -2593,6 +2593,9 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
final TableGroup parentTableGroup = fromClauseIndex.findTableGroup(
|
||||
from.getCorrelationParent().getNavigablePath()
|
||||
);
|
||||
if ( parentTableGroup == null ) {
|
||||
throw new InterpretationException( "Access to from node '" + from.getCorrelationParent() + "' is not possible in from-clause subqueries, unless the 'lateral' keyword is used for the subquery!" );
|
||||
}
|
||||
final SqlAliasBase sqlAliasBase = sqlAliasBaseManager.createSqlAliasBase( parentTableGroup.getGroupAlias() );
|
||||
if ( parentTableGroup instanceof PluralTableGroup ) {
|
||||
final PluralTableGroup pluralTableGroup = (PluralTableGroup) parentTableGroup;
|
||||
|
@ -2744,7 +2747,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
final TableGroup tableGroup;
|
||||
if ( sqmRoot instanceof SqmDerivedRoot<?> ) {
|
||||
final SqmDerivedRoot<?> derivedRoot = (SqmDerivedRoot<?>) sqmRoot;
|
||||
// Temporarily push an empty FromClauseIndex to disallow access to aliases from the top query
|
||||
// Only lateral subqueries are allowed to see the aliases
|
||||
fromClauseIndexStack.push( new FromClauseIndex( null ) );
|
||||
final SelectStatement statement = (SelectStatement) derivedRoot.getQueryPart().accept( this );
|
||||
fromClauseIndexStack.pop();
|
||||
final AnonymousTupleType<?> tupleType = (AnonymousTupleType<?>) sqmRoot.getNodeType();
|
||||
final List<SqlSelection> sqlSelections = statement.getQueryPart().getFirstQuerySpec().getSelectClause().getSqlSelections();
|
||||
final AnonymousTupleTableGroupProducer tableGroupProducer = tupleType.resolveTableGroupProducer(
|
||||
|
@ -3485,7 +3492,15 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
}
|
||||
|
||||
private TableGroup consumeDerivedJoin(SqmDerivedJoin<?> sqmJoin, TableGroup parentTableGroup, boolean transitive) {
|
||||
if ( !sqmJoin.isLateral() ) {
|
||||
// Temporarily push an empty FromClauseIndex to disallow access to aliases from the top query
|
||||
// Only lateral subqueries are allowed to see the aliases
|
||||
fromClauseIndexStack.push( new FromClauseIndex( null ) );
|
||||
}
|
||||
final SelectStatement statement = (SelectStatement) sqmJoin.getQueryPart().accept( this );
|
||||
if ( !sqmJoin.isLateral() ) {
|
||||
fromClauseIndexStack.pop();
|
||||
}
|
||||
final AnonymousTupleType<?> tupleType = (AnonymousTupleType<?>) sqmJoin.getNodeType();
|
||||
final List<SqlSelection> sqlSelections = statement.getQueryPart().getFirstQuerySpec().getSelectClause().getSqlSelections();
|
||||
final AnonymousTupleTableGroupProducer tableGroupProducer = tupleType.resolveTableGroupProducer(
|
||||
|
|
|
@ -17,9 +17,11 @@ import org.hibernate.query.criteria.JpaDerivedRoot;
|
|||
import org.hibernate.query.criteria.JpaRoot;
|
||||
import org.hibernate.query.criteria.JpaSubQuery;
|
||||
import org.hibernate.query.spi.QueryImplementor;
|
||||
import org.hibernate.query.sqm.InterpretationException;
|
||||
import org.hibernate.query.sqm.tree.SqmJoinType;
|
||||
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
|
||||
|
||||
import org.hibernate.testing.orm.junit.Jira;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||
import org.hibernate.testing.orm.domain.StandardDomainModel;
|
||||
import org.hibernate.testing.orm.domain.contacts.Address;
|
||||
|
@ -35,7 +37,9 @@ import org.junit.jupiter.api.Test;
|
|||
import jakarta.persistence.Tuple;
|
||||
import jakarta.persistence.criteria.Join;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import org.assertj.core.api.Assertions;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
|
@ -81,6 +85,51 @@ public class SubQueryInFromTests {
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Jira("https://hibernate.atlassian.net/browse/HHH-17898")
|
||||
public void testJoinSubqueryUsingInvalidAlias1(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
try {
|
||||
session.createQuery(
|
||||
"select c.name, a.name from Contact c " +
|
||||
"join (" +
|
||||
"select c2.name as name " +
|
||||
"from Contact c2 " +
|
||||
"where c2 = c" +
|
||||
") a",
|
||||
Tuple.class
|
||||
).getResultList();
|
||||
}
|
||||
catch (InterpretationException ex) {
|
||||
assertThat( ex.getMessage() ).contains( "lateral" );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Jira("https://hibernate.atlassian.net/browse/HHH-17898")
|
||||
public void testJoinSubqueryUsingInvalidAlias2(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
try {
|
||||
session.createQuery(
|
||||
"select c.name, a.address from Contact c " +
|
||||
"join (" +
|
||||
"select address.line1 as address " +
|
||||
"from c.addresses address " +
|
||||
") a",
|
||||
Tuple.class
|
||||
).getResultList();
|
||||
}
|
||||
catch (InterpretationException ex) {
|
||||
assertThat( ex.getMessage() ).contains( "lateral" );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsSubqueryInOnClause.class)
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsOrderByInCorrelatedSubquery.class)
|
||||
|
|
Loading…
Reference in New Issue