Skip to content

Commit c1d91ce

Browse files
committed
HHH-19396 Refactoring SqmCteTable and AnonymousTupleType constructors
Temporary deduplication disabling moved from org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.buildCacheableSqmInterpretation into org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitCteContainer
1 parent 38b7ede commit c1d91ce

File tree

4 files changed

+44
-52
lines changed

4 files changed

+44
-52
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ private static CacheableSqmInterpretation buildCacheableSqmInterpretation(
491491
executionContext.getQueryParameterBindings(),
492492
executionContext.getSession().getLoadQueryInfluencers(),
493493
sessionFactory.getSqlTranslationEngine(),
494-
sqm.getCteStatements().isEmpty()
494+
true
495495
)
496496
.translate();
497497

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: 4 additions & 11 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,14 +33,13 @@ public class SqmCteTable<T> extends AnonymousTupleType<T> implements JpaCteCrite
3433
private SqmCteTable(
3534
String name,
3635
SqmCteStatement<T> cteStatement,
37-
SqmSelectableNode<?>[] sqmSelectableNodes,
38-
List<String> aliases) {
39-
super( sqmSelectableNodes, aliases );
36+
SqmSelectQuery<T> selectStatement) {
37+
super(selectStatement);
4038
this.name = name;
4139
this.cteStatement = cteStatement;
4240
final List<SqmCteTableColumn> columns = new ArrayList<>( componentCount() );
4341
for ( int i = 0; i < componentCount(); i++ ) {
44-
columns.add( new SqmCteTableColumn( this, aliases.get(i), get(i) ) );
42+
columns.add( new SqmCteTableColumn( this, getComponentName(i), get(i) ) );
4543
}
4644
this.columns = columns;
4745
}
@@ -50,12 +48,7 @@ public static <X> SqmCteTable<X> createStatementTable(
5048
String name,
5149
SqmCteStatement<X> cteStatement,
5250
SqmSelectQuery<X> selectStatement) {
53-
final SqmSelectableNode<?>[] sqmSelectableNodes = selectStatement.getQueryPart()
54-
.getFirstQuerySpec()
55-
.getSelectClause()
56-
.getSelectionItems()
57-
.toArray( SqmSelectableNode[]::new );
58-
return new SqmCteTable<>( name, cteStatement, sqmSelectableNodes, extractAliases(selectStatement) );
51+
return new SqmCteTable<>( name, cteStatement, selectStatement );
5952
}
6053

6154
@Override

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

Lines changed: 36 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@
2323
import org.hibernate.query.sqm.tree.domain.SqmDomainType;
2424
import org.hibernate.query.sqm.tree.domain.SqmPluralPersistentAttribute;
2525
import org.hibernate.query.sqm.tree.select.SqmSelectQuery;
26+
import org.hibernate.query.sqm.tree.select.SqmSelection;
2627
import org.hibernate.query.sqm.tuple.TupleType;
2728
import org.hibernate.query.SemanticException;
2829
import org.hibernate.query.sqm.SqmExpressible;
2930
import org.hibernate.query.sqm.tree.domain.SqmPath;
3031
import org.hibernate.query.sqm.tree.select.SqmSelectClause;
3132
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
32-
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
3333
import org.hibernate.spi.NavigablePath;
3434
import org.hibernate.sql.ast.spi.FromClauseAccess;
3535
import org.hibernate.sql.ast.spi.SqlSelection;
@@ -56,29 +56,50 @@ public class AnonymousTupleType<T>
5656
private final String[] componentNames;
5757
private final Map<String, Integer> componentIndexMap;
5858

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

63-
public AnonymousTupleType(SqmSelectableNode<?>[] components, List<String> aliases) {
64-
expressibles = new SqmBindableType<?>[components.length];
65-
componentSourcePaths = new NavigablePath[components.length];
66-
for ( int i = 0; i < components.length; i++ ) {
67-
expressibles[i] = components[i].getNodeType();
68-
if ( components[i] instanceof SqmPath<?> path ) {
69-
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+
if ( selections != null ) {
75+
for ( SqmSelection<?> selection : selections ) {
76+
selection.getSelectableNode().visitSubSelectableNodes( selectableNodes::add );
77+
78+
if ( selection.getSelectableNode().isCompoundSelection() ) {
79+
selection.getSelectableNode().visitSubSelectableNodes( node ->
80+
aliases.add( node.getAlias() )
81+
);
82+
}
83+
else {
84+
aliases.add( selection.getAlias() );
85+
}
7086
}
7187
}
88+
89+
final SqmSelectableNode<?>[] components = selectableNodes.toArray(new SqmSelectableNode[0]);
90+
91+
expressibles = new SqmBindableType<?>[components.length];
92+
componentSourcePaths = new NavigablePath[components.length];
7293
componentNames = new String[components.length];
7394
//noinspection unchecked
7495
javaTypeDescriptor = (JavaType<T>) new ObjectArrayJavaType( getTypeDescriptors( components ) );
7596
componentIndexMap = linkedMapOfSize( components.length );
7697
for ( int i = 0; i < components.length; i++ ) {
77-
final SqmSelectableNode<?> component = components[i];
78-
String alias = aliases == null ? null : aliases.get( i );
79-
if ( alias == null ) {
80-
alias = component.getAlias();
98+
expressibles[i] = components[i].getNodeType();
99+
if ( components[i] instanceof SqmPath<?> path ) {
100+
componentSourcePaths[i] = path.getNavigablePath();
81101
}
102+
String alias = aliases.get( i );
82103
if ( alias == null ) {
83104
throw new SemanticException( "Select item at position " + (i+1) + " in select list has no alias"
84105
+ " (aliases are required in CTEs and in subqueries occurring in from clause)" );
@@ -114,31 +135,6 @@ public String getTypeName() {
114135
return SqmDomainType.super.getTypeName();
115136
}
116137

117-
private static SqmSelectableNode<?>[] extractSqmExpressibles(SqmSubQuery<?> subQuery) {
118-
final SqmSelectClause selectClause = subQuery.getQuerySpec().getSelectClause();
119-
if ( selectClause == null || selectClause.getSelectionItems().isEmpty() ) {
120-
throw new IllegalArgumentException( "subquery has no selection items" );
121-
}
122-
// todo: right now, we "snapshot" the state of the subquery when creating this type, but maybe we shouldn't?
123-
// i.e. what if the subquery changes later on? Or should we somehow mark the subquery to signal,
124-
// that changes to the select clause are invalid after a certain point?
125-
return selectClause.getSelectionItems().toArray( SqmSelectableNode[]::new );
126-
}
127-
128-
protected static List<String> extractAliases(SqmSelectQuery<?> subQuery) {
129-
final SqmSelectClause selectClause = subQuery.getQueryPart()
130-
.getFirstQuerySpec()
131-
.getSelectClause();
132-
final var aliases = new ArrayList<String>();
133-
for (final var selection : selectClause.getSelections()) {
134-
final var alias = selection.getAlias();
135-
selection.getSelectableNode().visitSubSelectableNodes( node ->
136-
aliases.add( alias == null ? node.getAlias() : alias )
137-
);
138-
}
139-
return aliases;
140-
}
141-
142138
private static JavaType<?>[] getTypeDescriptors(SqmSelectableNode<?>[] components) {
143139
final JavaType<?>[] typeDescriptors = new JavaType<?>[components.length];
144140
for ( int i = 0; i < components.length; i++ ) {

0 commit comments

Comments
 (0)