Skip to content

Commit 1ae3cfd

Browse files
committed
HHH-17002, HHH-18820, HHH-19391, HHH-18514 equals() and hashCode() for SQM nodes
- finally enables efficient caching of criteria query plans - also reconsider how alias generation is done - aliases should only be unique to a given query, NOT globally unique, since that results in interpretation cache misses - ran into and fixed several other problems along the way - note that the previous solution based on translating to HQL was not working at all, partly because the translation to HQL is not very correct - but anyway this is more efficient, since hashCodes are in general more flexible from an efficiency perspective - there is still a remaining problem where NavigablePaths elements are assigned globally unique aliases resulting in cache misses
1 parent 5ef0737 commit 1ae3cfd

File tree

134 files changed

+1885
-391
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

134 files changed

+1885
-391
lines changed

hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2UnnestFunction.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ public H2UnnestFunction(int maximumArraySize) {
6363
protected <T> SelfRenderingSqmSetReturningFunction<T> generateSqmSetReturningFunctionExpression(
6464
List<? extends SqmTypedNode<?>> arguments,
6565
QueryEngine queryEngine) {
66-
//noinspection unchecked
6766
return new SelfRenderingSqmSetReturningFunction<>(
6867
this,
6968
this,

hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AnyDiscriminatorSqmPath.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import org.hibernate.query.sqm.tree.domain.SqmPath;
1414
import org.hibernate.spi.NavigablePath;
1515

16+
import java.util.Objects;
17+
1618
public class AnyDiscriminatorSqmPath<T> extends AbstractSqmPath<T> implements DiscriminatorSqmPath<T> {
1719

1820
protected AnyDiscriminatorSqmPath(
@@ -46,4 +48,16 @@ public AnyDiscriminatorSqmPathSource<T> getExpressible() {
4648
// return (AnyDiscriminatorSqmPathSource<T>) getNodeType();
4749
return (AnyDiscriminatorSqmPathSource<T>) getReferencedPathSource();
4850
}
51+
52+
53+
@Override
54+
public boolean equals(Object object) {
55+
return object instanceof AnyDiscriminatorSqmPath<?> that
56+
&& Objects.equals( this.getLhs(), that.getLhs() );
57+
}
58+
59+
@Override
60+
public int hashCode() {
61+
return getLhs().hashCode();
62+
}
4963
}

hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddedDiscriminatorSqmPath.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import org.hibernate.query.sqm.tree.domain.SqmPath;
1515
import org.hibernate.spi.NavigablePath;
1616

17+
import java.util.Objects;
18+
1719
/**
1820
* {@link SqmPath} specialization for an embeddable discriminator
1921
*
@@ -59,4 +61,15 @@ public EmbeddedDiscriminatorSqmPath<T> copy(SqmCopyContext context) {
5961
public <X> X accept(SemanticQueryWalker<X> walker) {
6062
return walker.visitDiscriminatorPath( this );
6163
}
64+
65+
@Override
66+
public boolean equals(Object object) {
67+
return object instanceof EmbeddedDiscriminatorSqmPath<?> that
68+
&& Objects.equals( this.getLhs(), that.getLhs() );
69+
}
70+
71+
@Override
72+
public int hashCode() {
73+
return getLhs().hashCode();
74+
}
6275
}

hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityDiscriminatorSqmPath.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import org.hibernate.query.sqm.tree.domain.SqmEntityDomainType;
1818
import org.hibernate.spi.NavigablePath;
1919

20+
import java.util.Objects;
21+
2022
/**
2123
* {@link SqmPath} specialization for an entity discriminator
2224
*
@@ -72,6 +74,16 @@ public <X> X accept(SemanticQueryWalker<X> walker) {
7274
return entityDescriptor.hasSubclasses()
7375
? walker.visitDiscriminatorPath( this )
7476
: walker.visitEntityTypeLiteralExpression( new SqmLiteralEntityType( entityDomainType, nodeBuilder() ) );
77+
}
78+
79+
@Override
80+
public boolean equals(Object object) {
81+
return object instanceof EntityDiscriminatorSqmPath<?> that
82+
&& Objects.equals( this.getLhs(), that.getLhs() );
83+
}
7584

85+
@Override
86+
public int hashCode() {
87+
return getLhs().hashCode();
7688
}
7789
}

hibernate-core/src/main/java/org/hibernate/query/hql/internal/QuerySplitter.java

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
*/
55
package org.hibernate.query.hql.internal;
66

7-
import java.util.Set;
8-
97
import org.hibernate.metamodel.model.domain.EntityDomainType;
108
import org.hibernate.query.sqm.tree.SqmCopyContext;
119
import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement;
@@ -30,24 +28,24 @@ public static <R> SqmSelectStatement<R>[] split(SqmSelectStatement<R> statement)
3028
// We only allow unmapped polymorphism in a very restricted way. Specifically,
3129
// the unmapped polymorphic reference can only be a root and can be the only
3230
// root. Use that restriction to locate the unmapped polymorphic reference
33-
final SqmRoot<?> unmappedPolymorphicReference = findUnmappedPolymorphicReference( statement.getQueryPart() );
34-
31+
final SqmRoot<?> unmappedPolymorphicReference =
32+
findUnmappedPolymorphicReference( statement.getQueryPart() );
3533
if ( unmappedPolymorphicReference == null ) {
3634
@SuppressWarnings("unchecked")
3735
SqmSelectStatement<R>[] sqmSelectStatement = new SqmSelectStatement[] { statement };
3836
return sqmSelectStatement;
3937
}
4038

41-
final SqmPolymorphicRootDescriptor<R> unmappedPolymorphicDescriptor = (SqmPolymorphicRootDescriptor<R>) unmappedPolymorphicReference.getReferencedPathSource();
42-
final Set<EntityDomainType<? extends R>> implementors = unmappedPolymorphicDescriptor.getImplementors();
39+
final var unmappedPolymorphicDescriptor =
40+
(SqmPolymorphicRootDescriptor<R>)
41+
unmappedPolymorphicReference.getReferencedPathSource();
42+
var implementors = unmappedPolymorphicDescriptor.getImplementors();
4343
@SuppressWarnings("unchecked")
4444
final SqmSelectStatement<R>[] expanded = new SqmSelectStatement[ implementors.size() ];
45-
4645
int i = 0;
4746
for ( EntityDomainType<?> mappedDescriptor : implementors ) {
4847
expanded[i++] = copyStatement( statement, unmappedPolymorphicReference, mappedDescriptor );
4948
}
50-
5149
return expanded;
5250
}
5351

@@ -97,31 +95,29 @@ public static <R> SqmDeleteStatement<R>[] split(SqmDeleteStatement<R> statement)
9795
// We only allow unmapped polymorphism in a very restricted way. Specifically,
9896
// the unmapped polymorphic reference can only be a root and can be the only
9997
// root. Use that restriction to locate the unmapped polymorphic reference
100-
final SqmRoot<?> unmappedPolymorphicReference = findUnmappedPolymorphicReference( statement );
101-
98+
final SqmRoot<?> unmappedPolymorphicReference =
99+
findUnmappedPolymorphicReference( statement );
102100
if ( unmappedPolymorphicReference == null ) {
103101
@SuppressWarnings("unchecked")
104102
SqmDeleteStatement<R>[] sqmDeleteStatement = new SqmDeleteStatement[] { statement };
105103
return sqmDeleteStatement;
106104
}
107105

108-
final SqmPolymorphicRootDescriptor<R> unmappedPolymorphicDescriptor =
109-
(SqmPolymorphicRootDescriptor<R>) unmappedPolymorphicReference.getReferencedPathSource();
110-
final Set<EntityDomainType<? extends R>> implementors = unmappedPolymorphicDescriptor.getImplementors();
106+
final var unmappedPolymorphicDescriptor =
107+
(SqmPolymorphicRootDescriptor<R>)
108+
unmappedPolymorphicReference.getReferencedPathSource();
109+
final var implementors = unmappedPolymorphicDescriptor.getImplementors();
111110
@SuppressWarnings("unchecked")
112111
final SqmDeleteStatement<R>[] expanded = new SqmDeleteStatement[ implementors.size() ];
113-
114112
int i = 0;
115113
for ( EntityDomainType<?> mappedDescriptor : implementors ) {
116114
expanded[i++] = copyStatement( statement, unmappedPolymorphicReference, mappedDescriptor );
117115
}
118-
119116
return expanded;
120117
}
121118

122119
private static SqmRoot<?> findUnmappedPolymorphicReference(SqmDeleteOrUpdateStatement<?> queryPart) {
123-
return queryPart.getTarget().getReferencedPathSource() instanceof SqmPolymorphicRootDescriptor<?>
124-
? queryPart.getTarget()
125-
: null;
120+
final SqmRoot<?> target = queryPart.getTarget();
121+
return target.getReferencedPathSource() instanceof SqmPolymorphicRootDescriptor<?> ? target : null;
126122
}
127123
}

hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1223,7 +1223,7 @@ private SqmFromClause buildInferredFromClause(HqlParser.SelectClauseContext sele
12231223
final EntityDomainType<R> entityDescriptor = getResultEntity();
12241224
if ( entityDescriptor != null ) {
12251225
final SqmRoot<R> sqmRoot =
1226-
new SqmRoot<>( entityDescriptor, null, false, nodeBuilder() );
1226+
new SqmRoot<>( entityDescriptor, "_0", false, nodeBuilder() );
12271227
processingStateStack.getCurrent().getPathRegistry().register( sqmRoot );
12281228
fromClause.addRoot( sqmRoot );
12291229
}

hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmTreeCreationHelper.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -134,24 +134,21 @@ public class SqmTreeCreationHelper {
134134
*/
135135
public static <E> void handleRootAsCrossJoin(
136136
HqlParser.EntityWithJoinsContext entityWithJoinsContext,
137-
SqmRoot<?> sqmPrimaryRoot,
137+
SqmRoot<E> sqmPrimaryRoot,
138138
SemanticQueryBuilder<?> sqmBuilder) {
139-
final HqlParser.RootEntityContext fromRootContext = (HqlParser.RootEntityContext) entityWithJoinsContext.fromRoot();
139+
final HqlParser.RootEntityContext fromRootContext =
140+
(HqlParser.RootEntityContext) entityWithJoinsContext.fromRoot();
140141

141142
//noinspection unchecked
142143
final SqmRoot<E> sqmRoot = (SqmRoot<E>) fromRootContext.accept( sqmBuilder );
143144
SqmTreeCreationLogger.LOGGER.debugf( "Handling secondary root path as cross-join - %s", sqmRoot.getEntityName() );
144-
145-
final String alias = extractAlias( fromRootContext.variable(), sqmBuilder );
146-
final SqmEntityJoin<?,E> pseudoCrossJoin = new SqmEntityJoin<>(
145+
final SqmEntityJoin<E,E> pseudoCrossJoin = new SqmEntityJoin<>(
147146
sqmRoot.getManagedType(),
148-
alias,
147+
extractAlias( fromRootContext.variable(), sqmBuilder ),
149148
SqmJoinType.CROSS,
150149
sqmPrimaryRoot
151150
);
152-
153-
//noinspection unchecked,rawtypes
154-
sqmPrimaryRoot.addSqmJoin( (SqmEntityJoin) pseudoCrossJoin );
151+
sqmPrimaryRoot.addSqmJoin( pseudoCrossJoin );
155152

156153
final SqmCreationProcessingState processingState = sqmBuilder.getProcessingStateStack().getCurrent();
157154
final SqmPathRegistry pathRegistry = processingState.getPathRegistry();

hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingsImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ public <P> QueryParameterBinding<P> getBinding(String name) {
162162

163163
@Override
164164
public void validate() {
165-
for ( Map.Entry<QueryParameter<?>, QueryParameterBinding<?>> entry : parameterBindingMap.entrySet() ) {
165+
for ( var entry : parameterBindingMap.entrySet() ) {
166166
if ( !entry.getValue().isBound() ) {
167167
final QueryParameter<?> queryParameter = entry.getKey();
168168
if ( queryParameter.isNamed() ) {

hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmFunction.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import java.util.ArrayList;
88
import java.util.List;
9+
import java.util.Objects;
910
import java.util.function.Supplier;
1011

1112
import org.hibernate.metamodel.mapping.BasicValuedMapping;
@@ -255,4 +256,15 @@ public MappingModelExpressible<?> get() {
255256
}
256257
}
257258

259+
@Override
260+
// TODO: override on all subtypes
261+
public boolean equals(Object other) {
262+
return other instanceof SelfRenderingSqmAggregateFunction<?> that
263+
&& Objects.equals( this.toHqlString(), that.toHqlString() );
264+
}
265+
266+
@Override
267+
public int hashCode() {
268+
return toHqlString().hashCode();
269+
}
258270
}

hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmOrderedSetAggregateFunction.java

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -138,28 +138,31 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) {
138138
final List<? extends SqmTypedNode<?>> arguments = getArguments();
139139
hql.append( getFunctionName() );
140140
hql.append( '(' );
141-
int i = 1;
142-
if ( arguments.get( 0 ) instanceof SqmDistinct<?> ) {
143-
arguments.get( 0 ).appendHqlString( hql, context );
144-
if ( arguments.size() > 1 ) {
145-
hql.append( ' ' );
146-
arguments.get( 1 ).appendHqlString( hql, context );
147-
i = 2;
141+
if ( !arguments.isEmpty() ) {
142+
int i = 1;
143+
if ( arguments.get( 0 ) instanceof SqmDistinct<?> ) {
144+
arguments.get( 0 ).appendHqlString( hql, context );
145+
if ( arguments.size() > 1 ) {
146+
hql.append( ' ' );
147+
arguments.get( 1 ).appendHqlString( hql, context );
148+
i = 2;
149+
}
150+
}
151+
for ( ; i < arguments.size(); i++ ) {
152+
hql.append( ", " );
153+
arguments.get( i ).appendHqlString( hql, context );
148154
}
149155
}
150-
for ( ; i < arguments.size(); i++ ) {
151-
hql.append(", ");
152-
arguments.get( i ).appendHqlString( hql, context );
153-
}
154-
155156
hql.append( ')' );
156157
if ( withinGroup != null ) {
157158
hql.append( " within group (order by " );
158159
final List<SqmSortSpecification> sortSpecifications = withinGroup.getSortSpecifications();
159-
sortSpecifications.get( 0 ).appendHqlString( hql, context );
160-
for ( int j = 1; j < sortSpecifications.size(); j++ ) {
161-
hql.append( ", " );
162-
sortSpecifications.get( j ).appendHqlString( hql, context );
160+
if ( !sortSpecifications.isEmpty() ) {
161+
sortSpecifications.get( 0 ).appendHqlString( hql, context );
162+
for ( int j = 1; j < sortSpecifications.size(); j++ ) {
163+
hql.append( ", " );
164+
sortSpecifications.get( j ).appendHqlString( hql, context );
165+
}
163166
}
164167
hql.append( ')' );
165168
}

0 commit comments

Comments
 (0)