Skip to content

Commit a5ed73a

Browse files
cigalymbellade
authored andcommitted
HHH-19396 Parameter deduplicateSelectionItems must be set only for temporary tables and subqueries
Selection items representing same column in (sub)query will be represented with single instance, this will hide real alias
1 parent 80701e9 commit a5ed73a

File tree

3 files changed

+49
-41
lines changed

3 files changed

+49
-41
lines changed

hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1813,11 +1813,14 @@ public CteContainer visitCteContainer(SqmCteContainer consumer) {
18131813
final Collection<SqmCteStatement<?>> sqmCteStatements = consumer.getCteStatements();
18141814
cteContainer = new CteContainerImpl( cteContainer );
18151815
if ( !sqmCteStatements.isEmpty() ) {
1816+
final boolean originalDeduplicateSelectionItems = deduplicateSelectionItems;
1817+
deduplicateSelectionItems = false;
18161818
currentClauseStack.push( Clause.WITH );
18171819
for ( SqmCteStatement<?> sqmCteStatement : sqmCteStatements ) {
18181820
visitCteStatement( sqmCteStatement );
18191821
}
18201822
currentClauseStack.pop();
1823+
deduplicateSelectionItems = originalDeduplicateSelectionItems;
18211824
// Avoid leaking the processing state from CTEs to upper levels
18221825
lastPoppedFromClauseIndex = null;
18231826
lastPoppedProcessingState = null;

hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteTable.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import org.hibernate.query.sqm.tuple.internal.CteTupleTableGroupProducer;
1818
import org.hibernate.query.sqm.SqmPathSource;
1919
import org.hibernate.query.sqm.tree.select.SqmSelectQuery;
20-
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
2120
import org.hibernate.sql.ast.spi.FromClauseAccess;
2221
import org.hibernate.sql.ast.spi.SqlSelection;
2322
import org.hibernate.type.BasicType;
@@ -34,8 +33,8 @@ public class SqmCteTable<T> extends AnonymousTupleType<T> implements JpaCteCrite
3433
private SqmCteTable(
3534
String name,
3635
SqmCteStatement<T> cteStatement,
37-
SqmSelectableNode<?>[] sqmSelectableNodes) {
38-
super( sqmSelectableNodes );
36+
SqmSelectQuery<T> selectStatement) {
37+
super(selectStatement);
3938
this.name = name;
4039
this.cteStatement = cteStatement;
4140
final List<SqmCteTableColumn> columns = new ArrayList<>( componentCount() );
@@ -49,12 +48,7 @@ public static <X> SqmCteTable<X> createStatementTable(
4948
String name,
5049
SqmCteStatement<X> cteStatement,
5150
SqmSelectQuery<X> selectStatement) {
52-
final SqmSelectableNode<?>[] sqmSelectableNodes = selectStatement.getQueryPart()
53-
.getFirstQuerySpec()
54-
.getSelectClause()
55-
.getSelectionItems()
56-
.toArray( SqmSelectableNode[]::new );
57-
return new SqmCteTable<>( name, cteStatement, sqmSelectableNodes );
51+
return new SqmCteTable<>( name, cteStatement, selectStatement );
5852
}
5953

6054
@Override

hibernate-core/src/main/java/org/hibernate/query/sqm/tuple/internal/AnonymousTupleType.java

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,14 @@
2222
import org.hibernate.query.sqm.SqmPathSource;
2323
import org.hibernate.query.sqm.tree.domain.SqmDomainType;
2424
import org.hibernate.query.sqm.tree.domain.SqmPluralPersistentAttribute;
25+
import org.hibernate.query.sqm.tree.select.SqmSelectQuery;
26+
import org.hibernate.query.sqm.tree.select.SqmSelection;
2527
import org.hibernate.query.sqm.tuple.TupleType;
2628
import org.hibernate.query.SemanticException;
2729
import org.hibernate.query.sqm.SqmExpressible;
2830
import org.hibernate.query.sqm.tree.domain.SqmPath;
2931
import org.hibernate.query.sqm.tree.select.SqmSelectClause;
3032
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
31-
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
3233
import org.hibernate.spi.NavigablePath;
3334
import org.hibernate.sql.ast.spi.FromClauseAccess;
3435
import org.hibernate.sql.ast.spi.SqlSelection;
@@ -55,26 +56,47 @@ public class AnonymousTupleType<T>
5556
private final String[] componentNames;
5657
private final Map<String, Integer> componentIndexMap;
5758

58-
public AnonymousTupleType(SqmSubQuery<T> subQuery) {
59-
this( extractSqmExpressibles( subQuery ) );
60-
}
59+
public AnonymousTupleType(SqmSelectQuery<T> selectQuery) {
60+
final SqmSelectClause selectClause = selectQuery.getQueryPart()
61+
.getFirstQuerySpec()
62+
.getSelectClause();
6163

62-
public AnonymousTupleType(SqmSelectableNode<?>[] components) {
63-
expressibles = new SqmBindableType<?>[components.length];
64-
componentSourcePaths = new NavigablePath[components.length];
65-
for ( int i = 0; i < components.length; i++ ) {
66-
expressibles[i] = components[i].getNodeType();
67-
if ( components[i] instanceof SqmPath<?> path ) {
68-
componentSourcePaths[i] = path.getNavigablePath();
64+
if ( selectClause == null || selectClause.getSelections().isEmpty() ) {
65+
throw new IllegalArgumentException( "selectQuery has no selection items" );
66+
}
67+
// todo: right now, we "snapshot" the state of the selectQuery when creating this type, but maybe we shouldn't?
68+
// i.e. what if the selectQuery changes later on? Or should we somehow mark the selectQuery to signal,
69+
// that changes to the select clause are invalid after a certain point?
70+
71+
final List<SqmSelection<?>> selections = selectClause.getSelections();
72+
final List<SqmSelectableNode<?>> selectableNodes = new ArrayList<>();
73+
final List<String> aliases = new ArrayList<>();
74+
for ( SqmSelection<?> selection : selections ) {
75+
final boolean compound = selection.getSelectableNode().isCompoundSelection();
76+
selection.getSelectableNode().visitSubSelectableNodes( node -> {
77+
selectableNodes.add( node );
78+
if ( compound ) {
79+
aliases.add( node.getAlias() );
80+
}
81+
} );
82+
if ( !compound ) {
83+
// for compound selections we use the sub-selectable nodes aliases
84+
aliases.add( selection.getAlias() );
6985
}
7086
}
71-
componentNames = new String[components.length];
87+
88+
expressibles = new SqmBindableType<?>[selectableNodes.size()];
89+
componentSourcePaths = new NavigablePath[selectableNodes.size()];
90+
componentNames = new String[selectableNodes.size()];
7291
//noinspection unchecked
73-
javaTypeDescriptor = (JavaType<T>) new ObjectArrayJavaType( getTypeDescriptors( components ) );
74-
componentIndexMap = linkedMapOfSize( components.length );
75-
for ( int i = 0; i < components.length; i++ ) {
76-
final SqmSelectableNode<?> component = components[i];
77-
final String alias = component.getAlias();
92+
javaTypeDescriptor = (JavaType<T>) new ObjectArrayJavaType( getTypeDescriptors( selectableNodes ) );
93+
componentIndexMap = linkedMapOfSize( selectableNodes.size() );
94+
for ( int i = 0; i < selectableNodes.size(); i++ ) {
95+
expressibles[i] = selectableNodes.get( i ).getNodeType();
96+
if ( selectableNodes.get( i ) instanceof SqmPath<?> path ) {
97+
componentSourcePaths[i] = path.getNavigablePath();
98+
}
99+
String alias = aliases.get( i );
78100
if ( alias == null ) {
79101
throw new SemanticException( "Select item at position " + (i+1) + " in select list has no alias"
80102
+ " (aliases are required in CTEs and in subqueries occurring in from clause)" );
@@ -110,21 +132,10 @@ public String getTypeName() {
110132
return SqmDomainType.super.getTypeName();
111133
}
112134

113-
private static SqmSelectableNode<?>[] extractSqmExpressibles(SqmSubQuery<?> subQuery) {
114-
final SqmSelectClause selectClause = subQuery.getQuerySpec().getSelectClause();
115-
if ( selectClause == null || selectClause.getSelectionItems().isEmpty() ) {
116-
throw new IllegalArgumentException( "subquery has no selection items" );
117-
}
118-
// todo: right now, we "snapshot" the state of the subquery when creating this type, but maybe we shouldn't?
119-
// i.e. what if the subquery changes later on? Or should we somehow mark the subquery to signal,
120-
// that changes to the select clause are invalid after a certain point?
121-
return selectClause.getSelectionItems().toArray( SqmSelectableNode[]::new );
122-
}
123-
124-
private static JavaType<?>[] getTypeDescriptors(SqmSelectableNode<?>[] components) {
125-
final JavaType<?>[] typeDescriptors = new JavaType<?>[components.length];
126-
for ( int i = 0; i < components.length; i++ ) {
127-
typeDescriptors[i] = components[i].getExpressible().getExpressibleJavaType();
135+
private static JavaType<?>[] getTypeDescriptors(List<SqmSelectableNode<?>> components) {
136+
final JavaType<?>[] typeDescriptors = new JavaType<?>[components.size()];
137+
for ( int i = 0; i < components.size(); i++ ) {
138+
typeDescriptors[i] = components.get( i ).getExpressible().getExpressibleJavaType();
128139
}
129140
return typeDescriptors;
130141
}

0 commit comments

Comments
 (0)