HHH-17231 Reintroduce support for entity path expansion in subqueries

This commit is contained in:
Marco Belladelli 2023-09-22 11:16:48 +02:00
parent 8957a7ccf5
commit d59ecb633b
2 changed files with 38 additions and 25 deletions

View File

@ -261,9 +261,9 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
SqmToSqlAstConverter sqlAstCreationState) {
final boolean expandToAllColumns;
final Clause currentClause = sqlAstCreationState.getCurrentClauseStack().getCurrent();
if ( sqlAstCreationState.getCurrentProcessingState().isTopLevel() &&
( currentClause == Clause.GROUP || currentClause == Clause.ORDER ) ) {
final SqmQuerySpec<?> querySpec = (SqmQuerySpec<?>) sqlAstCreationState.getCurrentSqmQueryPart();
if ( currentClause == Clause.GROUP || currentClause == Clause.ORDER ) {
assert sqlAstCreationState.getCurrentSqmQueryPart().isSimpleQueryPart();
final SqmQuerySpec<?> querySpec = sqlAstCreationState.getCurrentSqmQueryPart().getFirstQuerySpec();
if ( currentClause == Clause.ORDER && !querySpec.groupByClauseContains( navigablePath ) ) {
// We must ensure that the order by expression be expanded but only if the group by
// contained the same expression, and that was expanded as well
@ -272,7 +272,12 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
else {
// When the table group is selected and the navigablePath is selected we need to expand
// to all columns, as we must make sure we include all columns present in the select clause
expandToAllColumns = isSelected( tableGroup, navigablePath, querySpec );
expandToAllColumns = isSelected(
tableGroup,
navigablePath,
querySpec,
sqlAstCreationState.getCurrentProcessingState().isTopLevel()
);
}
}
else {
@ -351,38 +356,43 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
);
}
private static boolean isSelected(TableGroup tableGroup, NavigablePath path, SqmQuerySpec<?> sqmQuerySpec) {
// If the table group is selected (initialized), check if the entity valued
// navigable path or any child path appears in the select clause
return tableGroup.isInitialized() && selectClauseContains( path, sqmQuerySpec );
}
private static boolean selectClauseContains(NavigablePath path, SqmQuerySpec<?> sqmQuerySpec) {
final List<SqmSelection<?>> selections = sqmQuerySpec.getSelectClause() == null
? Collections.emptyList()
: sqmQuerySpec.getSelectClause().getSelections();
for ( SqmSelection<?> selection : selections ) {
if ( selectionContains( selection.getSelectableNode(), path ) ) {
private static boolean isSelected(
TableGroup tableGroup,
NavigablePath path,
SqmQuerySpec<?> sqmQuerySpec,
boolean isTopLevel) {
// If the table group is not initialized, i.e. not selected, no need to check selections
if ( !tableGroup.isInitialized() || sqmQuerySpec.getSelectClause() == null ) {
return false;
}
final NavigablePath tableGroupPath = isTopLevel ? null : tableGroup.getNavigablePath();
for ( SqmSelection<?> selection : sqmQuerySpec.getSelectClause().getSelections() ) {
if ( selectionContains( selection.getSelectableNode(), path, tableGroupPath ) ) {
return true;
}
}
return false;
}
private static boolean selectionContains(Selection<?> selection, NavigablePath path) {
if ( selection instanceof SqmPath && path.isParentOrEqual( ( (SqmPath<?>) selection ).getNavigablePath() ) ) {
return true;
private static boolean selectionContains(Selection<?> selection, NavigablePath path, NavigablePath tableGroupPath) {
if ( selection instanceof SqmPath<?> ) {
final SqmPath<?> sqmPath = (SqmPath<?>) selection;
// Expansion is needed if the table group is null, i.e. we're in a top level query where EVPs are always
// expanded to all columns, or if the selection is on the same table (lhs) as the group by expression ...
return ( tableGroupPath == null || sqmPath.getLhs().getNavigablePath().equals( tableGroupPath ) )
// ... and if the entity valued path is selected or any of its columns are
&& path.isParentOrEqual( sqmPath.getNavigablePath() );
}
else if ( selection.isCompoundSelection() ) {
for ( Selection<?> compoundSelection : selection.getCompoundSelectionItems() ) {
if ( selectionContains( compoundSelection, path ) ) {
if ( selectionContains( compoundSelection, path, tableGroupPath ) ) {
return true;
}
}
}
else if ( selection instanceof SqmDynamicInstantiation ) {
for ( SqmDynamicInstantiationArgument<?> argument : ( (SqmDynamicInstantiation<?>) selection ).getArguments() ) {
if ( selectionContains( argument.getSelectableNode(), path ) ) {
if ( selectionContains( argument.getSelectableNode(), path, tableGroupPath ) ) {
return true;
}
}

View File

@ -7084,12 +7084,13 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
this.queryPartForRowNumberingClauseDepth = -1;
this.needsSelectAliases = false;
queryPartStack.push( subQuery );
appendSql( "exists (select 1" );
visitFromClause( subQuery.getFromClause() );
appendSql( "exists (" );
if ( !subQuery.getGroupByClauseExpressions().isEmpty()
|| subQuery.getHavingClauseRestrictions() != null ) {
// If we have a group by or having clause, we have to move the tuple comparison emulation to the HAVING clause
// If we have a group by or having clause, we have to move the tuple comparison emulation to the HAVING clause.
// Also, we need to explicitly include the selections to avoid 'invalid HAVING clause' errors
visitSelectClause( subQuery.getSelectClause() );
visitFromClause( subQuery.getFromClause() );
visitWhereClause( subQuery.getWhereClauseRestrictions() );
visitGroupByClause( subQuery, SelectItemReferenceStrategy.EXPRESSION );
@ -7114,6 +7115,8 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
}
else {
// If we have no group by or having clause, we can move the tuple comparison emulation to the WHERE clause
appendSql( "select 1" );
visitFromClause( subQuery.getFromClause() );
appendSql( " where " );
clauseStack.push( Clause.WHERE );
try {