From c73795bf8126d9444525e7b8a3263763ba412c9b Mon Sep 17 00:00:00 2001 From: Gavin King Date: Mon, 28 Apr 2025 10:42:44 +0200 Subject: [PATCH 1/5] HHH-19391 add test for issue contributed by @theigl --- .../query/criteria/plan/CriteriaPlanTest.java | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/plan/CriteriaPlanTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/plan/CriteriaPlanTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/plan/CriteriaPlanTest.java new file mode 100644 index 000000000000..8b6a36c90ae4 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/plan/CriteriaPlanTest.java @@ -0,0 +1,113 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.query.criteria.plan; + +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.query.criteria.HibernateCriteriaBuilder; +import org.hibernate.query.criteria.JpaCriteriaQuery; +import org.hibernate.query.criteria.JpaRoot; +import org.hibernate.testing.orm.junit.*; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.*; +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@DomainModel(annotatedClasses = {CriteriaPlanTest.Author.class, CriteriaPlanTest.Book.class}) +@ServiceRegistry( + settings = { + @Setting(name = AvailableSettings.CRITERIA_COPY_TREE, value = "false"), + @Setting(name = AvailableSettings.CRITERIA_PLAN_CACHE_ENABLED, value = "true"), + } +) +@SessionFactory +class CriteriaPlanTest { + + @Test + void criteriaPlanCacheWithEntityParameters(SessionFactoryScope scope) { + scope.inTransaction( session -> { + final Author author = populateData(session); + + assertThat(runQuery(session, author)).hasSize(5); + assertThat(runQuery(session, author)).hasSize(5); + } ); + } + + private static List runQuery(SessionImplementor session, Author author) { + final HibernateCriteriaBuilder cb = session.getCriteriaBuilder(); + final JpaCriteriaQuery q = cb.createQuery(Book.class); + final JpaRoot root = q.from(Book.class); + q.select(root); + q.where(cb.equal(root.get("author"), author)); + return session.createQuery(q).getResultList(); + } + + public Author populateData(SessionImplementor entityManager) { + final Author author = new Author(); + author.name = "David Gourley"; + entityManager.persist(author); + + for (int i = 0; i < 5; i++) { + final Book book = new Book(); + book.name = "HTTP Definitive guide " + i; + book.author = author; + entityManager.persist(book); + author.books.add(book); + } + + return author; + } + + @Entity(name = "Author") + @Table(name = "Author") + public static class Author { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + public Long authorId; + + @Column + public String name; + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "author") + public List books = new ArrayList<>(); + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final Author author = (Author) o; + return authorId.equals(author.authorId); + } + + @Override + public int hashCode() { + return authorId.hashCode(); + } + } + + @org.hibernate.annotations.Cache(usage = org.hibernate.annotations.CacheConcurrencyStrategy.READ_WRITE) + @Entity(name = "Book") + @Table(name = "Book") + public static class Book { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + public Long bookId; + + @Column + public String name; + + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "author_id", nullable = false) + public Author author; + } +} From cb857b175bb090bdf267ab5d7c68ae5e6f05f5f9 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Sun, 27 Apr 2025 12:28:59 +0200 Subject: [PATCH 2/5] 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 --- .../function/array/H2UnnestFunction.java | 1 - .../internal/AnyDiscriminatorSqmPath.java | 14 +++ .../EmbeddedDiscriminatorSqmPath.java | 13 +++ .../internal/EntityDiscriminatorSqmPath.java | 19 +++- .../query/hql/internal/QuerySplitter.java | 32 +++---- .../hql/internal/SemanticQueryBuilder.java | 2 +- .../hql/internal/SqmTreeCreationHelper.java | 15 ++- .../internal/QueryParameterBindingsImpl.java | 2 +- .../function/SelfRenderingSqmFunction.java | 12 +++ ...nderingSqmOrderedSetAggregateFunction.java | 35 +++---- .../query/sqm/internal/QuerySqmImpl.java | 31 ++----- .../sqm/internal/SimpleSqmRenderContext.java | 7 +- .../sqm/internal/SqmCriteriaNodeBuilder.java | 12 +-- .../sqm/internal/SqmSelectionQueryImpl.java | 28 ++---- .../SelectableMappingExpressionConverter.java | 6 +- .../query/sqm/spi/SqmCreationHelper.java | 23 +++++ .../sqm/tree/AbstractSqmDmlStatement.java | 7 +- .../AbstractSqmRestrictedDmlStatement.java | 6 +- .../query/sqm/tree/AbstractSqmStatement.java | 12 ++- .../hibernate/query/sqm/tree/SqmQuery.java | 2 + .../query/sqm/tree/cte/SqmCteStatement.java | 32 ++++++- .../query/sqm/tree/cte/SqmCteTable.java | 10 +- .../sqm/tree/delete/SqmDeleteStatement.java | 17 +++- .../tree/domain/AbstractSqmAttributeJoin.java | 23 ++++- .../sqm/tree/domain/AbstractSqmFrom.java | 93 ++++++++++++------- .../sqm/tree/domain/AbstractSqmJoin.java | 15 +++ .../sqm/tree/domain/AbstractSqmPath.java | 33 ++++--- .../tree/domain/AbstractSqmSimplePath.java | 1 + .../query/sqm/tree/domain/SqmCteRoot.java | 14 +++ .../query/sqm/tree/domain/SqmDerivedRoot.java | 14 +++ .../domain/SqmElementAggregateFunction.java | 16 +++- .../sqm/tree/domain/SqmFkExpression.java | 16 +++- .../sqm/tree/domain/SqmFunctionPath.java | 14 +++ .../sqm/tree/domain/SqmFunctionRoot.java | 14 +++ .../domain/SqmIndexAggregateFunction.java | 18 +++- .../SqmIndexedCollectionAccessPath.java | 15 +++ .../sqm/tree/domain/SqmMapEntryReference.java | 28 ++++-- .../sqm/tree/domain/SqmTreatedBagJoin.java | 15 +++ .../sqm/tree/domain/SqmTreatedCrossJoin.java | 15 +++ .../SqmTreatedEmbeddedValuedSimplePath.java | 15 +++ .../sqm/tree/domain/SqmTreatedEntityJoin.java | 16 ++++ .../SqmTreatedEntityValuedSimplePath.java | 15 +++ .../sqm/tree/domain/SqmTreatedListJoin.java | 15 +++ .../sqm/tree/domain/SqmTreatedMapJoin.java | 15 +++ .../tree/domain/SqmTreatedPluralPartJoin.java | 18 +++- .../query/sqm/tree/domain/SqmTreatedRoot.java | 17 +++- .../sqm/tree/domain/SqmTreatedSetJoin.java | 15 +++ .../sqm/tree/domain/SqmTreatedSimplePath.java | 15 +++ .../tree/domain/SqmTreatedSingularJoin.java | 15 +++ .../expression/AsWrapperSqmExpression.java | 13 +++ .../tree/expression/JpaCriteriaParameter.java | 48 +++++----- .../tree/expression/SqmAliasedNodeRef.java | 15 +++ .../query/sqm/tree/expression/SqmAny.java | 12 +++ .../expression/SqmAnyDiscriminatorValue.java | 14 +++ .../tree/expression/SqmBinaryArithmetic.java | 14 +++ .../query/sqm/tree/expression/SqmByUnit.java | 17 +++- .../sqm/tree/expression/SqmCaseSearched.java | 12 +++ .../sqm/tree/expression/SqmCaseSimple.java | 13 +++ .../sqm/tree/expression/SqmCastTarget.java | 16 ++++ .../sqm/tree/expression/SqmCoalesce.java | 27 ++++-- .../tree/expression/SqmCollectionSize.java | 12 +++ .../sqm/tree/expression/SqmDistinct.java | 13 +++ .../sqm/tree/expression/SqmDurationUnit.java | 12 +++ .../query/sqm/tree/expression/SqmEvery.java | 12 +++ .../sqm/tree/expression/SqmFieldLiteral.java | 17 +++- .../sqm/tree/expression/SqmFunction.java | 15 ++- .../tree/expression/SqmHqlNumericLiteral.java | 31 ++----- .../SqmJpaCriteriaParameterWrapper.java | 53 +++++++---- .../expression/SqmJsonExistsExpression.java | 11 ++- .../query/sqm/tree/expression/SqmLiteral.java | 12 +++ .../expression/SqmLiteralEmbeddableType.java | 13 +++ .../tree/expression/SqmLiteralEntityType.java | 12 +++ .../sqm/tree/expression/SqmLiteralNull.java | 10 ++ .../SqmModifiedSubQueryExpression.java | 14 +++ .../tree/expression/SqmNamedExpression.java | 14 +++ .../tree/expression/SqmNamedParameter.java | 20 +++- .../query/sqm/tree/expression/SqmOver.java | 13 +++ .../sqm/tree/expression/SqmOverflow.java | 14 +++ .../sqm/tree/expression/SqmParameter.java | 8 +- .../SqmParameterizedEntityType.java | 16 +++- .../expression/SqmPositionalParameter.java | 15 ++- .../SqmSelfRenderingExpression.java | 6 +- .../expression/SqmSetReturningFunction.java | 34 +++++-- .../query/sqm/tree/expression/SqmStar.java | 9 ++ .../sqm/tree/expression/SqmSummarization.java | 1 + .../sqm/tree/expression/SqmToDuration.java | 14 +++ .../tree/expression/SqmTrimSpecification.java | 13 +++ .../query/sqm/tree/expression/SqmTuple.java | 12 +++ .../tree/expression/SqmUnaryOperation.java | 4 +- .../query/sqm/tree/expression/SqmWindow.java | 22 +++++ .../ValueBindJpaCriteriaParameter.java | 34 +++++-- .../query/sqm/tree/from/SqmCrossJoin.java | 13 +++ .../query/sqm/tree/from/SqmCteJoin.java | 14 +++ .../query/sqm/tree/from/SqmDerivedJoin.java | 15 +++ .../query/sqm/tree/from/SqmEntityJoin.java | 12 +++ .../query/sqm/tree/from/SqmFrom.java | 2 + .../query/sqm/tree/from/SqmFromClause.java | 62 ++++++++++--- .../query/sqm/tree/from/SqmFunctionJoin.java | 15 +++ .../query/sqm/tree/from/SqmRoot.java | 7 +- .../sqm/tree/insert/SqmConflictClause.java | 15 +++ .../tree/insert/SqmInsertSelectStatement.java | 20 +++- .../tree/insert/SqmInsertValuesStatement.java | 22 ++++- .../AbstractNegatableSqmPredicate.java | 18 +++- .../tree/predicate/SqmBetweenPredicate.java | 16 ++++ .../SqmBooleanExpressionPredicate.java | 22 +++-- .../predicate/SqmComparisonPredicate.java | 16 ++++ .../tree/predicate/SqmEmptinessPredicate.java | 16 +++- .../tree/predicate/SqmExistsPredicate.java | 14 +++ .../tree/predicate/SqmGroupedPredicate.java | 13 +++ .../tree/predicate/SqmInListPredicate.java | 14 +++ .../predicate/SqmInSubQueryPredicate.java | 15 +++ .../tree/predicate/SqmJunctionPredicate.java | 23 ++++- .../sqm/tree/predicate/SqmLikePredicate.java | 17 ++++ .../tree/predicate/SqmMemberOfPredicate.java | 15 +++ .../tree/predicate/SqmNegatedPredicate.java | 12 +++ .../tree/predicate/SqmNullnessPredicate.java | 14 +++ .../tree/predicate/SqmTruthnessPredicate.java | 15 +++ .../sqm/tree/predicate/SqmWhereClause.java | 12 +++ .../tree/select/AbstractSqmSelectQuery.java | 50 ++++++---- .../tree/select/SqmDynamicInstantiation.java | 25 +++++ .../SqmDynamicInstantiationArgument.java | 14 +++ .../tree/select/SqmJpaCompoundSelection.java | 12 +++ .../sqm/tree/select/SqmOrderByClause.java | 12 +++ .../query/sqm/tree/select/SqmQueryGroup.java | 14 +++ .../query/sqm/tree/select/SqmQueryPart.java | 68 +++++++------- .../query/sqm/tree/select/SqmQuerySpec.java | 29 +++++- .../sqm/tree/select/SqmSelectClause.java | 13 +++ .../sqm/tree/select/SqmSelectStatement.java | 40 +++++--- .../query/sqm/tree/select/SqmSelection.java | 15 +++ .../sqm/tree/select/SqmSortSpecification.java | 20 ++-- .../query/sqm/tree/select/SqmSubQuery.java | 17 ++++ .../sqm/tree/update/SqmUpdateStatement.java | 20 +++- .../internal/JdbcParameterBindingsImpl.java | 31 +++---- ...stractQueryCacheResultTransformerTest.java | 2 +- 134 files changed, 1914 insertions(+), 442 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2UnnestFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2UnnestFunction.java index deaaec938c51..8c6aadf5f5ba 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2UnnestFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2UnnestFunction.java @@ -63,7 +63,6 @@ public H2UnnestFunction(int maximumArraySize) { protected SelfRenderingSqmSetReturningFunction generateSqmSetReturningFunctionExpression( List> arguments, QueryEngine queryEngine) { - //noinspection unchecked return new SelfRenderingSqmSetReturningFunction<>( this, this, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AnyDiscriminatorSqmPath.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AnyDiscriminatorSqmPath.java index 5f23139da585..e39e8b6916f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AnyDiscriminatorSqmPath.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AnyDiscriminatorSqmPath.java @@ -13,6 +13,8 @@ import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.spi.NavigablePath; +import java.util.Objects; + public class AnyDiscriminatorSqmPath extends AbstractSqmPath implements DiscriminatorSqmPath { protected AnyDiscriminatorSqmPath( @@ -45,4 +47,16 @@ public X accept(SemanticQueryWalker walker) { public AnyDiscriminatorSqmPathSource getExpressible() { return (AnyDiscriminatorSqmPathSource) getNodeType(); } + + + @Override + public boolean equals(Object object) { + return object instanceof AnyDiscriminatorSqmPath that + && Objects.equals( this.getLhs(), that.getLhs() ); + } + + @Override + public int hashCode() { + return getLhs().hashCode(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddedDiscriminatorSqmPath.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddedDiscriminatorSqmPath.java index 31ef610b8b82..56c166ca7962 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddedDiscriminatorSqmPath.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddedDiscriminatorSqmPath.java @@ -14,6 +14,8 @@ import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.spi.NavigablePath; +import java.util.Objects; + /** * {@link SqmPath} specialization for an embeddable discriminator * @@ -59,4 +61,15 @@ public EmbeddedDiscriminatorSqmPath copy(SqmCopyContext context) { public X accept(SemanticQueryWalker walker) { return walker.visitDiscriminatorPath( this ); } + + @Override + public boolean equals(Object object) { + return object instanceof EmbeddedDiscriminatorSqmPath that + && Objects.equals( this.getLhs(), that.getLhs() ); + } + + @Override + public int hashCode() { + return getLhs().hashCode(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityDiscriminatorSqmPath.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityDiscriminatorSqmPath.java index f16a5d4065b4..8927ff2122fa 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityDiscriminatorSqmPath.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityDiscriminatorSqmPath.java @@ -17,6 +17,8 @@ import org.hibernate.query.sqm.tree.domain.SqmEntityDomainType; import org.hibernate.spi.NavigablePath; +import java.util.Objects; + /** * {@link SqmPath} specialization for an entity discriminator * @@ -66,10 +68,19 @@ public EntityDiscriminatorSqmPath copy(SqmCopyContext context) { @Override public X accept(SemanticQueryWalker walker) { - if ( ! entityDescriptor.hasSubclasses() ) { - return walker.visitEntityTypeLiteralExpression( new SqmLiteralEntityType( entityDomainType, nodeBuilder() ) ); - } + return entityDescriptor.hasSubclasses() + ? walker.visitDiscriminatorPath( this ) + : walker.visitEntityTypeLiteralExpression( new SqmLiteralEntityType( entityDomainType, nodeBuilder() ) ); + } - return walker.visitDiscriminatorPath( this ); + @Override + public boolean equals(Object object) { + return object instanceof EntityDiscriminatorSqmPath that + && Objects.equals( this.getLhs(), that.getLhs() ); + } + + @Override + public int hashCode() { + return getLhs().hashCode(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/QuerySplitter.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/QuerySplitter.java index 4d3f35e74ac5..b7c294e5577d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/QuerySplitter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/QuerySplitter.java @@ -4,8 +4,6 @@ */ package org.hibernate.query.hql.internal; -import java.util.Set; - import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement; @@ -30,24 +28,24 @@ public static SqmSelectStatement[] split(SqmSelectStatement statement) // We only allow unmapped polymorphism in a very restricted way. Specifically, // the unmapped polymorphic reference can only be a root and can be the only // root. Use that restriction to locate the unmapped polymorphic reference - final SqmRoot unmappedPolymorphicReference = findUnmappedPolymorphicReference( statement.getQueryPart() ); - + final SqmRoot unmappedPolymorphicReference = + findUnmappedPolymorphicReference( statement.getQueryPart() ); if ( unmappedPolymorphicReference == null ) { @SuppressWarnings("unchecked") SqmSelectStatement[] sqmSelectStatement = new SqmSelectStatement[] { statement }; return sqmSelectStatement; } - final SqmPolymorphicRootDescriptor unmappedPolymorphicDescriptor = (SqmPolymorphicRootDescriptor) unmappedPolymorphicReference.getReferencedPathSource(); - final Set> implementors = unmappedPolymorphicDescriptor.getImplementors(); + final var unmappedPolymorphicDescriptor = + (SqmPolymorphicRootDescriptor) + unmappedPolymorphicReference.getReferencedPathSource(); + var implementors = unmappedPolymorphicDescriptor.getImplementors(); @SuppressWarnings("unchecked") final SqmSelectStatement[] expanded = new SqmSelectStatement[ implementors.size() ]; - int i = 0; for ( EntityDomainType mappedDescriptor : implementors ) { expanded[i++] = copyStatement( statement, unmappedPolymorphicReference, mappedDescriptor ); } - return expanded; } @@ -97,31 +95,29 @@ public static SqmDeleteStatement[] split(SqmDeleteStatement statement) // We only allow unmapped polymorphism in a very restricted way. Specifically, // the unmapped polymorphic reference can only be a root and can be the only // root. Use that restriction to locate the unmapped polymorphic reference - final SqmRoot unmappedPolymorphicReference = findUnmappedPolymorphicReference( statement ); - + final SqmRoot unmappedPolymorphicReference = + findUnmappedPolymorphicReference( statement ); if ( unmappedPolymorphicReference == null ) { @SuppressWarnings("unchecked") SqmDeleteStatement[] sqmDeleteStatement = new SqmDeleteStatement[] { statement }; return sqmDeleteStatement; } - final SqmPolymorphicRootDescriptor unmappedPolymorphicDescriptor = - (SqmPolymorphicRootDescriptor) unmappedPolymorphicReference.getReferencedPathSource(); - final Set> implementors = unmappedPolymorphicDescriptor.getImplementors(); + final var unmappedPolymorphicDescriptor = + (SqmPolymorphicRootDescriptor) + unmappedPolymorphicReference.getReferencedPathSource(); + final var implementors = unmappedPolymorphicDescriptor.getImplementors(); @SuppressWarnings("unchecked") final SqmDeleteStatement[] expanded = new SqmDeleteStatement[ implementors.size() ]; - int i = 0; for ( EntityDomainType mappedDescriptor : implementors ) { expanded[i++] = copyStatement( statement, unmappedPolymorphicReference, mappedDescriptor ); } - return expanded; } private static SqmRoot findUnmappedPolymorphicReference(SqmDeleteOrUpdateStatement queryPart) { - return queryPart.getTarget().getReferencedPathSource() instanceof SqmPolymorphicRootDescriptor - ? queryPart.getTarget() - : null; + final SqmRoot target = queryPart.getTarget(); + return target.getReferencedPathSource() instanceof SqmPolymorphicRootDescriptor ? target : null; } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java index 885dfd9ff84b..0821a59f59e3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java @@ -1229,7 +1229,7 @@ private SqmFromClause buildInferredFromClause(HqlParser.SelectClauseContext sele final EntityDomainType entityDescriptor = getResultEntity(); if ( entityDescriptor != null ) { final SqmRoot sqmRoot = - new SqmRoot<>( entityDescriptor, null, false, creationContext.getNodeBuilder() ); + new SqmRoot<>( entityDescriptor, "_0", false, creationContext.getNodeBuilder() ); processingStateStack.getCurrent().getPathRegistry().register( sqmRoot ); fromClause.addRoot( sqmRoot ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmTreeCreationHelper.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmTreeCreationHelper.java index 24c12826885a..bd308e3e5e26 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmTreeCreationHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmTreeCreationHelper.java @@ -134,24 +134,21 @@ public class SqmTreeCreationHelper { */ public static void handleRootAsCrossJoin( HqlParser.EntityWithJoinsContext entityWithJoinsContext, - SqmRoot sqmPrimaryRoot, + SqmRoot sqmPrimaryRoot, SemanticQueryBuilder sqmBuilder) { - final HqlParser.RootEntityContext fromRootContext = (HqlParser.RootEntityContext) entityWithJoinsContext.fromRoot(); + final HqlParser.RootEntityContext fromRootContext = + (HqlParser.RootEntityContext) entityWithJoinsContext.fromRoot(); //noinspection unchecked final SqmRoot sqmRoot = (SqmRoot) fromRootContext.accept( sqmBuilder ); SqmTreeCreationLogger.LOGGER.debugf( "Handling secondary root path as cross-join - %s", sqmRoot.getEntityName() ); - - final String alias = extractAlias( fromRootContext.variable(), sqmBuilder ); - final SqmEntityJoin pseudoCrossJoin = new SqmEntityJoin<>( + final SqmEntityJoin pseudoCrossJoin = new SqmEntityJoin<>( sqmRoot.getManagedType(), - alias, + extractAlias( fromRootContext.variable(), sqmBuilder ), SqmJoinType.CROSS, sqmPrimaryRoot ); - - //noinspection unchecked,rawtypes - sqmPrimaryRoot.addSqmJoin( (SqmEntityJoin) pseudoCrossJoin ); + sqmPrimaryRoot.addSqmJoin( pseudoCrossJoin ); final SqmCreationProcessingState processingState = sqmBuilder.getProcessingStateStack().getCurrent(); final SqmPathRegistry pathRegistry = processingState.getPathRegistry(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingsImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingsImpl.java index 5711a954da17..72740d486ef7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingsImpl.java @@ -162,7 +162,7 @@ public

QueryParameterBinding

getBinding(String name) { @Override public void validate() { - for ( Map.Entry, QueryParameterBinding> entry : parameterBindingMap.entrySet() ) { + for ( var entry : parameterBindingMap.entrySet() ) { if ( !entry.getValue().isBound() ) { final QueryParameter queryParameter = entry.getKey(); if ( queryParameter.isNamed() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmFunction.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmFunction.java index 133e46a4fc1d..d09108b3d4db 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmFunction.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.function.Supplier; import org.hibernate.metamodel.mapping.BasicValuedMapping; @@ -256,4 +257,15 @@ public MappingModelExpressible get() { } } + @Override + // TODO: override on all subtypes + public boolean equals(Object other) { + return other instanceof SelfRenderingSqmAggregateFunction that + && Objects.equals( this.toHqlString(), that.toHqlString() ); + } + + @Override + public int hashCode() { + return toHqlString().hashCode(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmOrderedSetAggregateFunction.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmOrderedSetAggregateFunction.java index 2cd720d3308e..8125588036a5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmOrderedSetAggregateFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmOrderedSetAggregateFunction.java @@ -138,28 +138,31 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { final List> arguments = getArguments(); hql.append( getFunctionName() ); hql.append( '(' ); - int i = 1; - if ( arguments.get( 0 ) instanceof SqmDistinct ) { - arguments.get( 0 ).appendHqlString( hql, context ); - if ( arguments.size() > 1 ) { - hql.append( ' ' ); - arguments.get( 1 ).appendHqlString( hql, context ); - i = 2; + if ( !arguments.isEmpty() ) { + int i = 1; + if ( arguments.get( 0 ) instanceof SqmDistinct ) { + arguments.get( 0 ).appendHqlString( hql, context ); + if ( arguments.size() > 1 ) { + hql.append( ' ' ); + arguments.get( 1 ).appendHqlString( hql, context ); + i = 2; + } + } + for ( ; i < arguments.size(); i++ ) { + hql.append( ", " ); + arguments.get( i ).appendHqlString( hql, context ); } } - for ( ; i < arguments.size(); i++ ) { - hql.append(", "); - arguments.get( i ).appendHqlString( hql, context ); - } - hql.append( ')' ); if ( withinGroup != null ) { hql.append( " within group (order by " ); final List sortSpecifications = withinGroup.getSortSpecifications(); - sortSpecifications.get( 0 ).appendHqlString( hql, context ); - for ( int j = 1; j < sortSpecifications.size(); j++ ) { - hql.append( ", " ); - sortSpecifications.get( j ).appendHqlString( hql, context ); + if ( !sortSpecifications.isEmpty() ) { + sortSpecifications.get( 0 ).appendHqlString( hql, context ); + for ( int j = 1; j < sortSpecifications.size(); j++ ) { + hql.append( ", " ); + sortSpecifications.get( j ).appendHqlString( hql, context ); + } } hql.append( ')' ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java index 772cea5d4298..3fefcfa94572 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java @@ -205,30 +205,13 @@ public QuerySqmImpl( SqmStatement criteria, boolean copyAst, Class expectedResultType, - SharedSessionContractImplementor producer) { - super( producer ); + SharedSessionContractImplementor session) { + super( session ); hql = CRITERIA_HQL_STRING; - if ( copyAst ) { - sqm = criteria.copy( SqmCopyContext.simpleContext() ); - if ( producer.isCriteriaPlanCacheEnabled() ) { - queryStringCacheKey = sqm.toHqlString(); - setQueryPlanCacheable( true ); - } - else { - queryStringCacheKey = sqm; - } - } - else { - sqm = criteria; - if ( producer.isCriteriaPlanCacheEnabled() ) { - queryStringCacheKey = sqm.toHqlString(); - } - else { - queryStringCacheKey = sqm; - } - // Cache immutable query plans by default - setQueryPlanCacheable( true ); - } + sqm = copyAst ? criteria.copy( SqmCopyContext.simpleContext() ) : criteria; + queryStringCacheKey = sqm; + // Cache immutable query plans by default + setQueryPlanCacheable( !copyAst || session.isCriteriaPlanCacheEnabled() ); setComment( hql ); @@ -236,7 +219,7 @@ public QuerySqmImpl( parameterMetadata = !domainParameterXref.hasParameters() ? ParameterMetadataImpl.EMPTY : new ParameterMetadataImpl( domainParameterXref.getQueryParameters() ); - parameterBindings = parameterMetadata.createBindings( producer.getFactory() ); + parameterBindings = parameterMetadata.createBindings( session.getFactory() ); // Parameters might be created through HibernateCriteriaBuilder.value which we need to bind here for ( SqmParameter sqmParameter : domainParameterXref.getParameterResolutions().getSqmParameters() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleSqmRenderContext.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleSqmRenderContext.java index 130e5c75cbc7..46c0481ea53a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleSqmRenderContext.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleSqmRenderContext.java @@ -23,10 +23,9 @@ public SimpleSqmRenderContext() { @Override public String resolveAlias(SqmFrom from) { final String explicitAlias = from.getExplicitAlias(); - if ( explicitAlias != null ) { - return explicitAlias; - } - return fromAliases.computeIfAbsent( from, f -> "alias_" + (fromId++) ); + return explicitAlias == null + ? fromAliases.computeIfAbsent( from, f -> "alias_" + (fromId++) ) + : explicitAlias; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java index fe575eabf9ef..d100df5bd9b8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java @@ -577,8 +577,8 @@ private SqmCastTarget castTarget(Class castTargetJavaType, @Nullable L @Override public SqmPredicate wrap(Expression expression) { - return expression instanceof SqmPredicate - ? (SqmPredicate) expression + return expression instanceof SqmPredicate predicate + ? predicate : new SqmBooleanExpressionPredicate( (SqmExpression) expression, this ); } @@ -607,7 +607,7 @@ public SqmExpression fk(Path

path) { final SqmPathSource toOneReference = sqmPath.getReferencedPathSource(); final boolean validToOneRef = toOneReference.getBindableType() == Bindable.BindableType.SINGULAR_ATTRIBUTE - && toOneReference instanceof EntitySqmPathSource; + && toOneReference instanceof EntitySqmPathSource; if ( !validToOneRef ) { throw new FunctionArgumentException( String.format( @@ -670,8 +670,6 @@ private static JpaCriteriaQuery createUnionSet( CriteriaQuery left, CriteriaQuery right) { assert operator == SetOperator.UNION || operator == SetOperator.UNION_ALL; - assert left instanceof SqmSelectStatement; - assert right instanceof SqmSelectStatement; final SqmSelectStatement leftSqm = (SqmSelectStatement) left; final SqmSelectStatement rightSqm = (SqmSelectStatement) right; @@ -707,8 +705,6 @@ private static JpaCriteriaQuery createIntersectSet( CriteriaQuery left, CriteriaQuery right) { assert operator == SetOperator.INTERSECT || operator == SetOperator.INTERSECT_ALL; - assert left instanceof SqmSelectStatement; - assert right instanceof SqmSelectStatement; final SqmSelectStatement leftSqm = (SqmSelectStatement) left; final SqmSelectStatement rightSqm = (SqmSelectStatement) right; @@ -744,8 +740,6 @@ private static JpaCriteriaQuery createExceptSet( CriteriaQuery left, CriteriaQuery right) { assert operator == SetOperator.EXCEPT || operator == SetOperator.EXCEPT_ALL; - assert left instanceof SqmSelectStatement; - assert right instanceof SqmSelectStatement; final SqmSelectStatement leftSqm = (SqmSelectStatement) left; final SqmSelectStatement rightSqm = (SqmSelectStatement) right; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmSelectionQueryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmSelectionQueryImpl.java index 65eb65212cae..07534f69c7a7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmSelectionQueryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmSelectionQueryImpl.java @@ -165,6 +165,9 @@ public SqmSelectionQueryImpl( this( criteria, session.isCriteriaCopyTreeEnabled(), expectedResultType, session ); } + /** + * Form used for criteria queries + */ public SqmSelectionQueryImpl( SqmSelectStatement criteria, boolean copyAst, @@ -173,27 +176,10 @@ public SqmSelectionQueryImpl( super( session ); this.expectedResultType = expectedResultType; hql = CRITERIA_HQL_STRING; - if ( copyAst ) { - sqm = criteria.copy( SqmCopyContext.simpleContext() ); - if ( session.isCriteriaPlanCacheEnabled() ) { - queryStringCacheKey = sqm.toHqlString(); - setQueryPlanCacheable( true ); - } - else { - queryStringCacheKey = sqm; - } - } - else { - sqm = criteria; - if ( session.isCriteriaPlanCacheEnabled() ) { - queryStringCacheKey = sqm.toHqlString(); - } - else { - queryStringCacheKey = sqm; - } - // Cache immutable query plans by default - setQueryPlanCacheable( true ); - } + sqm = copyAst ? criteria.copy( SqmCopyContext.simpleContext() ) : criteria; + queryStringCacheKey = sqm; + // Cache immutable query plans by default + setQueryPlanCacheable( !copyAst || session.isCriteriaPlanCacheEnabled() ); domainParameterXref = DomainParameterXref.from( sqm ); parameterMetadata = domainParameterXref.hasParameters() diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/SelectableMappingExpressionConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/SelectableMappingExpressionConverter.java index 1794d1b242d3..a3ab21896b84 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/SelectableMappingExpressionConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/SelectableMappingExpressionConverter.java @@ -20,7 +20,7 @@ /** * A function for producing an {@link Expression} from a {@link NavigablePath} for a {@link TableGroup} and {@link SelectableMapping}. */ -public class SelectableMappingExpressionConverter implements Function { +public class SelectableMappingExpressionConverter implements Function, Expression> { private final NavigablePath navigablePath; private final SelectableMapping selectableMapping; @@ -30,11 +30,11 @@ private SelectableMappingExpressionConverter(NavigablePath navigablePath, Select this.selectableMapping = selectableMapping; } - public static SqmSelection forSelectableMapping(SqmFrom from, SelectableMapping selectableMapping) { + public static SqmSelection forSelectableMapping(SqmFrom from, SelectableMapping selectableMapping) { return new SqmSelection<>( new SqmSelfRenderingExpression<>( new SelectableMappingExpressionConverter( from.getNavigablePath(), selectableMapping ), - (SqmExpressible) selectableMapping.getJdbcMapping(), + (SqmExpressible) selectableMapping.getJdbcMapping(), from.nodeBuilder() ), from.nodeBuilder() diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/SqmCreationHelper.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/SqmCreationHelper.java index 1ba493beea19..136150f0e9cf 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/SqmCreationHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/SqmCreationHelper.java @@ -6,6 +6,7 @@ import java.util.List; +import org.hibernate.Internal; import org.hibernate.metamodel.mapping.CollectionPart; import org.hibernate.metamodel.model.domain.PluralPersistentAttribute; import org.hibernate.query.criteria.JpaPredicate; @@ -23,6 +24,7 @@ /** * @author Steve Ebersole */ +@Internal public class SqmCreationHelper { /** @@ -39,17 +41,38 @@ public class SqmCreationHelper { private static final AtomicLong UNIQUE_ID_COUNTER = new AtomicLong(); public static NavigablePath buildRootNavigablePath(String base, String alias) { + // call to determineAlias() currently prevents caching certain plans return new NavigablePath( base, determineAlias( alias ) ); } public static NavigablePath buildSubNavigablePath(NavigablePath lhs, String base, String alias) { + // call to determineAlias() currently prevents caching certain plans return lhs.append( base, determineAlias( alias ) ); } + /** + * DO NOT USE ME + * + * @deprecated This method returns a globally-unique alias which + * introduces a temporal dependence in the query interpretation + * process, leading to misses on the query interpretation cache. + * Aliases only need to be unique in the scope of a given query, + * and so alias generation should be contextual to the query. + */ + @Deprecated(since = "7") public static String acquireUniqueAlias() { return Long.toString(UNIQUE_ID_COUNTER.incrementAndGet()); } + /** + * DO NOT USE ME + * + * @deprecated When the argument is null, this method returns a + * globally-unique alias which introduces a temporal dependence + * in the query interpretation process, leading to misses on the + * query interpretation cache. + */ + @Deprecated(since = "7") public static String determineAlias(String alias) { // Make sure we always create a unique alias, otherwise we might use a wrong table group for the same join if ( alias == null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmDmlStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmDmlStatement.java index ecedc7b2711a..72c9e60285bc 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmDmlStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmDmlStatement.java @@ -10,7 +10,6 @@ import org.hibernate.query.criteria.JpaRoot; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SqmQuerySource; -import org.hibernate.query.sqm.spi.SqmCreationHelper; import org.hibernate.query.sqm.tree.cte.SqmCteContainer; import org.hibernate.query.sqm.tree.cte.SqmCteStatement; import org.hibernate.query.sqm.tree.expression.SqmParameter; @@ -94,21 +93,21 @@ public JpaCteCriteria getCteCriteria(String cteName) { @Override public JpaCteCriteria with(AbstractQuery criteria) { - return withInternal( SqmCreationHelper.acquireUniqueAlias(), criteria ); + return withInternal( generateAlias(), criteria ); } @Override public JpaCteCriteria withRecursiveUnionAll( AbstractQuery baseCriteria, Function, AbstractQuery> recursiveCriteriaProducer) { - return withInternal( SqmCreationHelper.acquireUniqueAlias(), baseCriteria, false, recursiveCriteriaProducer ); + return withInternal( generateAlias(), baseCriteria, false, recursiveCriteriaProducer ); } @Override public JpaCteCriteria withRecursiveUnionDistinct( AbstractQuery baseCriteria, Function, AbstractQuery> recursiveCriteriaProducer) { - return withInternal( SqmCreationHelper.acquireUniqueAlias(), baseCriteria, true, recursiveCriteriaProducer ); + return withInternal( generateAlias(), baseCriteria, true, recursiveCriteriaProducer ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmRestrictedDmlStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmRestrictedDmlStatement.java index ee82efebd0c9..7a8a15f18a6b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmRestrictedDmlStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmRestrictedDmlStatement.java @@ -93,11 +93,9 @@ public SqmWhereClause getWhereClause() { } public void applyPredicate(SqmPredicate predicate) { - if ( predicate == null ) { - return; + if ( predicate != null ) { + initAndGetWhereClause().applyPredicate( predicate ); } - - initAndGetWhereClause().applyPredicate( predicate ); } public void setWhereClause(SqmWhereClause whereClause) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmStatement.java index b2306eeeb92d..b0f294d1b12c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmStatement.java @@ -4,7 +4,6 @@ */ package org.hibernate.query.sqm.tree; -import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; @@ -18,6 +17,8 @@ import jakarta.persistence.criteria.ParameterExpression; +import static java.util.Collections.emptySet; +import static java.util.Collections.unmodifiableSet; import static org.hibernate.query.sqm.tree.jpa.ParameterCollector.collectParameters; /** @@ -77,7 +78,7 @@ public Set> getSqmParameters() { return collectParameters( this ); } - return parameters == null ? Collections.emptySet() : Collections.unmodifiableSet( parameters ); + return parameters == null ? emptySet() : unmodifiableSet( parameters ); } @Override @@ -97,4 +98,11 @@ public Set> getParameters() { .filter( parameterExpression -> !( parameterExpression instanceof ValueBindJpaCriteriaParameter ) ) .collect( Collectors.toSet() ); } + + private int aliasCounter = 0; + + @Override + public String generateAlias() { + return "_" + (++aliasCounter); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/SqmQuery.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/SqmQuery.java index 83fb2f8e6ef6..c0fcfb17140a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/SqmQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/SqmQuery.java @@ -14,4 +14,6 @@ public interface SqmQuery extends JpaCriteriaBase, SqmNode { @Override SqmQuery copy(SqmCopyContext context); + + String generateAlias(); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteStatement.java index d2c8831ac838..c062545773fd 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteStatement.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.function.Function; import org.hibernate.query.criteria.JpaCteCriteria; @@ -339,12 +340,12 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { if ( getMaterialization() != CteMaterialization.UNDEFINED ) { hql.append( getMaterialization() ).append( ' ' ); } - if ( getCteDefinition() instanceof SqmSubQuery ) { - ( (SqmSubQuery) getCteDefinition() ).appendHqlString( hql, context ); + if ( getCteDefinition() instanceof SqmSubQuery subQuery ) { + subQuery.appendHqlString( hql, context ); } - else { + else if ( getCteDefinition() instanceof SqmSelectStatement selectStatement ) { hql.append( '(' ); - ( (SqmSelectStatement) getCteDefinition() ).appendHqlString( hql, context ); + selectStatement.appendHqlString( hql, context ); hql.append( ')' ); } String separator; @@ -404,4 +405,27 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { } } } + + @Override + public boolean equals(Object object) { + return object instanceof SqmCteStatement that + && Objects.equals( cteTable, that.cteTable ) + && Objects.equals( cteDefinition, that.cteDefinition ) + && materialization == that.materialization + && searchClauseKind == that.searchClauseKind + && Objects.equals( searchBySpecifications, that.searchBySpecifications ) + && Objects.equals( searchAttributeName, that.searchAttributeName ) + && Objects.equals( cycleAttributes, that.cycleAttributes ) + && Objects.equals( cycleMarkAttributeName, that.cycleMarkAttributeName ) + && Objects.equals( cyclePathAttributeName, that.cyclePathAttributeName ) + && Objects.equals( cycleValue, that.cycleValue ) + && Objects.equals( noCycleValue, that.noCycleValue ); + } + + @Override + public int hashCode() { + return Objects.hash( cteTable, cteDefinition, materialization, + searchClauseKind, searchBySpecifications, searchAttributeName, + cycleAttributes, cycleMarkAttributeName, cyclePathAttributeName, cycleValue, noCycleValue ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteTable.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteTable.java index fd2240744cc5..2ec6147c0de3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteTable.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteTable.java @@ -97,11 +97,11 @@ public SqmCteStatement getCteStatement() { @Override public String getName() { - if ( Character.isDigit( name.charAt( 0 ) ) ) { - // Created through JPA criteria without an explicit name - return null; - } - return name; + // TODO: this is extremely fragile! + // better to distinguish between generated and explicit aliases + return name.charAt( 0 ) == '_' + ? null // Created through JPA criteria without an explicit name + : name; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/delete/SqmDeleteStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/delete/SqmDeleteStatement.java index d83384b86210..60425e7989f6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/delete/SqmDeleteStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/delete/SqmDeleteStatement.java @@ -5,6 +5,7 @@ package org.hibernate.query.sqm.tree.delete; import java.util.Map; +import java.util.Objects; import java.util.Set; import org.hibernate.query.criteria.JpaCriteriaDelete; @@ -41,7 +42,7 @@ public SqmDeleteStatement(Class targetEntity, NodeBuilder nodeBuilder) { super( new SqmRoot<>( nodeBuilder.getDomainModel().entity( targetEntity ), - null, + "_0", !nodeBuilder.isJpaQueryComplianceEnabled(), nodeBuilder ), @@ -113,6 +114,20 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { super.appendHqlString( hql, context ); } + @Override + public boolean equals(Object node) { + return node instanceof SqmDeleteStatement that + && super.equals( node ) + && Objects.equals( this.getTarget(), that.getTarget() ) + && Objects.equals( this.getWhereClause(), that.getWhereClause() ) + && Objects.equals( this.getCteStatements(), that.getCteStatements() ); + } + + @Override + public int hashCode() { + return Objects.hash( super.hashCode(), getTarget(), getWhereClause(), getCteStatements() ); + } + @Override public Subquery subquery(EntityType type) { throw new UnsupportedOperationException( "DELETE query cannot be sub-query" ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmAttributeJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmAttributeJoin.java index 0a32d578733d..ac1129d4b781 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmAttributeJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmAttributeJoin.java @@ -21,6 +21,8 @@ import jakarta.persistence.criteria.JoinType; +import java.util.Objects; + /** * Models a join based on a mapped attribute reference. * @@ -91,11 +93,11 @@ public void clearFetched() { } private void validateFetchAlias(String alias) { - if ( fetchJoin && alias != null && nodeBuilder().isJpaQueryComplianceEnabled() ) { - throw new IllegalStateException( - "The JPA specification does not permit specifying an alias for fetch joins." - ); - } +// if ( fetchJoin && alias != null && nodeBuilder().isJpaQueryComplianceEnabled() ) { +// throw new IllegalStateException( +// "The JPA specification does not permit specifying an alias for fetch joins." +// ); +// } } @Override @@ -151,5 +153,16 @@ public JoinType getJoinType() { @Override public abstract SqmTreatedAttributeJoin treatAs(EntityDomainType treatTarget, String alias, boolean fetched); + @Override + public boolean equals(Object object) { + return object instanceof AbstractSqmAttributeJoin that + && super.equals( object ) + && this.implicitJoin == that.implicitJoin + && this.fetchJoin == that.fetchJoin; + } + @Override + public int hashCode() { + return Objects.hash( super.hashCode(), implicitJoin, fetchJoin ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmFrom.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmFrom.java index 5cedaf440b36..3a4fb2d4bdfc 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmFrom.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmFrom.java @@ -6,7 +6,6 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Objects; @@ -62,6 +61,8 @@ import jakarta.persistence.metamodel.SetAttribute; import jakarta.persistence.metamodel.SingularAttribute; +import static java.util.Collections.emptyList; +import static java.util.Collections.unmodifiableList; import static org.hibernate.query.sqm.internal.SqmUtil.findCompatibleFetchJoin; /** @@ -207,7 +208,12 @@ public boolean hasJoins() { @Override public List> getSqmJoins() { - return joins == null ? Collections.emptyList() : Collections.unmodifiableList( joins ); + return joins == null ? emptyList() : unmodifiableList( joins ); + } + + @Override + public int getNumberOfJoins() { + return joins == null ? 0 : joins.size(); } @Override @@ -222,13 +228,13 @@ public void addSqmJoin(SqmJoin join) { @Internal public void removeLeftFetchJoins() { if ( joins != null ) { - for ( SqmJoin join : new ArrayList<>(joins) ) { + for ( var join : new ArrayList<>( joins ) ) { if ( join instanceof SqmAttributeJoin attributeJoin ) { if ( attributeJoin.isFetched() ) { if ( join.getSqmJoinType() == SqmJoinType.LEFT ) { joins.remove( join ); - final List> orderedJoins = findRoot().getOrderedJoins(); - if (orderedJoins != null) { + final var orderedJoins = findRoot().getOrderedJoins(); + if ( orderedJoins != null ) { orderedJoins.remove( join ); } } @@ -250,12 +256,12 @@ public void visitSqmJoins(Consumer> consumer) { @Override public List> getSqmTreats() { - return treats == null ? Collections.emptyList() : treats; + return treats == null ? emptyList() : treats; } protected > X findTreat(ManagedDomainType targetType, String alias) { if ( treats != null ) { - for ( SqmFrom treat : treats ) { + for ( var treat : treats ) { if ( treat.getModel() == targetType ) { if ( Objects.equals( treat.getExplicitAlias(), alias ) ) { //noinspection unchecked @@ -341,7 +347,7 @@ public SqmEntityJoin join(EntityDomainType targetEntityDescriptor, final SqmRoot root = (SqmRoot) findRoot(); final SqmEntityJoin sqmEntityJoin = new SqmEntityJoin<>( targetEntityDescriptor, - null, + generateAlias(), joinType, root ); @@ -355,9 +361,12 @@ public SqmBagJoin join(CollectionAttribute attribute) { } @Override - @SuppressWarnings("unchecked") public SqmBagJoin join(CollectionAttribute attribute, JoinType jt) { - final SqmBagJoin join = buildBagJoin( (BagPersistentAttribute) attribute, SqmJoinType.from( jt ), false ); + final SqmBagJoin join = buildBagJoin( + (BagPersistentAttribute) attribute, + SqmJoinType.from( jt ), + false + ); addSqmJoin( join ); return join; } @@ -418,8 +427,8 @@ public SqmAttributeJoin join(String attributeName) { @Override @SuppressWarnings("unchecked") public SqmAttributeJoin join(String attributeName, JoinType jt) { - final SqmPathSource subPathSource = (SqmPathSource) getReferencedPathSource() - .getSubPathSource( attributeName ); + final SqmPathSource subPathSource = (SqmPathSource) + getReferencedPathSource().getSubPathSource( attributeName ); return (SqmAttributeJoin) buildJoin( subPathSource, SqmJoinType.from( jt ), false ); } @@ -565,40 +574,42 @@ public SqmEntityJoin join(Class entityJavaType, JoinType joinType) @Override public SqmEntityJoin join(EntityType entity, JoinType joinType) { //noinspection unchecked - final SqmEntityJoin join = new SqmEntityJoin<>( entity, null, joinType, (SqmRoot) findRoot() ); + final SqmEntityJoin join = + new SqmEntityJoin<>( entity, generateAlias(), joinType, (SqmRoot) findRoot() ); addSqmJoin( join ); return join; } @Override public JpaDerivedJoin join(Subquery subquery) { - return join( subquery, SqmJoinType.INNER, false, null ); + return join( subquery, SqmJoinType.INNER, false, generateAlias() ); } @Override public JpaDerivedJoin join(Subquery subquery, SqmJoinType joinType) { - return join( subquery, joinType, false, null ); + return join( subquery, joinType, false, generateAlias() ); } @Override public JpaDerivedJoin joinLateral(Subquery subquery) { - return join( subquery, SqmJoinType.INNER, true, null ); + return join( subquery, SqmJoinType.INNER, true, generateAlias() ); } @Override public JpaDerivedJoin joinLateral(Subquery subquery, SqmJoinType joinType) { - return join( subquery, joinType, true, null ); + return join( subquery, joinType, true, generateAlias() ); } @Override public JpaDerivedJoin join(Subquery subquery, SqmJoinType joinType, boolean lateral) { - return join( subquery, joinType, lateral, null ); + return join( subquery, joinType, lateral, generateAlias() ); } public JpaDerivedJoin join(Subquery subquery, SqmJoinType joinType, boolean lateral, String alias) { validateComplianceFromSubQuery(); //noinspection unchecked - final JpaDerivedJoin join = new SqmDerivedJoin<>( (SqmSubQuery) subquery, alias, joinType, lateral, (SqmRoot) findRoot() ); + final JpaDerivedJoin join = + new SqmDerivedJoin<>( (SqmSubQuery) subquery, alias, joinType, lateral, (SqmRoot) findRoot() ); //noinspection unchecked addSqmJoin( (SqmJoin) join ); return join; @@ -606,18 +617,19 @@ public JpaDerivedJoin join(Subquery subquery, SqmJoinType joinType, bo @Override public SqmJoin join(JpaCteCriteria cte) { - return join( cte, SqmJoinType.INNER, null ); + return join( cte, SqmJoinType.INNER, generateAlias() ); } @Override public SqmJoin join(JpaCteCriteria cte, SqmJoinType joinType) { - return join( cte, joinType, null ); + return join( cte, joinType, generateAlias() ); } public SqmJoin join(JpaCteCriteria cte, SqmJoinType joinType, String alias) { validateComplianceFromSubQuery(); //noinspection unchecked - final SqmJoin join = new SqmCteJoin<>( ( SqmCteStatement ) cte, alias, joinType, (SqmRoot) findRoot() ); + final SqmJoin join = + new SqmCteJoin<>( ( SqmCteStatement ) cte, alias, joinType, (SqmRoot) findRoot() ); //noinspection unchecked addSqmJoin( (SqmJoin) join ); return join; @@ -647,7 +659,13 @@ public JpaFunctionJoin join(JpaSetReturningFunction function) { public JpaFunctionJoin join(JpaSetReturningFunction function, SqmJoinType joinType, boolean lateral) { validateComplianceFromFunction(); //noinspection unchecked - final SqmFunctionJoin join = new SqmFunctionJoin<>( (SqmSetReturningFunction) function, alias, joinType, lateral, (SqmRoot) findRoot() ); + final SqmFunctionJoin join = + new SqmFunctionJoin<>( + (SqmSetReturningFunction) function, + generateAlias(), + joinType, lateral, + (SqmRoot) findRoot() + ); //noinspection unchecked addSqmJoin( (SqmJoin) join ); return join; @@ -698,16 +716,16 @@ public JpaFunctionJoin joinArrayCollection( private void validateComplianceFromSubQuery() { if ( nodeBuilder().isJpaQueryComplianceEnabled() ) { throw new IllegalStateException( - "The JPA specification does not support subqueries in the from clause. " + - "Please disable the JPA query compliance if you want to use this feature." ); + "The JPA specification does not support subqueries in the from clause. " + + "Please disable the JPA query compliance if you want to use this feature." ); } } private void validateComplianceFromFunction() { if ( nodeBuilder().isJpaQueryComplianceEnabled() ) { throw new IllegalStateException( - "The JPA specification does not support functions in the from clause. " + - "Please disable the JPA query compliance if you want to use this feature." ); + "The JPA specification does not support functions in the from clause. " + + "Please disable the JPA query compliance if you want to use this feature." ); } } @@ -719,7 +737,7 @@ public JpaCrossJoin crossJoin(Class entityJavaType) { @Override public JpaCrossJoin crossJoin(EntityDomainType entity) { final SqmCrossJoin crossJoin = - new SqmCrossJoin<>( (SqmEntityDomainType) entity, null, findRoot() ); + new SqmCrossJoin<>( (SqmEntityDomainType) entity, generateAlias(), findRoot() ); // noinspection unchecked addSqmJoin( (SqmJoin) crossJoin ); return crossJoin; @@ -741,8 +759,7 @@ public SqmSingularJoin fetch(SingularAttribute attribute) @Override public SqmSingularJoin fetch(SingularAttribute attribute, JoinType jt) { - final SqmSingularPersistentAttribute persistentAttribute = - (SqmSingularPersistentAttribute) attribute; + final var persistentAttribute = (SqmSingularPersistentAttribute) attribute; final SqmAttributeJoin compatibleFetchJoin = findCompatibleFetchJoin( this, persistentAttribute, SqmJoinType.from( jt ) ); if ( compatibleFetchJoin != null ) { @@ -841,7 +858,7 @@ private SqmSingularJoin buildSingularJoin( return new SqmSingularJoin<>( this, attribute, - null, + generateAlias(), joinType, fetched, nodeBuilder() @@ -858,7 +875,7 @@ private SqmBagJoin buildBagJoin( return new SqmBagJoin<>( this, (SqmBagPersistentAttribute) attribute, - null, + generateAlias(), joinType, fetched, nodeBuilder() @@ -872,7 +889,7 @@ private SqmListJoin buildListJoin( return new SqmListJoin<>( this, (SqmListPersistentAttribute) attribute, - null, + generateAlias(), joinType, fetched, nodeBuilder() @@ -886,7 +903,7 @@ private SqmMapJoin buildMapJoin( return new SqmMapJoin<>( this, (SqmMapPersistentAttribute) attribute, - null, + generateAlias(), joinType, fetched, nodeBuilder() @@ -900,7 +917,7 @@ private SqmSetJoin buildSetJoin( return new SqmSetJoin<>( this, (SqmSetPersistentAttribute) attribute, - null, + generateAlias(), joinType, fetched, nodeBuilder() @@ -949,4 +966,10 @@ public JpaSelection alias(String name) { } return super.alias( name ); } + + private int aliasCounter = 0; + + private String generateAlias() { + return alias + "_" + (++aliasCounter); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmJoin.java index 861d9f5e16ac..4bb17f0545e6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmJoin.java @@ -21,6 +21,8 @@ import jakarta.persistence.criteria.JoinType; import jakarta.persistence.criteria.Predicate; +import java.util.Objects; + /** * @author Steve Ebersole */ @@ -151,4 +153,17 @@ public SqmEntityJoin join(Class targetEntityClass) { public SqmEntityJoin join(Class targetEntityClass, SqmJoinType joinType) { return super.join( targetEntityClass, joinType ); } + + @Override + public boolean equals(Object object) { + return object instanceof AbstractSqmJoin that + && super.equals( object ) + && this.joinType == that.joinType; // unnecessary, but harmless +// && Objects.equals( onClausePredicate, that.onClausePredicate ); // including this causes problems + } + + @Override + public int hashCode() { + return Objects.hash( super.hashCode(), joinType ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPath.java index 0a1c37fd9e32..a2a1174a19b0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPath.java @@ -6,10 +6,10 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Consumer; import org.hibernate.AssertionFailure; @@ -34,6 +34,7 @@ import jakarta.persistence.metamodel.PluralAttribute; import jakarta.persistence.metamodel.SingularAttribute; +import static java.util.Collections.emptyList; import static org.hibernate.internal.util.NullnessUtil.castNonNull; /** @@ -45,8 +46,8 @@ public abstract class AbstractSqmPath extends AbstractSqmExpression implem /** * For HQL and Criteria processing - used to track reusable paths relative to this path. - * E.g., given `p.mate.mate` the SqmRoot identified by `p` would - * have a reusable path for the `p.mate` path. + * E.g., given {@code p.mate.mate} the {@code SqmRoot} identified by {@code p} would + * have a reusable path for the {@code p.mate} path. */ private Map> reusablePaths; @@ -99,11 +100,8 @@ public SqmPath getLhs() { @Override public List> getReusablePaths() { - if ( reusablePaths == null ) { - return Collections.emptyList(); - } + return reusablePaths == null ? emptyList() : new ArrayList<>( reusablePaths.values() ); - return new ArrayList<>( reusablePaths.values() ); } @Override @@ -131,10 +129,7 @@ public void registerReusablePath(SqmPath path) { @Override public SqmPath getReusablePath(String name) { - if ( reusablePaths == null ) { - return null; - } - return reusablePaths.get( name ); + return reusablePaths == null ? null : reusablePaths.get( name ); } @Override @@ -335,6 +330,22 @@ public > SqmExpression get(MapAttribute) attribute ); } + @Override + public boolean equals(Object object) { + return object instanceof AbstractSqmPath that + && this.getClass() == that.getClass() + && Objects.equals( this.navigablePath, that.navigablePath ) + && Objects.equals( this.getExplicitAlias(), that.getExplicitAlias() ); +// && Objects.equals( this.lhs, that.lhs ); + } + + @Override + public int hashCode() { + return Objects.hash( navigablePath, getExplicitAlias() ); +// return lhs == null ? 0 : lhs.hashCode(); +// return navigablePath.hashCode(); +// return Objects.hash( navigablePath, lhs ); + } @Override public String toString() { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmSimplePath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmSimplePath.java index 2fcda0050a96..e74155f437cd 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmSimplePath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmSimplePath.java @@ -9,6 +9,7 @@ import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SqmPathSource; + /** * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCteRoot.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCteRoot.java index df5defc533f9..fc86420ec565 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCteRoot.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCteRoot.java @@ -14,6 +14,8 @@ import org.hibernate.query.sqm.tree.from.SqmRoot; import org.hibernate.spi.NavigablePath; +import java.util.Objects; + /** * @author Christian Beikov */ @@ -99,4 +101,16 @@ public SqmPathSource getResolvedModel() { public SqmCorrelatedRoot createCorrelation() { throw new UnsupportedOperationException(); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmCteRoot that + && super.equals( object ) + && Objects.equals( this.cte, that.cte ); + } + + @Override + public int hashCode() { + return Objects.hash( super.hashCode(), cte ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmDerivedRoot.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmDerivedRoot.java index 316088534271..44015c20312e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmDerivedRoot.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmDerivedRoot.java @@ -17,6 +17,8 @@ import org.hibernate.query.sqm.tree.select.SqmSubQuery; import org.hibernate.spi.NavigablePath; +import java.util.Objects; + /** * @author Christian Beikov */ @@ -123,4 +125,16 @@ public SqmTreatedRoot treatAs(Class treatJavaType, String alias public SqmTreatedRoot treatAs(EntityDomainType treatTarget, String alias) { throw new UnsupportedOperationException( "Derived roots can not be treated" ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmDerivedRoot that + && super.equals( object ) + && Objects.equals( this.subQuery, that.subQuery ); + } + + @Override + public int hashCode() { + return Objects.hash( super.hashCode(), subQuery ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmElementAggregateFunction.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmElementAggregateFunction.java index 6bc793795c46..f730970373bf 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmElementAggregateFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmElementAggregateFunction.java @@ -5,6 +5,7 @@ package org.hibernate.query.sqm.tree.domain; import java.util.List; +import java.util.Objects; import org.hibernate.metamodel.model.domain.PluralPersistentAttribute; import org.hibernate.metamodel.model.domain.ReturnableType; @@ -114,8 +115,21 @@ public X accept(SemanticQueryWalker walker) { @Override public void appendHqlString(StringBuilder hql, SqmRenderContext context) { - hql.append(functionName).append( "(" ); + hql.append( functionName ).append( "(" ); getLhs().appendHqlString( hql, context ); hql.append( ')' ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmElementAggregateFunction that + && Objects.equals( this.functionName, that.functionName ) + && Objects.equals( this.getExplicitAlias(), that.getExplicitAlias() ) + && Objects.equals( this.getLhs(), that.getLhs() ); + } + + @Override + public int hashCode() { + return Objects.hash( getLhs(), functionName ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmFkExpression.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmFkExpression.java index 5ba4960ff4ac..d53bb6698ef0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmFkExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmFkExpression.java @@ -16,6 +16,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.spi.NavigablePath; +import java.util.Objects; + /** * Reference to the key-side (as opposed to the target-side) of the * foreign-key of a to-one association. @@ -61,6 +63,18 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( ')' ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmFkExpression that + && Objects.equals( this.getExplicitAlias(), that.getExplicitAlias() ) + && Objects.equals( this.getLhs(), that.getLhs() ); + } + + @Override + public int hashCode() { + return getLhs().hashCode(); + } + @Override public SqmFkExpression copy(SqmCopyContext context) { final SqmFkExpression existing = context.getCopy( this ); @@ -70,7 +84,7 @@ public SqmFkExpression copy(SqmCopyContext context) { final SqmEntityValuedSimplePath lhsCopy = (SqmEntityValuedSimplePath) getLhs().copy( context ); return context.registerCopy( this, - new SqmFkExpression( getNavigablePathCopy( lhsCopy ), lhsCopy ) + new SqmFkExpression<>( getNavigablePathCopy( lhsCopy ), lhsCopy ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmFunctionPath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmFunctionPath.java index cb4692fe51c5..94505bd34aee 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmFunctionPath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmFunctionPath.java @@ -29,6 +29,8 @@ import jakarta.persistence.metamodel.ManagedType; import jakarta.persistence.metamodel.Type; +import java.util.Objects; + import static java.util.Arrays.asList; public class SqmFunctionPath extends AbstractSqmPath { @@ -160,4 +162,16 @@ public SqmTreatedPath treatAs(Class treatJavaType) { public SqmTreatedPath treatAs(EntityDomainType treatTarget) { throw new TreatException( "Embeddable paths cannot be TREAT-ed" ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmFunctionPath that + && super.equals( object ) + && Objects.equals( function, that.function ); + } + + @Override + public int hashCode() { + return Objects.hash( super.hashCode(), function ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmFunctionRoot.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmFunctionRoot.java index 3bc7b2f28a90..7e399744aa4d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmFunctionRoot.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmFunctionRoot.java @@ -17,6 +17,8 @@ import org.hibernate.query.sqm.tree.from.SqmRoot; import org.hibernate.spi.NavigablePath; +import java.util.Objects; + /** * @author Christian Beikov @@ -139,4 +141,16 @@ public SqmTreatedRoot treatAs(Class treatJavaType, String alias public SqmTreatedRoot treatAs(EntityDomainType treatTarget, String alias, boolean fetch) { throw new UnsupportedOperationException( "Function roots can not be treated" ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmFunctionRoot that + && super.equals( object ) + && Objects.equals( this.function, that.function ); + } + + @Override + public int hashCode() { + return Objects.hash( super.hashCode(), function ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmIndexAggregateFunction.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmIndexAggregateFunction.java index c2e785471680..d28ba7b7829e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmIndexAggregateFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmIndexAggregateFunction.java @@ -5,6 +5,7 @@ package org.hibernate.query.sqm.tree.domain; import java.util.List; +import java.util.Objects; import org.hibernate.metamodel.mapping.CollectionPart; import org.hibernate.metamodel.model.domain.ReturnableType; @@ -118,8 +119,23 @@ public X accept(SemanticQueryWalker walker) { @Override public void appendHqlString(StringBuilder hql, SqmRenderContext context) { - hql.append(functionName).append( "(" ); + hql.append( functionName ).append( "(" ); getLhs().appendHqlString( hql, context ); hql.append( ')' ); } + + + @Override + public boolean equals(Object object) { + return object instanceof SqmIndexAggregateFunction that + && Objects.equals( this.functionName, that.functionName ) + && Objects.equals( this.getExplicitAlias(), that.getExplicitAlias() ) + && Objects.equals( this.getLhs(), that.getLhs() ); + + } + + @Override + public int hashCode() { + return Objects.hash( getLhs(), functionName ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmIndexedCollectionAccessPath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmIndexedCollectionAccessPath.java index f11205be63c3..b5edfcc480a9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmIndexedCollectionAccessPath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmIndexedCollectionAccessPath.java @@ -14,6 +14,8 @@ import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.expression.SqmExpression; +import java.util.Objects; + /** * @author Steve Ebersole */ @@ -99,4 +101,17 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { selectorExpression.appendHqlString( hql, context ); hql.append( ']' ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmIndexedCollectionAccessPath that + && Objects.equals( this.getExplicitAlias(), that.getExplicitAlias() ) + && Objects.equals( this.getLhs(), that.getLhs() ) + && Objects.equals( this.selectorExpression, that.selectorExpression ); + } + + @Override + public int hashCode() { + return Objects.hash( getLhs(), selectorExpression ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMapEntryReference.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMapEntryReference.java index 328c0db73493..38a9f18e24e8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMapEntryReference.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMapEntryReference.java @@ -4,12 +4,8 @@ */ package org.hibernate.query.sqm.tree.domain; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; - +import jakarta.persistence.criteria.Expression; +import jakarta.persistence.criteria.Predicate; import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SemanticQueryWalker; @@ -19,8 +15,12 @@ import org.hibernate.query.sqm.tree.select.SqmSelectableNode; import org.hibernate.type.descriptor.java.JavaType; -import jakarta.persistence.criteria.Expression; -import jakarta.persistence.criteria.Predicate; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; /** @@ -140,6 +140,18 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( ')' ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmMapEntryReference that + && Objects.equals( mapPath, that.mapPath ) + && Objects.equals( explicitAlias, that.explicitAlias ); + } + + @Override + public int hashCode() { + return Objects.hash( mapPath, explicitAlias ); + } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // JPA (ugh) diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedBagJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedBagJoin.java index aa9428a2b761..b85605b239ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedBagJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedBagJoin.java @@ -17,6 +17,8 @@ import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Predicate; +import java.util.Objects; + /** * @author Steve Ebersole */ @@ -126,6 +128,19 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( ')' ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmTreatedBagJoin that + && Objects.equals( this.getExplicitAlias(), that.getExplicitAlias() ) + && Objects.equals( this.treatTarget.getTypeName(), that.treatTarget.getTypeName() ) + && Objects.equals( this.wrappedPath.getNavigablePath(), that.wrappedPath.getNavigablePath() ); + } + + @Override + public int hashCode() { + return Objects.hash( treatTarget.getTypeName(), wrappedPath.getNavigablePath() ); + } + @Override public SqmTreatedBagJoin on(JpaExpression restriction) { return (SqmTreatedBagJoin) super.on( restriction ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedCrossJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedCrossJoin.java index 53030e3db6f5..97e6c1f17782 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedCrossJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedCrossJoin.java @@ -11,6 +11,8 @@ import org.hibernate.query.sqm.tree.from.SqmCrossJoin; import org.hibernate.spi.NavigablePath; +import java.util.Objects; + /** * A TREAT form of {@linkplain SqmCrossJoin} * @@ -99,6 +101,19 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( ')' ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmTreatedCrossJoin that + && Objects.equals( this.getExplicitAlias(), that.getExplicitAlias() ) + && Objects.equals( this.treatTarget.getName(), that.treatTarget.getName() ) + && Objects.equals( this.wrappedPath.getNavigablePath(), that.wrappedPath.getNavigablePath() ); + } + + @Override + public int hashCode() { + return Objects.hash( treatTarget.getName(), wrappedPath.getNavigablePath() ); + } + @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public SqmTreatedCrossJoin treatAs(Class treatJavaType, String alias) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEmbeddedValuedSimplePath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEmbeddedValuedSimplePath.java index 52e6aa4409af..aa165aa558a9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEmbeddedValuedSimplePath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEmbeddedValuedSimplePath.java @@ -11,6 +11,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.spi.NavigablePath; +import java.util.Objects; + /** * @author Steve Ebersole */ @@ -116,4 +118,17 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( treatTarget.getTypeName() ); hql.append( ')' ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmTreatedEmbeddedValuedSimplePath that + && Objects.equals( this.getExplicitAlias(), that.getExplicitAlias() ) + && Objects.equals( this.treatTarget.getTypeName(), that.treatTarget.getTypeName() ) + && Objects.equals( this.wrappedPath.getNavigablePath(), that.wrappedPath.getNavigablePath() ); + } + + @Override + public int hashCode() { + return Objects.hash( treatTarget.getTypeName(), wrappedPath.getNavigablePath() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEntityJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEntityJoin.java index a044b2f49f60..c72f7f845cff 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEntityJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEntityJoin.java @@ -11,6 +11,8 @@ import org.hibernate.query.sqm.tree.from.SqmEntityJoin; import org.hibernate.spi.NavigablePath; +import java.util.Objects; + /** * @author Steve Ebersole */ @@ -104,4 +106,18 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( treatTarget.getName() ); hql.append( ')' ); } + + + @Override + public boolean equals(Object object) { + return object instanceof SqmTreatedEntityJoin that + && Objects.equals( this.getExplicitAlias(), that.getExplicitAlias() ) + && Objects.equals( this.treatTarget.getName(), that.treatTarget.getName() ) + && Objects.equals( this.wrappedPath.getNavigablePath(), that.wrappedPath.getNavigablePath() ); + } + + @Override + public int hashCode() { + return Objects.hash( treatTarget.getName(), wrappedPath.getNavigablePath() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEntityValuedSimplePath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEntityValuedSimplePath.java index de89aaee56fd..32260007422d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEntityValuedSimplePath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEntityValuedSimplePath.java @@ -12,6 +12,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.spi.NavigablePath; +import java.util.Objects; + /** * @author Steve Ebersole */ @@ -141,4 +143,17 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( treatTarget.getName() ); hql.append( ')' ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmTreatedEntityValuedSimplePath that + && Objects.equals( this.getExplicitAlias(), that.getExplicitAlias() ) + && Objects.equals( this.treatTarget.getTypeName(), that.treatTarget.getTypeName() ) + && Objects.equals( this.wrappedPath.getNavigablePath(), that.wrappedPath.getNavigablePath() ); + } + + @Override + public int hashCode() { + return Objects.hash( treatTarget.getTypeName(), wrappedPath.getNavigablePath() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedListJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedListJoin.java index b81825f3b191..08f6917f5986 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedListJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedListJoin.java @@ -19,6 +19,8 @@ import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Predicate; +import java.util.Objects; + /** * @author Steve Ebersole */ @@ -156,4 +158,17 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( treatTarget.getTypeName() ); hql.append( ')' ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmTreatedListJoin that + && Objects.equals( this.getExplicitAlias(), that.getExplicitAlias() ) + && Objects.equals( this.treatTarget.getTypeName(), that.treatTarget.getTypeName() ) + && Objects.equals( this.wrappedPath.getNavigablePath(), that.wrappedPath.getNavigablePath() ); + } + + @Override + public int hashCode() { + return Objects.hash( treatTarget.getTypeName(), wrappedPath.getNavigablePath() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedMapJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedMapJoin.java index 7f825fd1625b..d914bcd7ba20 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedMapJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedMapJoin.java @@ -18,6 +18,8 @@ import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Predicate; +import java.util.Objects; + /** * @author Steve Ebersole */ @@ -165,4 +167,17 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( treatTarget.getTypeName() ); hql.append( ')' ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmTreatedMapJoin that + && Objects.equals( this.getExplicitAlias(), that.getExplicitAlias() ) + && Objects.equals( this.treatTarget.getTypeName(), that.treatTarget.getTypeName() ) + && Objects.equals( this.wrappedPath.getNavigablePath(), that.wrappedPath.getNavigablePath() ); + } + + @Override + public int hashCode() { + return Objects.hash( treatTarget.getTypeName(), wrappedPath.getNavigablePath() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedPluralPartJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedPluralPartJoin.java index ce7826659fb1..8e50dde97c98 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedPluralPartJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedPluralPartJoin.java @@ -10,6 +10,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.spi.NavigablePath; +import java.util.Objects; + /** * @author Steve Ebersole */ @@ -134,8 +136,6 @@ public SqmTreatedPluralPartJoin treatAs(EntityDomainType treatTarget, String ali return super.treatAs( treatTarget, alias, fetch ); } - - @Override public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( "treat(" ); @@ -144,4 +144,18 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( treatTarget.getName() ); hql.append( ')' ); } + + + @Override + public boolean equals(Object object) { + return object instanceof SqmTreatedPluralPartJoin that + && Objects.equals( this.getExplicitAlias(), that.getExplicitAlias() ) + && Objects.equals( this.treatTarget.getName(), that.treatTarget.getName() ) + && Objects.equals( this.wrappedPath.getNavigablePath(), that.wrappedPath.getNavigablePath() ); + } + + @Override + public int hashCode() { + return Objects.hash( treatTarget.getName(), wrappedPath.getNavigablePath() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedRoot.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedRoot.java index f0c84989ebc9..084a4f2392d6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedRoot.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedRoot.java @@ -13,6 +13,8 @@ import org.hibernate.query.sqm.tree.from.SqmRoot; import org.hibernate.spi.NavigablePath; +import java.util.Objects; + /** * @author Steve Ebersole */ @@ -37,7 +39,7 @@ public SqmTreatedRoot( this.treatTarget = treatTarget; } - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings("unchecked") private SqmTreatedRoot( NavigablePath navigablePath, SqmRoot wrappedPath, @@ -124,4 +126,17 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( treatTarget.getName() ); hql.append( ')' ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmTreatedRoot that + && Objects.equals( this.getExplicitAlias(), that.getExplicitAlias() ) + && Objects.equals( this.treatTarget.getName(), that.treatTarget.getName() ) + && Objects.equals( this.wrappedPath.getNavigablePath(), that.wrappedPath.getNavigablePath() ); + } + + @Override + public int hashCode() { + return Objects.hash( wrappedPath.getNavigablePath(), treatTarget.getName() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSetJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSetJoin.java index 061a3280e781..5937da38751b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSetJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSetJoin.java @@ -17,6 +17,8 @@ import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Predicate; +import java.util.Objects; + /** * @author Steve Ebersole */ @@ -126,6 +128,19 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( ')' ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmTreatedSetJoin that + && Objects.equals( this.getExplicitAlias(), that.getExplicitAlias() ) + && Objects.equals( this.treatTarget.getTypeName(), that.treatTarget.getTypeName() ) + && Objects.equals( this.wrappedPath.getNavigablePath(), that.wrappedPath.getNavigablePath() ); + } + + @Override + public int hashCode() { + return Objects.hash( treatTarget.getTypeName(), wrappedPath.getNavigablePath() ); + } + @Override public SqmTreatedSetJoin on(JpaExpression restriction) { return (SqmTreatedSetJoin) super.on( restriction ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSimplePath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSimplePath.java index 462fc821a5c0..47f6e812b32d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSimplePath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSimplePath.java @@ -12,6 +12,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.spi.NavigablePath; +import java.util.Objects; + /** * @author Steve Ebersole */ @@ -142,4 +144,17 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( treatTarget.getName() ); hql.append( ')' ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmTreatedSimplePath that + && Objects.equals( this.getExplicitAlias(), that.getExplicitAlias() ) + && Objects.equals( this.treatTarget.getName(), that.treatTarget.getName() ) + && Objects.equals( this.wrappedPath.getNavigablePath(), that.wrappedPath.getNavigablePath() ); + } + + @Override + public int hashCode() { + return Objects.hash( treatTarget.getName(), wrappedPath.getNavigablePath() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSingularJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSingularJoin.java index 68e95ea646ee..6f4b8fde08a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSingularJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSingularJoin.java @@ -17,6 +17,8 @@ import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Predicate; +import java.util.Objects; + /** * @author Steve Ebersole */ @@ -129,6 +131,19 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( ')' ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmTreatedSingularJoin that + && Objects.equals( this.getExplicitAlias(), that.getExplicitAlias() ) + && Objects.equals( this.treatTarget.getTypeName(), that.treatTarget.getTypeName() ) + && Objects.equals( this.wrappedPath.getNavigablePath(), that.wrappedPath.getNavigablePath() ); + } + + @Override + public int hashCode() { + return Objects.hash( treatTarget.getTypeName(), wrappedPath.getNavigablePath() ); + } + @Override public SqmTreatedSingularJoin treatAs(Class treatJavaType) { return (SqmTreatedSingularJoin) super.treatAs( treatJavaType ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/AsWrapperSqmExpression.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/AsWrapperSqmExpression.java index e9278c3fda66..f156529b5b33 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/AsWrapperSqmExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/AsWrapperSqmExpression.java @@ -10,6 +10,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.type.BasicType; +import java.util.Objects; + public class AsWrapperSqmExpression extends AbstractSqmExpression { private final SqmExpression expression; @@ -50,4 +52,15 @@ public SqmExpression getExpression() { public BasicType getNodeType() { return (BasicType) super.getNodeType(); } + + @Override + public boolean equals(Object object) { + return object instanceof AsWrapperSqmExpression that + && Objects.equals( this.expression, that.expression ); + } + + @Override + public int hashCode() { + return Objects.hashCode( expression ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/JpaCriteriaParameter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/JpaCriteriaParameter.java index d6f6e7eec1a9..af5d1e28b858 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/JpaCriteriaParameter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/JpaCriteriaParameter.java @@ -4,8 +4,6 @@ */ package org.hibernate.query.sqm.tree.expression; -import java.util.Objects; - import org.hibernate.procedure.spi.NamedCallableQueryMemento; import org.hibernate.query.BindableType; import org.hibernate.query.ParameterMetadata; @@ -17,6 +15,8 @@ import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmRenderContext; +import java.util.Objects; + /** * {@link JpaParameterExpression} created via JPA {@link jakarta.persistence.criteria.CriteriaBuilder}. *

@@ -140,39 +140,33 @@ public NamedCallableQueryMemento.ParameterMemento toMemento() { @Override public void appendHqlString(StringBuilder hql, SqmRenderContext context) { - if ( getName() == null ) { - hql.append( ':' ).append( context.resolveParameterName( this ) ); - } - else { - hql.append( ':' ).append( getName() ); - } + hql.append( ':' ).append( name( context ) ); + } + + private String name(SqmRenderContext context) { + return name == null ? context.resolveParameterName( this ) : name; } @Override - public boolean equals(Object o) { - if ( this == o ) { - return true; - } - else if ( o == null ) { - return false; - } - else if ( !(o instanceof JpaCriteriaParameter that) ) { - return false; - } - else { - return Objects.equals( name, that.name ); - } + public int compareTo(SqmParameter parameter) { + return parameter instanceof JpaCriteriaParameter + ? Integer.compare( hashCode(), parameter.hashCode() ) + : 1; } + // we can use value equality if the parameter has a name + // otherwise we must fall back to identity equality + @Override - public int hashCode() { - return name == null ? super.hashCode() : Objects.hash( name ); + public boolean equals(Object object) { + return this == object + || object instanceof JpaCriteriaParameter that + && this.name != null && that.name != null + && Objects.equals( this.name, that.name ); } @Override - public int compareTo(SqmParameter anotherParameter) { - return anotherParameter instanceof JpaCriteriaParameter - ? Integer.compare( hashCode(), anotherParameter.hashCode() ) - : 1; + public int hashCode() { + return name == null ? super.hashCode() : name.hashCode(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmAliasedNodeRef.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmAliasedNodeRef.java index 2b6a200ba16f..04725cf3dae3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmAliasedNodeRef.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmAliasedNodeRef.java @@ -11,6 +11,8 @@ import org.hibernate.query.sqm.SqmExpressible; import org.hibernate.query.sqm.tree.SqmCopyContext; +import java.util.Objects; + /** * Models a reference to a {@link org.hibernate.query.sqm.tree.select.SqmAliasedNode} * used in the order-by or group-by clause by either position or alias, @@ -79,4 +81,17 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( navigablePath.getLocalName() ); } } + + @Override + public boolean equals(Object object) { + return object instanceof SqmAliasedNodeRef that + && position == that.position + && Objects.equals( navigablePath == null ? null : navigablePath.getLocalName(), + that.navigablePath == null ? null : that.navigablePath.getLocalName() ); + } + + @Override + public int hashCode() { + return Objects.hash( position, navigablePath == null ? null : navigablePath.getLocalName() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmAny.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmAny.java index 8b04cb11a358..79b48a58c20b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmAny.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmAny.java @@ -13,6 +13,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import java.util.Objects; + /** * @author Gavin King */ @@ -67,4 +69,14 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { subquery.appendHqlString( hql, context ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmAny sqmAny + && Objects.equals( subquery, sqmAny.subquery ); + } + + @Override + public int hashCode() { + return subquery.hashCode(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmAnyDiscriminatorValue.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmAnyDiscriminatorValue.java index b420692f5242..0ee0b6b5892b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmAnyDiscriminatorValue.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmAnyDiscriminatorValue.java @@ -16,6 +16,8 @@ import org.hibernate.query.sqm.tree.select.SqmSelectableNode; import org.hibernate.type.BasicType; +import java.util.Objects; + public class SqmAnyDiscriminatorValue extends AbstractSqmExpression implements SqmSelectableNode, SemanticPathPart { @@ -95,4 +97,16 @@ public SqmPath resolveIndexedAccess( public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( getEntityValue().getName() ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmAnyDiscriminatorValue that + && Objects.equals( this.value.getName(), that.value.getName() ) + && Objects.equals( this.pathName, that.pathName ); + } + + @Override + public int hashCode() { + return Objects.hash( value.getName(), pathName ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmBinaryArithmetic.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmBinaryArithmetic.java index ded2dfa1c4e6..4a0190e92a45 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmBinaryArithmetic.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmBinaryArithmetic.java @@ -13,6 +13,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.query.sqm.tree.select.SqmSelectableNode; +import java.util.Objects; + import static org.hibernate.query.sqm.BinaryArithmeticOperator.ADD; import static org.hibernate.query.sqm.BinaryArithmeticOperator.SUBTRACT; import static org.hibernate.type.spi.TypeConfiguration.isDuration; @@ -143,4 +145,16 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { rhsOperand.appendHqlString( hql, context ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmBinaryArithmetic that + && this.operator == that.operator + && Objects.equals( this.lhsOperand, that.lhsOperand ) + && Objects.equals( this.rhsOperand, that.rhsOperand ); + } + + @Override + public int hashCode() { + return Objects.hash( lhsOperand, rhsOperand, operator ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmByUnit.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmByUnit.java index 5e06d4429808..89a27477e08c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmByUnit.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmByUnit.java @@ -10,6 +10,8 @@ import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmRenderContext; +import java.util.Objects; + /** * @author Gavin King */ @@ -20,7 +22,7 @@ public class SqmByUnit extends AbstractSqmExpression { public SqmByUnit( SqmDurationUnit unit, SqmExpression duration, - SqmExpressible longType, + SqmExpressible longType, NodeBuilder nodeBuilder) { super( longType, nodeBuilder ); this.unit = unit; @@ -58,10 +60,23 @@ public SqmExpression getDuration() { public X accept(SemanticQueryWalker walker) { return walker.visitByUnit( this ); } + @Override public void appendHqlString(StringBuilder hql, SqmRenderContext context) { duration.appendHqlString( hql, context ); hql.append( " by " ); hql.append( unit.getUnit() ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmByUnit that + && Objects.equals( this.unit, that.unit ) + && Objects.equals( this.duration, that.duration ); + } + + @Override + public int hashCode() { + return Objects.hash( unit, duration ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCaseSearched.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCaseSearched.java index 9669f37e5fca..40d5ef8dc9bc 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCaseSearched.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCaseSearched.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import org.hibernate.query.criteria.JpaSearchedCase; import org.hibernate.query.internal.QueryHelper; @@ -157,6 +158,17 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( " end" ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmCaseSearched that + && Objects.equals( this.whenFragments, that.whenFragments ) + && Objects.equals( this.otherwise, that.otherwise ); + } + + @Override + public int hashCode() { + return Objects.hash( whenFragments, otherwise ); + } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // JPA diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCaseSimple.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCaseSimple.java index 19fe31985da2..36800246b16f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCaseSimple.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCaseSimple.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import org.hibernate.query.criteria.JpaExpression; import org.hibernate.query.criteria.JpaSimpleCase; @@ -171,6 +172,18 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( " end" ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmCaseSimple that + && Objects.equals( this.fixture, that.fixture ) + && Objects.equals( this.whenFragments, that.whenFragments ) + && Objects.equals( this.otherwise, that.otherwise ); + } + + @Override + public int hashCode() { + return Objects.hash( fixture, whenFragments, otherwise ); + } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // JPA diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCastTarget.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCastTarget.java index 76e26de492fd..e0574fdeede9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCastTarget.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCastTarget.java @@ -15,6 +15,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.query.sqm.tree.SqmTypedNode; +import java.util.Objects; + /** * @author Gavin King @@ -111,4 +113,18 @@ else if ( length != null ) { hql.append( ')' ); } } + + @Override + public boolean equals(Object object) { + return object instanceof SqmCastTarget that + && Objects.equals( type, that.type ) + && Objects.equals( length, that.length ) + && Objects.equals( precision, that.precision ) + && Objects.equals( scale, that.scale ); + } + + @Override + public int hashCode() { + return Objects.hash( type, length, precision, scale ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCoalesce.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCoalesce.java index bbdff81be7bb..123c89025348 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCoalesce.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCoalesce.java @@ -6,8 +6,8 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; -import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.query.criteria.JpaCoalesce; import org.hibernate.query.criteria.JpaExpression; import org.hibernate.query.sqm.NodeBuilder; @@ -19,6 +19,8 @@ import jakarta.persistence.criteria.Expression; import org.hibernate.query.sqm.tree.SqmRenderContext; +import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty; + /** * @author Steve Ebersole * @author Gavin King @@ -97,6 +99,16 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( ')' ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmCoalesce that + && Objects.equals( this.arguments, that.arguments ); + } + + @Override + public int hashCode() { + return arguments.hashCode(); + } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // JPA @@ -108,17 +120,17 @@ public SqmCoalesce value(T value) { } private SqmExpression firstOrNull() { - if ( CollectionHelper.isEmpty( arguments ) ) { + if ( isEmpty( arguments ) ) { return null; } - - //noinspection unchecked - return (SqmExpression) arguments.get( 0 ); + else { + //noinspection unchecked + return (SqmExpression) arguments.get( 0 ); + } } @Override public SqmCoalesce value(Expression value) { - //noinspection unchecked value( (SqmExpression) value ); return this; } @@ -126,7 +138,7 @@ public SqmCoalesce value(Expression value) { @Override public SqmCoalesce value(JpaExpression value) { //noinspection unchecked - value( (SqmExpression) value ); + value( (SqmExpression) value ); return this; } @@ -139,5 +151,4 @@ public SqmCoalesce values(T... values) { } return this; } - } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCollectionSize.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCollectionSize.java index 0515e8926665..04d86be2fe16 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCollectionSize.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmCollectionSize.java @@ -11,6 +11,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.query.sqm.tree.domain.SqmPath; +import java.util.Objects; + /** * Represents the {@code SIZE()} function. * @@ -68,4 +70,14 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( ')' ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmCollectionSize that + && Objects.equals( this.pluralPath, that.pluralPath ); + } + + @Override + public int hashCode() { + return pluralPath.hashCode(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmDistinct.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmDistinct.java index 54ca72178e52..335ac1cb07e6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmDistinct.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmDistinct.java @@ -12,6 +12,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.query.sqm.tree.SqmTypedNode; +import java.util.Objects; + /** * @author Gavin King */ @@ -58,4 +60,15 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( "distinct " ); expression.appendHqlString( hql, context ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmDistinct that + && Objects.equals( this.expression, that.expression ); + } + + @Override + public int hashCode() { + return Objects.hashCode( expression ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmDurationUnit.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmDurationUnit.java index ddbc38823ffa..66596c9f87a9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmDurationUnit.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmDurationUnit.java @@ -14,6 +14,7 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.query.sqm.tree.SqmTypedNode; + /** * @author Gavin King */ @@ -54,4 +55,15 @@ public SqmExpressible getNodeType() { public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( unit ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmDurationUnit that + && this.unit == that.unit; + } + + @Override + public int hashCode() { + return unit.hashCode(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmEvery.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmEvery.java index 87d7a1665c88..3c3d8a508f33 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmEvery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmEvery.java @@ -13,6 +13,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import java.util.Objects; + /** * @author Gavin King */ @@ -63,4 +65,14 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { subquery.appendHqlString( hql, context ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmEvery sqmAny + && Objects.equals( this.subquery, sqmAny.subquery ); + } + + @Override + public int hashCode() { + return subquery.hashCode(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmFieldLiteral.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmFieldLiteral.java index e7511e2f8f44..6536c2edb544 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmFieldLiteral.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmFieldLiteral.java @@ -10,6 +10,7 @@ import java.util.Collection; import java.util.List; import java.util.Locale; +import java.util.Objects; import org.hibernate.QueryException; import org.hibernate.query.criteria.JpaSelection; @@ -116,11 +117,8 @@ public void applyInferableType(@Nullable SqmExpressible type) { @Override public JavaType getExpressibleJavaType() { - if ( expressible == this ) { - return fieldJavaType; - } + return expressible == this ? fieldJavaType : expressible.getExpressibleJavaType(); - return expressible.getExpressibleJavaType(); } @Override @@ -143,6 +141,17 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { SqmLiteral.appendHqlString( hql, getJavaTypeDescriptor(), getValue() ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmFieldLiteral that + && Objects.equals( value, that.value ); + } + + @Override + public int hashCode() { + return Objects.hash( value ); + } + @Override public NodeBuilder nodeBuilder() { return nodeBuilder; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmFunction.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmFunction.java index c8117e8eca0a..620fa4fee27e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmFunction.java @@ -5,6 +5,7 @@ package org.hibernate.query.sqm.tree.expression; import java.util.List; +import java.util.Objects; import org.hibernate.query.criteria.JpaFunction; import org.hibernate.query.hql.spi.SemanticPathPart; @@ -182,7 +183,7 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { private SqmFunctionPath getFunctionPath() { SqmFunctionPath path = functionPath; if ( path == null ) { - path = functionPath = new SqmFunctionPath( this ); + path = functionPath = new SqmFunctionPath<>( this ); } return path; } @@ -202,4 +203,16 @@ public SqmPath resolveIndexedAccess( SqmCreationState creationState) { return getFunctionPath().resolveIndexedAccess( selector, isTerminal, creationState ); } + + @Override + public boolean equals(Object other) { + return other instanceof SqmFunction that + && Objects.equals( this.functionName, that.functionName ) + && Objects.equals( this.arguments, that.arguments ); + } + + @Override + public int hashCode() { + return Objects.hash( functionName, arguments ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmHqlNumericLiteral.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmHqlNumericLiteral.java index 7bd1eda1a0ab..c998a3b58c0d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmHqlNumericLiteral.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmHqlNumericLiteral.java @@ -76,29 +76,14 @@ public X accept(SemanticQueryWalker walker) { @Override public void appendHqlString(StringBuilder hql, SqmRenderContext context) { - hql.append( literalValue ); - - switch ( typeCategory ) { - case BIG_DECIMAL: { - hql.append( "bd" ); - break; - } - case FLOAT: { - hql.append( "f" ); - break; - } - case BIG_INTEGER: { - hql.append( "bi" ); - break; - } - case LONG: { - hql.append( "l" ); - break; - } - default: { - // nothing to do for double/integer - } - } + hql.append( literalValue ) + .append( switch ( typeCategory ) { + case BIG_DECIMAL -> "bd"; + case FLOAT -> "f"; + case BIG_INTEGER -> "bi"; + case LONG -> "l"; + case INTEGER, DOUBLE -> ""; + } ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmJpaCriteriaParameterWrapper.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmJpaCriteriaParameterWrapper.java index aa5f2a4512b2..e58163b60d66 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmJpaCriteriaParameterWrapper.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmJpaCriteriaParameterWrapper.java @@ -17,10 +17,12 @@ import static org.hibernate.query.sqm.tree.expression.SqmExpressionHelper.toSqmType; /** - * Acts as the per-use wrapper for a JpaCriteriaParameter ({@link jakarta.persistence.criteria.CriteriaBuilder#parameter}). - * - * JpaCriteriaParameter is the "domain query parameter" ({@link org.hibernate.query.QueryParameter} - * while SqmJpaCriteriaParameterWrapper is the {@link SqmParameter} + * Acts as the per-use wrapper for a {@link JpaCriteriaParameter} + * ({@link jakarta.persistence.criteria.CriteriaBuilder#parameter}). + *

+ * {@code JpaCriteriaParameter} is the "domain query parameter" + * ({@link org.hibernate.query.QueryParameter} while + * {@code SqmJpaCriteriaParameterWrapper} is the {@link SqmParameter} */ public class SqmJpaCriteriaParameterWrapper extends AbstractSqmExpression @@ -92,23 +94,27 @@ public SqmParameter copy() { /** * Unsupported. Visitation for a criteria parameter should be handled - * as part of {@link SemanticQueryWalker#visitJpaCriteriaParameter}. This wrapper - * is intended just for representing unique SqmParameter references for each - * JpaCriteriaParameter occurrence in the SQM true as part of the {@link org.hibernate.query.QueryParameter} + * as part of {@link SemanticQueryWalker#visitJpaCriteriaParameter}. + * This wrapper is intended just for representing unique SqmParameter + * references for each {@link JpaCriteriaParameter} occurrence in the + * SQM tree as part of the {@link org.hibernate.query.QueryParameter} * to {@link SqmParameter} to {@link JdbcParameter} transformation. - * Each occurrence requires a unique SqmParameter to make sure we ultimately get the complete - * set of JdbcParameter references + * Each occurrence requires a unique {@link SqmParameter} to make + * sure we ultimately get the complete set of {@code JdbcParameter} + * references. */ @Override public X accept(SemanticQueryWalker walker) { throw new UnsupportedOperationException( - "Direct SemanticQueryWalker visitation of a SqmJpaCriteriaParameterWrapper " + - "is not supported. Visitation for a criteria parameter should be handled " + - "during `SemanticQueryWalker#visitJpaCriteriaParameter`. This wrapper is " + - "intended only for representing unique SQM parameter nodes for each criteria " + - "parameter in the SQM tree as part of the QueryParameter -> SqmParameter -> JdbcParameter " + - "transformation. Each occurrence requires a unique SqmParameter to make sure we" + - "ultimately get the complete set of JdbcParameter references" + """ + Direct SemanticQueryWalker visitation of a SqmJpaCriteriaParameterWrapper \ + is not supported. Visitation for a criteria parameter should be handled \ + during SemanticQueryWalker#visitJpaCriteriaParameter. This wrapper is \ + intended only for representing unique SQM parameter nodes for each criteria \ + parameter in the SQM tree as part of the QueryParameter -> SqmParameter -> JdbcParameter \ + transformation. Each occurrence requires a unique SqmParameter to make sure we \ + ultimately get the complete set of JdbcParameter references.\ + """ ); } @@ -124,8 +130,19 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { @Override public int compareTo(SqmParameter anotherParameter) { - return anotherParameter instanceof SqmJpaCriteriaParameterWrapper ? - getJpaCriteriaParameter().compareTo( ( (SqmJpaCriteriaParameterWrapper) anotherParameter ).getJpaCriteriaParameter() ) + return anotherParameter instanceof SqmJpaCriteriaParameterWrapper wrapper + ? getJpaCriteriaParameter().compareTo( wrapper.getJpaCriteriaParameter() ) : 1; } + +// @Override +// public boolean equals(Object object) { +// return object instanceof SqmJpaCriteriaParameterWrapper that +// && Objects.equals( this.jpaCriteriaParameter, that.jpaCriteriaParameter ); +// } +// +// @Override +// public int hashCode() { +// return jpaCriteriaParameter.hashCode(); +// } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmJsonExistsExpression.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmJsonExistsExpression.java index 0b823c537db4..51aae5631373 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmJsonExistsExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmJsonExistsExpression.java @@ -180,11 +180,12 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { getArguments().get( 1 ).appendHqlString( hql, context ); appendPassingExpressionHqlString( hql, context ); - switch ( errorBehavior ) { - case ERROR -> hql.append( " error on error" ); - case TRUE -> hql.append( " true on error" ); - case FALSE -> hql.append( " false on error" ); - } + hql.append( switch ( errorBehavior ) { + case ERROR -> " error on error"; + case TRUE -> " true on error"; + case FALSE -> " false on error"; + case UNSPECIFIED -> ""; + } ); hql.append( ')' ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteral.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteral.java index ff8fb72e80f0..e560461e87e2 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteral.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteral.java @@ -13,6 +13,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import java.util.Objects; + import static org.hibernate.internal.util.QuotingHelper.appendSingleQuoteEscapedString; /** @@ -99,4 +101,14 @@ else if ( value instanceof Enum enumValue ) { } } + @Override + public boolean equals(Object object) { + return object instanceof SqmLiteral that + && Objects.equals( value, that.value ); + } + + @Override + public int hashCode() { + return Objects.hashCode( value ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteralEmbeddableType.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteralEmbeddableType.java index 1c5f2a7de197..e4193ebac5ad 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteralEmbeddableType.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteralEmbeddableType.java @@ -17,6 +17,8 @@ import org.hibernate.query.sqm.tree.domain.SqmEmbeddableDomainType; import org.hibernate.query.sqm.tree.select.SqmSelectableNode; +import java.util.Objects; + import static org.hibernate.persister.entity.DiscriminatorHelper.getDiscriminatorType; /** @@ -87,4 +89,15 @@ public SqmPath resolveIndexedAccess( public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( embeddableDomainType.getTypeName() ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmLiteralEmbeddableType that + && Objects.equals( embeddableDomainType.getTypeName(), that.embeddableDomainType.getTypeName() ); + } + + @Override + public int hashCode() { + return embeddableDomainType.getTypeName().hashCode(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteralEntityType.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteralEntityType.java index 93c80c3df705..0dd45bacbe2d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteralEntityType.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteralEntityType.java @@ -16,6 +16,8 @@ import org.hibernate.query.sqm.tree.domain.SqmEntityDomainType; import org.hibernate.query.sqm.tree.select.SqmSelectableNode; +import java.util.Objects; + import static org.hibernate.persister.entity.DiscriminatorHelper.getDiscriminatorType; /** @@ -99,4 +101,14 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( entityType.getName() ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmLiteralEntityType that + && Objects.equals( this.entityType.getName(), that.entityType.getName() ); + } + + @Override + public int hashCode() { + return entityType.getName().hashCode(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteralNull.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteralNull.java index 5662bf215e8d..229c836ef227 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteralNull.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteralNull.java @@ -57,4 +57,14 @@ public String asLoggableText() { public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( "null" ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmLiteralNull; + } + + @Override + public int hashCode() { + return 1; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmModifiedSubQueryExpression.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmModifiedSubQueryExpression.java index 3525e679e501..edb0928b94dc 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmModifiedSubQueryExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmModifiedSubQueryExpression.java @@ -11,6 +11,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.query.sqm.tree.select.SqmSubQuery; +import java.util.Objects; + /** * Represents a {@link Modifier#ALL}, {@link Modifier#ANY}, {@link Modifier#SOME} modifier applied to a subquery as * part of a comparison. @@ -88,4 +90,16 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { subQuery.appendHqlString( hql, context ); hql.append( ')' ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmModifiedSubQueryExpression that + && modifier == that.modifier + && Objects.equals( subQuery, that.subQuery ); + } + + @Override + public int hashCode() { + return Objects.hash( subQuery, modifier ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmNamedExpression.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmNamedExpression.java index 95439793fc66..1f9bf5508f9f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmNamedExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmNamedExpression.java @@ -9,6 +9,8 @@ import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmRenderContext; +import java.util.Objects; + /** * A named expression. Used when the name of the expression matters * e.g. in XML generation. @@ -60,4 +62,16 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( " as " ); hql.append( name ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmNamedExpression that + && Objects.equals( this.name, that.name ) + && Objects.equals( this.expression, that.expression ); + } + + @Override + public int hashCode() { + return Objects.hash( expression, name ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmNamedParameter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmNamedParameter.java index fd3bfd3d1c8e..253a717db300 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmNamedParameter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmNamedParameter.java @@ -10,6 +10,8 @@ import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmRenderContext; +import java.util.Objects; + /** * Represents a named query parameter in the SQM tree. * @@ -77,14 +79,24 @@ public SqmParameter copy() { @Override public void appendHqlString(StringBuilder hql, SqmRenderContext context) { - hql.append( ':' ); - hql.append( getName() ); + hql.append( ':' ).append( getName() ); } @Override public int compareTo(SqmParameter anotherParameter) { - return anotherParameter instanceof SqmNamedParameter - ? getName().compareTo( ( (SqmNamedParameter) anotherParameter ).getName() ) + return anotherParameter instanceof SqmNamedParameter namedParameter + ? getName().compareTo( namedParameter.getName() ) : -1; } + + @Override + public boolean equals(Object object) { + return object instanceof SqmNamedParameter that + && Objects.equals( name, that.name ); + } + + @Override + public int hashCode() { + return name.hashCode(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmOver.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmOver.java index d89b0bb4704b..cc0e955c3156 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmOver.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmOver.java @@ -5,6 +5,7 @@ package org.hibernate.query.sqm.tree.expression; import java.util.List; +import java.util.Objects; import org.hibernate.query.common.FrameExclusion; import org.hibernate.query.common.FrameKind; @@ -103,4 +104,16 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { window.appendHqlString( hql, context ); hql.append( ')' ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmOver sqmOver + && Objects.equals( expression, sqmOver.expression ) + && Objects.equals( window, sqmOver.window ); + } + + @Override + public int hashCode() { + return Objects.hash( expression, window ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmOverflow.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmOverflow.java index 00bd8fb99619..fcfb8b31df06 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmOverflow.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmOverflow.java @@ -8,6 +8,8 @@ import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmRenderContext; +import java.util.Objects; + /** * @author Christian Beikov */ @@ -78,4 +80,16 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { } } + @Override + public boolean equals(Object object) { + return object instanceof SqmOverflow that + && this.withCount == that.withCount + && Objects.equals( this.separatorExpression, that.separatorExpression ) + && Objects.equals( this.fillerExpression, that.fillerExpression ); + } + + @Override + public int hashCode() { + return Objects.hash( separatorExpression, fillerExpression, withCount ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmParameter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmParameter.java index ed622affb3c3..6ee8f64384fd 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmParameter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmParameter.java @@ -13,10 +13,10 @@ * Models a parameter expression declared in the query. * * @implNote Each usage of a given named/positional query parameter - * will result in a unique SqmParameter instance, each will simply - * use to the same binding. This is important to distinguish usage - * of the same parameter in different clauses which effects the - * rendering and value binding. + * will result in a unique {@code SqmParameter} instance, each will + * simply use to the same binding. This is important to distinguish + * usage of the same parameter in different clauses which effects + * the rendering and value binding. * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmParameterizedEntityType.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmParameterizedEntityType.java index 91f348058ac3..5bdc50374d46 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmParameterizedEntityType.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmParameterizedEntityType.java @@ -11,6 +11,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.query.sqm.tree.select.SqmSelectableNode; +import java.util.Objects; + /** * Entity type expression based on a parameter - `TYPE( :someParam )` * @@ -19,7 +21,7 @@ public class SqmParameterizedEntityType extends AbstractSqmExpression implements SqmSelectableNode { private final SqmParameter discriminatorSource; - public SqmExpression getDiscriminatorSource() { + public SqmExpression getDiscriminatorSource() { return discriminatorSource; } @@ -48,8 +50,6 @@ public SqmParameterizedEntityType copy(SqmCopyContext context) { @Override public void internalApplyInferableType(SqmExpressible type) { setExpressibleType( type ); - - //noinspection unchecked discriminatorSource.applyInferableType( type ); } @@ -65,4 +65,14 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( ')' ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmParameterizedEntityType that + && Objects.equals( discriminatorSource, that.discriminatorSource ); + } + + @Override + public int hashCode() { + return discriminatorSource.hashCode(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmPositionalParameter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmPositionalParameter.java index c78bcc0bc0cf..38cc6ee43c25 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmPositionalParameter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmPositionalParameter.java @@ -86,8 +86,19 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { @Override public int compareTo(SqmParameter anotherParameter) { - return anotherParameter instanceof SqmPositionalParameter - ? getPosition().compareTo( ( (SqmPositionalParameter) anotherParameter ).getPosition() ) + return anotherParameter instanceof SqmPositionalParameter positionalParameter + ? getPosition().compareTo( positionalParameter.getPosition() ) : 1; } + + @Override + public boolean equals(Object object) { + return object instanceof SqmPositionalParameter that + && position == that.position; + } + + @Override + public int hashCode() { + return position; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmSelfRenderingExpression.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmSelfRenderingExpression.java index a588469bebea..30da0afd7e99 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmSelfRenderingExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmSelfRenderingExpression.java @@ -17,10 +17,10 @@ * @author Steve Ebersole */ public class SqmSelfRenderingExpression extends AbstractSqmExpression { - private final Function renderer; + private final Function, Expression> renderer; public SqmSelfRenderingExpression( - Function renderer, + Function, Expression> renderer, SqmExpressible type, NodeBuilder criteriaBuilder) { super( type, criteriaBuilder ); @@ -51,4 +51,6 @@ public X accept(SemanticQueryWalker walker) { public void appendHqlString(StringBuilder hql, SqmRenderContext context) { throw new UnsupportedOperationException(); } + + //TODO: what is a correct impl of equals() / hashCode() here? } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmSetReturningFunction.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmSetReturningFunction.java index 97f9153d7fac..28a99ae41b56 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmSetReturningFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmSetReturningFunction.java @@ -5,6 +5,7 @@ package org.hibernate.query.sqm.tree.expression; import java.util.List; +import java.util.Objects; import org.hibernate.Incubating; import org.hibernate.query.criteria.JpaSetReturningFunction; @@ -27,8 +28,8 @@ * @since 7.0 */ @Incubating -public abstract class SqmSetReturningFunction extends AbstractSqmNode implements SqmVisitableNode, - JpaSetReturningFunction { +public abstract class SqmSetReturningFunction extends AbstractSqmNode + implements SqmVisitableNode, JpaSetReturningFunction { // this function-name is the one used to resolve the descriptor from // the function registry (which may or may not be a db function name) private final String functionName; @@ -83,15 +84,30 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( functionName ); if ( arguments.isEmpty() ) { hql.append( "()" ); - return; } - hql.append( '(' ); - arguments.get( 0 ).appendHqlString( hql, context ); - for ( int i = 1; i < arguments.size(); i++ ) { - hql.append( ", " ); - arguments.get( i ).appendHqlString( hql, context ); + else { + hql.append( '(' ); + arguments.get( 0 ).appendHqlString( hql, context ); + for ( int i = 1; i < arguments.size(); i++ ) { + hql.append( ", " ); + arguments.get( i ).appendHqlString( hql, context ); + } + hql.append( ')' ); } + } - hql.append( ')' ); + @Override + // TODO: override on all subtypes + public boolean equals(Object other) { + return other instanceof SqmSetReturningFunction that + && Objects.equals( this.functionName, that.functionName ) + && Objects.equals( this.arguments, that.arguments ) + && this.getClass() == that.getClass() + && Objects.equals( this.toHqlString(), that.toHqlString() ); + } + + @Override + public int hashCode() { + return Objects.hash( functionName, arguments, getClass() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmStar.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmStar.java index bd3816509716..5b1afef12212 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmStar.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmStar.java @@ -36,4 +36,13 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( "*" ); } + @Override + public boolean equals(Object other) { + return other instanceof SqmStar; + } + + @Override + public int hashCode() { + return 1; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmSummarization.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmSummarization.java index 7c245f81bfca..092c1e528781 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmSummarization.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmSummarization.java @@ -65,6 +65,7 @@ public enum Kind { ROLLUP, CUBE } + @Override public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( kind ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmToDuration.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmToDuration.java index 0f8e261e219b..4d5ccfc90381 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmToDuration.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmToDuration.java @@ -10,6 +10,8 @@ import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmRenderContext; +import java.util.Objects; + /** * @author Gavin King */ @@ -70,4 +72,16 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( ' ' ); hql.append( unit.getUnit() ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmToDuration that + && Objects.equals( magnitude, that.magnitude ) + && Objects.equals( unit, that.unit ); + } + + @Override + public int hashCode() { + return Objects.hash( magnitude, unit ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmTrimSpecification.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmTrimSpecification.java index dfa0a69e9984..821340a12726 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmTrimSpecification.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmTrimSpecification.java @@ -13,6 +13,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.query.sqm.tree.SqmTypedNode; +import java.util.Objects; + /** * Needed to pass TrimSpecification as an SqmExpression when we call out to * SqmFunctionTemplates handling TRIM calls as a function argument. @@ -55,4 +57,15 @@ public SqmExpressible getNodeType() { public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( specification ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmTrimSpecification that + && specification == that.specification; + } + + @Override + public int hashCode() { + return Objects.hashCode( specification ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmTuple.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmTuple.java index 9cf74d74c824..a65f5b76b744 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmTuple.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmTuple.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import org.hibernate.query.SemanticException; import org.hibernate.query.criteria.JpaCompoundSelection; @@ -94,6 +95,17 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( ')' ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmTuple that + && Objects.equals( this.groupedExpressions, that.groupedExpressions ); + } + + @Override + public int hashCode() { + return Objects.hashCode( groupedExpressions ); + } + @Override public String asLoggableText() { return toString(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmUnaryOperation.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmUnaryOperation.java index d468a9e85872..10a4beadba0f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmUnaryOperation.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmUnaryOperation.java @@ -70,11 +70,11 @@ public X accept(SemanticQueryWalker walker) { @Override public String asLoggableText() { - return ( operation == UnaryArithmeticOperator.UNARY_MINUS ? '-' : '+' ) + operand.asLoggableText(); + return operation.getOperatorChar() + operand.asLoggableText(); } @Override public void appendHqlString(StringBuilder hql, SqmRenderContext context) { - hql.append( operation == UnaryArithmeticOperator.UNARY_MINUS ? '-' : '+' ); + hql.append( operation.getOperatorChar() ); operand.appendHqlString( hql, context ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmWindow.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmWindow.java index 0d8b61084b9c..92c3a8d0e7ca 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmWindow.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmWindow.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import org.hibernate.Incubating; import org.hibernate.query.criteria.JpaWindow; @@ -286,4 +287,25 @@ private static void renderFrameKind(StringBuilder sb, FrameKind kind, SqmExpress throw new UnsupportedOperationException( "Unsupported frame kind: " + kind ); } } + + @Override + public boolean equals(Object object) { + if ( !(object instanceof SqmWindow sqmWindow) ) { + return false; + } + return Objects.equals( partitions, sqmWindow.partitions ) + && Objects.equals( orderList, sqmWindow.orderList ) + && mode == sqmWindow.mode + && startKind == sqmWindow.startKind + && Objects.equals( startExpression, sqmWindow.startExpression ) + && endKind == sqmWindow.endKind + && Objects.equals( endExpression, sqmWindow.endExpression ) + && exclusion == sqmWindow.exclusion; + } + + @Override + public int hashCode() { + return Objects.hash( partitions, orderList, mode, startKind, startExpression, endKind, endExpression, + exclusion ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/ValueBindJpaCriteriaParameter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/ValueBindJpaCriteriaParameter.java index 712366ea5a63..663651c7f99a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/ValueBindJpaCriteriaParameter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/ValueBindJpaCriteriaParameter.java @@ -9,8 +9,12 @@ import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmRenderContext; +import java.util.Objects; + + /** - * It is a JpaCriteriaParameter created from a value when ValueHandlingMode is equal to BIND + * A {@link JpaCriteriaParameter} created from a value when + * {@link org.hibernate.query.criteria.ValueHandlingMode} is {@code BIND}. * * @see org.hibernate.query.criteria.ValueHandlingMode */ @@ -46,17 +50,33 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { } @Override - public boolean equals(Object o) { - return this == o; + // TODO: fix this + public int compareTo(SqmParameter parameter) { + return this == parameter ? 0 : 1; } + // this is not really a parameter, it's really a literal value + // so use value equality based on its value + @Override - public int hashCode() { - return System.identityHashCode( this ); + public boolean equals(Object object) { + return object instanceof ValueBindJpaCriteriaParameter that + && Objects.equals( this.value, that.value ); +// && getJavaTypeDescriptor().areEqual( this.value, (T) that.value ); } @Override - public int compareTo(SqmParameter anotherParameter) { - return this == anotherParameter ? 0 : 1; + public int hashCode() { + return value == null ? 0 : value.hashCode(); // getJavaTypeDescriptor().extractHashCode( value ); } + +// @Override +// public boolean equals(Object object) { +// return this == object; +// } +// +// @Override +// public int hashCode() { +// return System.identityHashCode( this ); +// } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmCrossJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmCrossJoin.java index 93e1041e463a..e6a1f6e9bfc8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmCrossJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmCrossJoin.java @@ -25,6 +25,7 @@ import jakarta.persistence.criteria.From; import jakarta.persistence.criteria.JoinType; + import static org.hibernate.query.sqm.spi.SqmCreationHelper.buildRootNavigablePath; /** @@ -211,4 +212,16 @@ public SqmTreatedCrossJoin treatAs(Class treatAsType) { public SqmTreatedCrossJoin treatAs(EntityDomainType treatAsType) { return treatAs( treatAsType, null ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmCrossJoin + && super.equals( object ); + } + + @Override + // needed to make static code analyzer happy + public int hashCode() { + return super.hashCode(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmCteJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmCteJoin.java index 6b7819ba0d90..e3026249ad3b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmCteJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmCteJoin.java @@ -20,6 +20,8 @@ import jakarta.persistence.criteria.JoinType; +import java.util.Objects; + /** * @author Christian Beikov */ @@ -154,4 +156,16 @@ public SqmFrom getParent() { public JoinType getJoinType() { return getSqmJoinType().getCorrespondingJpaJoinType(); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmCteJoin that + && super.equals( object ) + && Objects.equals( this.cte.getName(), that.cte.getName() ); + } + + @Override + public int hashCode() { + return Objects.hash( super.hashCode(), cte.getName() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmDerivedJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmDerivedJoin.java index 1e9d310f0eb8..a4b05f440fa8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmDerivedJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmDerivedJoin.java @@ -26,6 +26,8 @@ import jakarta.persistence.criteria.JoinType; import jakarta.persistence.criteria.Predicate; +import java.util.Objects; + /** * @author Christian Beikov */ @@ -216,4 +218,17 @@ public SqmFrom getParent() { public JoinType getJoinType() { return getSqmJoinType().getCorrespondingJpaJoinType(); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmDerivedJoin that + && super.equals( object ) + && this.lateral == that.lateral + && Objects.equals( this.subQuery, that.subQuery ); + } + + @Override + public int hashCode() { + return Objects.hash( super.hashCode(), subQuery, lateral ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmEntityJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmEntityJoin.java index 74beb680da40..ddb8fb741793 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmEntityJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmEntityJoin.java @@ -30,6 +30,8 @@ import jakarta.persistence.criteria.Predicate; import jakarta.persistence.metamodel.EntityType; +import java.util.Objects; + /** * @author Steve Ebersole */ @@ -228,5 +230,15 @@ public SqmEntityJoin makeCopy(SqmCreationProcessingState creationProcessing ); } + @Override + public boolean equals(Object other) { + return other instanceof SqmEntityJoin that + && Objects.equals( this.getEntityName(), that.getEntityName() ) + && super.equals( other ); + } + @Override + public int hashCode() { + return Objects.hash( super.hashCode(), getEntityName() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFrom.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFrom.java index 860cebb71cf1..e0bc830699e9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFrom.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFrom.java @@ -58,6 +58,8 @@ default String resolveAlias(SqmRenderContext context) { boolean hasJoins(); + int getNumberOfJoins(); + /** * The joins associated with this SqmFrom */ diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFromClause.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFromClause.java index 5a6b65c6cb30..d5dcb66b3ef6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFromClause.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFromClause.java @@ -7,15 +7,16 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.function.Consumer; -import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.query.sqm.tree.domain.SqmTreatedPath; import static java.util.Collections.emptyList; import static java.util.Collections.unmodifiableList; +import static org.hibernate.internal.util.collections.CollectionHelper.arrayList; /** * Contract representing a from clause. @@ -32,7 +33,7 @@ public SqmFromClause() { } public SqmFromClause(int expectedNumberOfRoots) { - this.domainRoots = CollectionHelper.arrayList( expectedNumberOfRoots ); + domainRoots = arrayList( expectedNumberOfRoots ); } private SqmFromClause(SqmFromClause original, SqmCopyContext context) { @@ -70,7 +71,6 @@ public void addRoot(SqmRoot root) { if ( domainRoots == null ) { domainRoots = new ArrayList<>(); } - domainRoots.add( root ); } @@ -84,12 +84,7 @@ public void visitRoots(Consumer> consumer) { } public int getNumberOfRoots() { - if ( domainRoots == null ) { - return 0; - } - else { - return domainRoots.size(); - } + return domainRoots == null ? 0 : domainRoots.size(); } public void appendHqlString(StringBuilder sb, SqmRenderContext context) { @@ -146,7 +141,7 @@ public static void appendJoins(SqmFrom sqmFrom, StringBuilder sb, SqmRende else { sb.append( sqmFrom.resolveAlias( context ) ); } - sb.append( '.' ).append( ( attributeJoin ).getAttribute().getName() ); + sb.append( '.' ).append( attributeJoin.getAttribute().getName() ); sb.append( ' ' ).append( sqmJoin.resolveAlias( context ) ); if ( attributeJoin.getJoinPredicate() != null ) { sb.append( " on " ); @@ -160,7 +155,7 @@ else if ( sqmJoin instanceof SqmCrossJoin sqmCrossJoin ) { appendJoins( sqmJoin, sb, context ); } else if ( sqmJoin instanceof SqmEntityJoin sqmEntityJoin ) { - sb.append( ( sqmEntityJoin ).getEntityName() ); + sb.append( sqmEntityJoin.getEntityName() ); sb.append( ' ' ).append( sqmJoin.resolveAlias( context ) ); if ( sqmEntityJoin.getJoinPredicate() != null ) { sb.append( " on " ); @@ -192,4 +187,49 @@ public static void appendTreatJoins(SqmFrom sqmFrom, StringBuilder sb, Sqm appendJoins( sqmTreat, sb, context ); } } + + @Override + public boolean equals(Object object) { + return object instanceof SqmFromClause that + && this.getNumberOfRoots() == that.getNumberOfRoots() + && equalRoots( this.getRoots(), that.getRoots() ); + } + + // both lists must be the same size + private boolean equalRoots(List> theseRoots, List> thoseRoots) { + for ( int i = 0; i < theseRoots.size(); i++ ) { + var thisRoot = theseRoots.get( i ); + var thatRoot = thoseRoots.get( i ); + if ( !Objects.equals( thisRoot.getEntityName(), thatRoot.getEntityName() ) + || !Objects.equals( thisRoot.getExplicitAlias(), thatRoot.getExplicitAlias() ) + || !Objects.equals( thisRoot, thatRoot ) // needed for SqmDerivedRoots + || thisRoot.getNumberOfJoins() != thatRoot.getNumberOfJoins() + || !equalsJoins( thisRoot.getSqmJoins(), thatRoot.getSqmJoins() ) ) { + return false; + } + } + return true; + } + + private boolean equalsJoins(List> theseJoins, List> thoseJoins) { + for ( int i = 0; i < theseJoins.size(); i++ ) { + var thisJoin = theseJoins.get( i ); + var thatJoin = thoseJoins.get( i ); + if ( !Objects.equals( thisJoin.getNavigablePath(), thatJoin.getNavigablePath() ) + || !Objects.equals( thisJoin.getExplicitAlias(), thatJoin.getExplicitAlias() ) + || !Objects.equals( thisJoin.getJoinType(), thatJoin.getJoinType() ) + || !Objects.equals( thisJoin, thatJoin ) // needed for SqmDerivedRoots + || thisJoin.getNumberOfJoins() != thatJoin.getNumberOfJoins() + || !Objects.equals( thisJoin.getOn(), thatJoin.getOn() ) + || !equalsJoins( thisJoin.getSqmJoins(), thatJoin.getSqmJoins() ) ) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return getNumberOfRoots(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFunctionJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFunctionJoin.java index 28ac139ca649..e84fe08513e1 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFunctionJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFunctionJoin.java @@ -27,6 +27,8 @@ import jakarta.persistence.criteria.JoinType; import jakarta.persistence.criteria.Predicate; +import java.util.Objects; + /** * @author Christian Beikov */ @@ -226,4 +228,17 @@ public SqmFrom getParent() { public JoinType getJoinType() { return getSqmJoinType().getCorrespondingJpaJoinType(); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmFunctionJoin that + && super.equals( object ) + && this.lateral == that.lateral + && Objects.equals( this.function, that.function ); + } + + @Override + public int hashCode() { + return Objects.hash( super.hashCode(), function, lateral ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmRoot.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmRoot.java index 06fdabf4e89c..465ee76ddde1 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmRoot.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmRoot.java @@ -206,24 +206,25 @@ public SqmTreatedFrom treatAs(EntityDomainType treatTarg return treat; } + @SuppressWarnings("unchecked") @Override public SqmTreatedRoot treatAs(Class treatJavaType, String alias) { throw new UnsupportedOperationException( "Root treats can not be aliased" ); } - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings("unchecked") @Override public SqmTreatedRoot treatAs(EntityDomainType treatTarget, String alias) { throw new UnsupportedOperationException( "Root treats can not be aliased" ); } - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings("unchecked") @Override public SqmTreatedRoot treatAs(Class treatJavaType, String alias, boolean fetch) { throw new TreatException( "Root paths cannot be aliased, nor fetched - " + getNavigablePath().getFullPath() ); } - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings("unchecked") @Override public SqmTreatedRoot treatAs(EntityDomainType treatTarget, String alias, boolean fetch) { throw new TreatException( "Root paths cannot be aliased, nor fetched - " + getNavigablePath().getFullPath() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmConflictClause.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmConflictClause.java index 91e72de7f496..dbbcb6ea2455 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmConflictClause.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmConflictClause.java @@ -8,6 +8,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Objects; import org.hibernate.query.criteria.JpaConflictClause; import org.hibernate.query.criteria.JpaConflictUpdateAction; @@ -212,4 +213,18 @@ private static void appendUnqualifiedPath(StringBuilder sb, SqmPath path) { } sb.append( path.getReferencedPathSource().getPathName() ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmConflictClause that + && Objects.equals( excludedRoot, that.excludedRoot ) + && Objects.equals( constraintName, that.constraintName ) + && Objects.equals( constraintPaths, that.constraintPaths ) + && Objects.equals( updateAction, that.updateAction ); + } + + @Override + public int hashCode() { + return Objects.hash( excludedRoot, constraintName, constraintPaths, updateAction ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertSelectStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertSelectStatement.java index 3afdf8164b93..5d4619d8b683 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertSelectStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertSelectStatement.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -53,7 +54,7 @@ public SqmInsertSelectStatement(Class targetEntity, NodeBuilder nodeBuilder) super( new SqmRoot<>( nodeBuilder.getDomainModel().entity( targetEntity ), - null, + "_0", false, nodeBuilder ), @@ -188,4 +189,21 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { conflictClause.appendHqlString( hql, context ); } } + + @Override + public boolean equals(Object object) { + if ( !(object instanceof SqmInsertSelectStatement that) ) { + return false; + } + return Objects.equals( selectQueryPart, that.selectQueryPart ) + && Objects.equals( this.getTarget(), that.getTarget() ) + && Objects.equals( this.getInsertionTargetPaths(), that.getInsertionTargetPaths() ) + && Objects.equals( this.getConflictClause(), that.getConflictClause() ) + && Objects.equals( this.getCteStatements(), that.getCteStatements() ); + } + + @Override + public int hashCode() { + return Objects.hash( selectQueryPart, getTarget(), getInsertionTargetPaths(), getConflictClause(), getCteStatements() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertValuesStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertValuesStatement.java index e13c1aa06cb8..6af599fb6abe 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertValuesStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertValuesStatement.java @@ -9,6 +9,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -49,7 +50,7 @@ public SqmInsertValuesStatement(Class targetEntity, NodeBuilder nodeBuilder) super( new SqmRoot<>( nodeBuilder.getDomainModel().entity( targetEntity ), - null, + "_0", false, nodeBuilder ), @@ -208,7 +209,7 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { appendValues( valuesList.get( i ), hql, context ); } hql.append( ')' ); - final SqmConflictClause conflictClause = getConflictClause(); + final SqmConflictClause conflictClause = getConflictClause(); if ( conflictClause != null ) { conflictClause.appendHqlString( hql, context ); } @@ -224,4 +225,21 @@ private static void appendValues(SqmValues sqmValues, StringBuilder sb, SqmRende } sb.append( ')' ); } + + @Override + public boolean equals(Object object) { + if ( !(object instanceof SqmInsertValuesStatement that) ) { + return false; + } + return Objects.equals( valuesList, that.valuesList ) + && Objects.equals( this.getTarget(), that.getTarget() ) + && Objects.equals( this.getInsertionTargetPaths(), that.getInsertionTargetPaths() ) + && Objects.equals( this.getConflictClause(), that.getConflictClause() ) + && Objects.equals( this.getCteStatements(), that.getCteStatements() ); + } + + @Override + public int hashCode() { + return Objects.hash( valuesList, getTarget(), getInsertionTargetPaths(), getConflictClause(), getCteStatements() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/AbstractNegatableSqmPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/AbstractNegatableSqmPredicate.java index cca6b386f76e..2daa57708480 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/AbstractNegatableSqmPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/AbstractNegatableSqmPredicate.java @@ -7,6 +7,8 @@ import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SqmExpressible; +import java.util.Objects; + /** * @author Steve Ebersole */ @@ -33,7 +35,7 @@ public boolean isNegated() { @Override public void negate() { - this.negated = !this.negated; + negated = !negated; } protected abstract SqmNegatablePredicate createNegatedNode(); @@ -45,4 +47,18 @@ public SqmNegatablePredicate not() { return createNegatedNode(); } + @Override + // for safety only, overridden on all subtypes + public boolean equals(Object other) { + return other instanceof AbstractNegatableSqmPredicate that + && this.negated == that.negated + && this.getClass() == that.getClass() + && Objects.equals( this.toHqlString(), that.toHqlString() ); + } + + @Override + // for safety only, overridden on all subtypes + public int hashCode() { + return Objects.hash( getClass(), negated ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBetweenPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBetweenPredicate.java index 779610718d5a..2a3fda49d43f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBetweenPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBetweenPredicate.java @@ -12,6 +12,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.query.sqm.tree.expression.SqmExpression; +import java.util.Objects; + import static org.hibernate.query.sqm.internal.TypecheckUtil.assertComparable; /** @@ -96,6 +98,20 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { upperBound.appendHqlString( hql, context ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmBetweenPredicate that + && this.isNegated() == that.isNegated() + && Objects.equals( expression, that.expression ) + && Objects.equals( lowerBound, that.lowerBound ) + && Objects.equals( upperBound, that.upperBound ); + } + + @Override + public int hashCode() { + return Objects.hash( isNegated(), expression, lowerBound, upperBound ); + } + @Override protected SqmNegatablePredicate createNegatedNode() { return new SqmBetweenPredicate( expression, lowerBound, upperBound, ! isNegated(), nodeBuilder() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBooleanExpressionPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBooleanExpressionPredicate.java index 5d6a40806ed1..fa627320e1f9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBooleanExpressionPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBooleanExpressionPredicate.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SemanticQueryWalker; @@ -82,6 +83,18 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { booleanExpression.appendHqlString( hql, context ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmBooleanExpressionPredicate that + && this.isNegated() == that.isNegated() + && Objects.equals( this.booleanExpression, that.booleanExpression ); + } + + @Override + public int hashCode() { + return Objects.hash( booleanExpression, isNegated() ); + } + @Override protected SqmNegatablePredicate createNegatedNode() { return new SqmBooleanExpressionPredicate( booleanExpression, !isNegated(), nodeBuilder() ); @@ -89,11 +102,8 @@ protected SqmNegatablePredicate createNegatedNode() { @Override public String toString() { - if ( isNegated() ) { - return "SqmBooleanExpressionPredicate( (not) " + booleanExpression + " )"; - } - else { - return "SqmBooleanExpressionPredicate( " + booleanExpression + " )"; - } + return isNegated() + ? "SqmBooleanExpressionPredicate( (not) " + booleanExpression + " )" + : "SqmBooleanExpressionPredicate( " + booleanExpression + " )"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java index 86f6b4931756..6415dd62a513 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java @@ -13,6 +13,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.query.sqm.tree.expression.SqmExpression; +import java.util.Objects; + import static org.hibernate.query.sqm.internal.TypecheckUtil.assertComparable; /** @@ -116,4 +118,18 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( ' ' ); rightHandExpression.appendHqlString( hql, context ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmComparisonPredicate that + && this.isNegated() == that.isNegated() + && this.operator == that.operator + && Objects.equals( this.leftHandExpression, that.leftHandExpression ) + && Objects.equals( this.rightHandExpression, that.rightHandExpression ); + } + + @Override + public int hashCode() { + return Objects.hash( isNegated(), operator, leftHandExpression, rightHandExpression ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmEmptinessPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmEmptinessPredicate.java index aff4553c57b9..912ee0538c22 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmEmptinessPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmEmptinessPredicate.java @@ -10,6 +10,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath; +import java.util.Objects; + /** * @author Steve Ebersole */ @@ -17,7 +19,7 @@ public class SqmEmptinessPredicate extends AbstractNegatableSqmPredicate { private final SqmPluralValuedSimplePath pluralPath; public SqmEmptinessPredicate( - SqmPluralValuedSimplePath pluralPath, + SqmPluralValuedSimplePath pluralPath, boolean negated, NodeBuilder nodeBuilder) { super( negated, nodeBuilder ); @@ -62,6 +64,18 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { } } + @Override + public boolean equals(Object object) { + return object instanceof SqmEmptinessPredicate that + && this.isNegated() == that.isNegated() + && Objects.equals( pluralPath, that.pluralPath ); + } + + @Override + public int hashCode() { + return Objects.hash( isNegated(), pluralPath ); + } + @Override protected SqmNegatablePredicate createNegatedNode() { return new SqmEmptinessPredicate( pluralPath, !isNegated(), nodeBuilder() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmExistsPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmExistsPredicate.java index 2212490da458..f99af9155593 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmExistsPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmExistsPredicate.java @@ -10,6 +10,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.query.sqm.tree.expression.SqmExpression; +import java.util.Objects; + /** * @author Gavin King */ @@ -70,6 +72,18 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { expression.appendHqlString( hql, context ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmExistsPredicate that + && this.isNegated() == that.isNegated() + && Objects.equals( this.expression, that.expression ); + } + + @Override + public int hashCode() { + return Objects.hash( isNegated(), expression ); + } + @Override protected SqmNegatablePredicate createNegatedNode() { return new SqmExistsPredicate( expression, !isNegated(), nodeBuilder() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmGroupedPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmGroupedPredicate.java index 53983d86c534..e970d82e5f57 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmGroupedPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmGroupedPredicate.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SemanticQueryWalker; @@ -67,10 +68,22 @@ public List> getExpressions() { public SqmPredicate not() { return new SqmNegatedPredicate( this, nodeBuilder() ); } + @Override public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( '(' ); subPredicate.appendHqlString( hql, context ); hql.append( ')' ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmGroupedPredicate that + && Objects.equals( subPredicate, that.subPredicate ); + } + + @Override + public int hashCode() { + return Objects.hashCode( subPredicate ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInListPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInListPredicate.java index f26a653a1551..70eccf33b105 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInListPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInListPredicate.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Objects; import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.query.criteria.JpaExpression; @@ -161,6 +162,19 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( ')' ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmInListPredicate that + && this.isNegated() == that.isNegated() + && Objects.equals( this.testExpression, that.testExpression ) + && Objects.equals( this.listExpressions, that.listExpressions ); + } + + @Override + public int hashCode() { + return Objects.hash( isNegated(), testExpression, listExpressions ); + } + @Override protected SqmNegatablePredicate createNegatedNode() { return new SqmInListPredicate<>( testExpression, listExpressions, !isNegated(), nodeBuilder() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInSubQueryPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInSubQueryPredicate.java index e4e0b9b8b96e..0bb6cd8d0e6b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInSubQueryPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInSubQueryPredicate.java @@ -16,6 +16,8 @@ import jakarta.persistence.criteria.Expression; +import java.util.Objects; + import static org.hibernate.query.sqm.internal.TypecheckUtil.assertComparable; /** @@ -124,4 +126,17 @@ protected SqmNegatablePredicate createNegatedNode() { nodeBuilder() ); } + + @Override + public boolean equals(Object object) { + return object instanceof SqmInSubQueryPredicate that + && this.isNegated() == that.isNegated() + && Objects.equals( this.testExpression, that.testExpression ) + && Objects.equals( this.subQueryExpression, that.subQueryExpression ); + } + + @Override + public int hashCode() { + return Objects.hash( testExpression, subQueryExpression, isNegated() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmJunctionPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmJunctionPredicate.java index 418fc48399ed..dd0a66b4b0ea 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmJunctionPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmJunctionPredicate.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SemanticQueryWalker; @@ -105,9 +106,11 @@ public SqmPredicate not() { @Override public void appendHqlString(StringBuilder hql, SqmRenderContext context) { - final String separator = booleanOperator == BooleanOperator.AND - ? " and " - : " or "; + final String separator = + switch ( booleanOperator ) { + case AND -> " and "; + case OR -> " or "; + }; appendJunctionHqlString( predicates.get( 0 ), hql, context ); for ( int i = 1; i < predicates.size(); i++ ) { hql.append( separator ); @@ -132,4 +135,18 @@ private void appendJunctionHqlString(SqmPredicate p, StringBuilder sb, SqmRender p.appendHqlString( sb, context ); } } + + @Override + public boolean equals(Object object) { + if ( !(object instanceof SqmJunctionPredicate that) ) { + return false; + } + return booleanOperator == that.booleanOperator + && Objects.equals( predicates, that.predicates ); + } + + @Override + public int hashCode() { + return Objects.hash( booleanOperator, predicates ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmLikePredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmLikePredicate.java index e81663f7b3ef..da7c2ae132f8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmLikePredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmLikePredicate.java @@ -12,6 +12,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.query.sqm.tree.expression.SqmExpression; +import java.util.Objects; + import static org.hibernate.query.sqm.internal.TypecheckUtil.assertString; /** @@ -140,6 +142,21 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { } } + @Override + public boolean equals(Object object) { + return object instanceof SqmLikePredicate that + && this.isNegated() == that.isNegated() + && isCaseSensitive == that.isCaseSensitive + && Objects.equals( this.matchExpression, that.matchExpression ) + && Objects.equals( pattern, that.pattern ) + && Objects.equals( escapeCharacter, that.escapeCharacter ); + } + + @Override + public int hashCode() { + return Objects.hash( isNegated(), matchExpression, pattern, escapeCharacter, isCaseSensitive ); + } + @Override protected SqmNegatablePredicate createNegatedNode() { return new SqmLikePredicate( diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmMemberOfPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmMemberOfPredicate.java index 795e7c2e6b3b..6632deb70f5b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmMemberOfPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmMemberOfPredicate.java @@ -13,6 +13,8 @@ import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath; import org.hibernate.query.sqm.tree.expression.SqmExpression; +import java.util.Objects; + import static org.hibernate.query.sqm.internal.TypecheckUtil.areTypesComparable; /** @@ -95,6 +97,19 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { pluralPath.appendHqlString( hql, context ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmMemberOfPredicate that + && this.isNegated() == that.isNegated() + && Objects.equals( leftHandExpression, that.leftHandExpression ) + && Objects.equals( pluralPath, that.pluralPath ); + } + + @Override + public int hashCode() { + return Objects.hash( isNegated(), leftHandExpression, pluralPath ); + } + @Override protected SqmNegatablePredicate createNegatedNode() { return new SqmMemberOfPredicate( leftHandExpression, pluralPath, !isNegated(), nodeBuilder() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmNegatedPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmNegatedPredicate.java index 9b22d8f36eb4..4779363bbaea 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmNegatedPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmNegatedPredicate.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SemanticQueryWalker; @@ -74,6 +75,17 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( ')' ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmNegatedPredicate that + && Objects.equals( wrappedPredicate, that.wrappedPredicate ); + } + + @Override + public int hashCode() { + return Objects.hash( wrappedPredicate ); + } + @Override protected SqmNegatablePredicate createNegatedNode() { return new SqmNegatedPredicate( this, nodeBuilder() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmNullnessPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmNullnessPredicate.java index d8324031e365..74eabd0121b3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmNullnessPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmNullnessPredicate.java @@ -10,6 +10,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.query.sqm.tree.expression.SqmExpression; +import java.util.Objects; + /** * @author Steve Ebersole */ @@ -63,6 +65,18 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { } } + @Override + public boolean equals(Object object) { + return object instanceof SqmNullnessPredicate that + && this.isNegated() == that.isNegated() + && Objects.equals( this.expression, that.expression ); + } + + @Override + public int hashCode() { + return Objects.hash( isNegated(), expression ); + } + @Override protected SqmNegatablePredicate createNegatedNode() { return new SqmNullnessPredicate( expression, !isNegated(), nodeBuilder() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmTruthnessPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmTruthnessPredicate.java index bd377c34a4db..61ba80f84c5f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmTruthnessPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmTruthnessPredicate.java @@ -10,6 +10,8 @@ import org.hibernate.query.sqm.tree.SqmRenderContext; import org.hibernate.query.sqm.tree.expression.SqmExpression; +import java.util.Objects; + /** * @author Gavin King */ @@ -65,6 +67,19 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( getBooleanValue() ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmTruthnessPredicate that + && this.isNegated() == that.isNegated() + && this.value == that.value + && Objects.equals( this.expression, that.expression ); + } + + @Override + public int hashCode() { + return Objects.hash( isNegated(), value, expression ); + } + @Override protected SqmNegatablePredicate createNegatedNode() { return new SqmTruthnessPredicate( expression, getBooleanValue(), !isNegated(), nodeBuilder() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmWhereClause.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmWhereClause.java index 7b6048fd451f..9b2df0fe3647 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmWhereClause.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmWhereClause.java @@ -5,6 +5,7 @@ package org.hibernate.query.sqm.tree.predicate; import java.util.Collection; +import java.util.Objects; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.tree.SqmCopyContext; @@ -71,4 +72,15 @@ public void applyPredicates(Collection predicates) { public String toString() { return "where " + predicate; } + + @Override + public boolean equals(Object other) { + return other instanceof SqmWhereClause that + && Objects.equals( this.predicate, that.predicate ); + } + + @Override + public int hashCode() { + return predicate == null ? 0 : predicate.hashCode(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/AbstractSqmSelectQuery.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/AbstractSqmSelectQuery.java index 347938dd3d15..ea5a7ab94f13 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/AbstractSqmSelectQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/AbstractSqmSelectQuery.java @@ -8,6 +8,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.function.Function; @@ -19,7 +20,6 @@ import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.criteria.JpaSetReturningFunction; import org.hibernate.query.sqm.NodeBuilder; -import org.hibernate.query.sqm.spi.SqmCreationHelper; import org.hibernate.query.sqm.tree.AbstractSqmNode; import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmRenderContext; @@ -119,21 +119,21 @@ public JpaCteCriteria getCteCriteria(String cteName) { @Override public JpaCteCriteria with(AbstractQuery criteria) { - return withInternal( SqmCreationHelper.acquireUniqueAlias(), criteria ); + return withInternal( generateAlias(), criteria ); } @Override public JpaCteCriteria withRecursiveUnionAll( AbstractQuery baseCriteria, Function, AbstractQuery> recursiveCriteriaProducer) { - return withInternal( SqmCreationHelper.acquireUniqueAlias(), baseCriteria, false, recursiveCriteriaProducer ); + return withInternal( generateAlias(), baseCriteria, false, recursiveCriteriaProducer ); } @Override public JpaCteCriteria withRecursiveUnionDistinct( AbstractQuery baseCriteria, Function, AbstractQuery> recursiveCriteriaProducer) { - return withInternal( SqmCreationHelper.acquireUniqueAlias(), baseCriteria, true, recursiveCriteriaProducer ); + return withInternal( generateAlias(), baseCriteria, true, recursiveCriteriaProducer ); } @Override @@ -279,12 +279,11 @@ public SqmRoot from(Class entityClass) { return addRoot( new SqmRoot<>( nodeBuilder().getDomainModel().entity( entityClass ), - null, + generateAlias(), true, nodeBuilder() ) ); - } @Override @@ -315,14 +314,21 @@ private SqmRoot addRoot(SqmRoot root) { @Override public SqmRoot from(EntityType entityType) { - return addRoot( new SqmRoot<>( (EntityDomainType) entityType, null, true, nodeBuilder() ) ); + return addRoot( + new SqmRoot<>( + (EntityDomainType) entityType, + generateAlias(), + true, + nodeBuilder() + ) + ); } private void validateComplianceFromSubQuery() { if ( nodeBuilder().isJpaQueryComplianceEnabled() ) { throw new IllegalStateException( - "The JPA specification does not support subqueries in the from clause. " + - "Please disable the JPA query compliance if you want to use this feature." ); + "The JPA specification does not support subqueries in the from clause. " + + "Please disable the JPA query compliance if you want to use this feature." ); } } @@ -416,18 +422,28 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { sqmQueryPart.appendHqlString( hql, context ); } + @Override + public boolean equals(Object object) { + return object instanceof AbstractSqmSelectQuery that + && Objects.equals( this.resultType, that.resultType ) // for performance! + && Objects.equals( this.sqmQueryPart, that.sqmQueryPart ) + && Objects.equals( this.cteStatements, that.cteStatements ); + } + + @Override + public int hashCode() { + return Objects.hash( cteStatements, sqmQueryPart ); + } + @SuppressWarnings("unchecked") protected Selection getResultSelection(Selection[] selections) { final Class resultType = getResultType(); if ( resultType == null || resultType == Object.class ) { - switch ( selections.length ) { - case 0: - throw new IllegalArgumentException( "Empty selections passed to criteria query typed as Object" ); - case 1: - return (Selection) selections[0]; - default: - return (Selection) nodeBuilder().array( selections ); - } + return switch ( selections.length ) { + case 0 -> throw new IllegalArgumentException( "Empty selections passed to criteria query typed as Object" ); + case 1 -> (Selection) selections[0]; + default -> (Selection) nodeBuilder().array( selections ); + }; } else if ( Tuple.class.isAssignableFrom( resultType ) ) { return (Selection) nodeBuilder().tuple( selections ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmDynamicInstantiation.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmDynamicInstantiation.java index 2c40219f9908..7d9727bd2882 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmDynamicInstantiation.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmDynamicInstantiation.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Consumer; import org.hibernate.query.sqm.DynamicInstantiationNature; @@ -294,6 +295,18 @@ else if ( instantiationTarget.getNature() == MAP ) { hql.append( ')' ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmDynamicInstantiation that + && Objects.equals( instantiationTarget, that.instantiationTarget ) + && Objects.equals( arguments, that.arguments ); + } + + @Override + public int hashCode() { + return Objects.hash( instantiationTarget, arguments ); + } + @SuppressWarnings("unused") public SqmDynamicInstantiation makeShallowCopy() { return new SqmDynamicInstantiation<>( getInstantiationTarget(), nodeBuilder() ); @@ -309,6 +322,18 @@ private DynamicInstantiationTargetImpl(DynamicInstantiationNature nature, JavaTy this.javaType = javaType; } + @Override + public boolean equals(Object object) { + return object instanceof DynamicInstantiationTargetImpl that + && nature == that.nature + && Objects.equals( javaType, that.javaType ); + } + + @Override + public int hashCode() { + return Objects.hash( nature, javaType ); + } + @Override public DynamicInstantiationNature getNature() { return nature; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmDynamicInstantiationArgument.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmDynamicInstantiationArgument.java index 02c04eb8ccce..a6c733504f82 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmDynamicInstantiationArgument.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmDynamicInstantiationArgument.java @@ -9,6 +9,8 @@ import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmRenderContext; +import java.util.Objects; + /** * Represents an individual argument to a dynamic instantiation. * @@ -63,4 +65,16 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( " as " ).append( alias ); } } + + @Override + public boolean equals(Object object) { + return object instanceof SqmDynamicInstantiationArgument that + && Objects.equals( selectableNode, that.selectableNode ) + && Objects.equals( alias, that.alias ); + } + + @Override + public int hashCode() { + return Objects.hash( selectableNode, alias ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmJpaCompoundSelection.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmJpaCompoundSelection.java index 8dc32cb0012b..84097fa71b7a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmJpaCompoundSelection.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmJpaCompoundSelection.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.function.Consumer; import org.hibernate.query.criteria.JpaCompoundSelection; @@ -145,6 +146,17 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { } } + @Override + public boolean equals(Object object) { + return object instanceof SqmJpaCompoundSelection that + && Objects.equals( selectableNodes, that.selectableNodes ); + } + + @Override + public int hashCode() { + return Objects.hash( selectableNodes ); + } + @Override public void visitSubSelectableNodes(Consumer> jpaSelectionConsumer) { selectableNodes.forEach( jpaSelectionConsumer ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmOrderByClause.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmOrderByClause.java index 00e68db8e753..5f1afd24c123 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmOrderByClause.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmOrderByClause.java @@ -7,6 +7,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.expression.SqmAliasedNodeRef; @@ -85,4 +86,15 @@ public void setSortSpecifications(List sortSpecifications) } } } + + @Override + public boolean equals(Object object) { + return object instanceof SqmOrderByClause that + && Objects.equals( this.sortSpecifications, that.sortSpecifications ); + } + + @Override + public int hashCode() { + return Objects.hash( sortSpecifications ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQueryGroup.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQueryGroup.java index 45dddd6d054d..3186d0f6b963 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQueryGroup.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQueryGroup.java @@ -8,6 +8,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.Objects; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.query.common.FetchClauseType; @@ -243,4 +244,17 @@ private static void appendQueryPart(SqmQueryPart queryPart, StringBuilder sb, sb.append( ')' ); } } + + @Override + public boolean equals(Object object) { + return object instanceof SqmQueryGroup that + && super.equals( that ) + && this.setOperator == that.setOperator + && Objects.equals( this.queryParts, that.queryParts ); + } + + @Override + public int hashCode() { + return Objects.hash( super.hashCode(), queryParts, setOperator ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQueryPart.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQueryPart.java index df3a77fece26..15a71af2e65c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQueryPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQueryPart.java @@ -5,6 +5,7 @@ package org.hibernate.query.sqm.tree.select; import java.util.List; +import java.util.Objects; import org.hibernate.query.common.FetchClauseType; import org.hibernate.query.criteria.JpaExpression; @@ -175,39 +176,44 @@ public JpaQueryPart setFetch(JpaExpression fetch, FetchClau public abstract void validateQueryStructureAndFetchOwners(); public void appendHqlString(StringBuilder hql, SqmRenderContext context) { - if ( orderByClause == null || orderByClause.getSortSpecifications().isEmpty() ) { - return; - } - hql.append( " order by " ); - final List sortSpecifications = orderByClause.getSortSpecifications(); - sortSpecifications.get( 0 ).appendHqlString( hql, context ); - for ( int i = 1; i < sortSpecifications.size(); i++ ) { - hql.append( ", " ); - sortSpecifications.get( i ).appendHqlString( hql, context ); - } + if ( orderByClause != null && !orderByClause.getSortSpecifications().isEmpty() ) { + hql.append( " order by " ); + final List sortSpecifications = orderByClause.getSortSpecifications(); + sortSpecifications.get( 0 ).appendHqlString( hql, context ); + for ( int i = 1; i < sortSpecifications.size(); i++ ) { + hql.append( ", " ); + sortSpecifications.get( i ).appendHqlString( hql, context ); + } - if ( offsetExpression != null ) { - hql.append( " offset " ); - offsetExpression.appendHqlString( hql, context ); - hql.append( " rows " ); - } - if ( fetchExpression != null ) { - hql.append( " fetch first " ); - fetchExpression.appendHqlString( hql, context ); - switch ( fetchClauseType ) { - case ROWS_ONLY: - hql.append( " rows only" ); - break; - case ROWS_WITH_TIES: - hql.append( " rows with ties" ); - break; - case PERCENT_ONLY: - hql.append( " percent rows only" ); - break; - case PERCENT_WITH_TIES: - hql.append( " percent rows with ties" ); - break; + if ( offsetExpression != null ) { + hql.append( " offset " ); + offsetExpression.appendHqlString( hql, context ); + hql.append( " rows " ); + } + if ( fetchExpression != null ) { + hql.append( " fetch first " ); + fetchExpression.appendHqlString( hql, context ); + hql.append( switch ( fetchClauseType ) { + case ROWS_ONLY -> " rows only"; + case ROWS_WITH_TIES -> " rows with ties"; + case PERCENT_ONLY -> " percent rows only"; + case PERCENT_WITH_TIES -> " percent rows with ties"; + } ); } } } + + @Override + public boolean equals(Object object) { + return object instanceof SqmQueryPart that + && Objects.equals( orderByClause, that.orderByClause ) + && Objects.equals( offsetExpression, that.offsetExpression ) + && Objects.equals( fetchExpression, that.fetchExpression ) + && fetchClauseType == that.fetchClauseType; + } + + @Override + public int hashCode() { + return Objects.hash( orderByClause, offsetExpression, fetchExpression, fetchClauseType ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQuerySpec.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQuerySpec.java index d6b45f9dbba1..b6ec9288a855 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQuerySpec.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQuerySpec.java @@ -8,6 +8,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; import org.hibernate.Internal; @@ -595,10 +596,12 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( "distinct " ); } final List> selections = selectClause.getSelections(); - selections.get( 0 ).appendHqlString( hql, context ); - for ( int i = 1; i < selections.size(); i++ ) { - hql.append( ", " ); - selections.get( i ).appendHqlString( hql, context ); + if ( !selections.isEmpty() ) { + selections.get( 0 ).appendHqlString( hql, context ); + for ( int i = 1; i < selections.size(); i++ ) { + hql.append( ", " ); + selections.get( i ).appendHqlString( hql, context ); + } } } if ( fromClause != null ) { @@ -676,4 +679,22 @@ private boolean isSameOrParent(NavigablePath navigablePath, List } return false; } + + @Override + public boolean equals(Object other) { + return other instanceof SqmQuerySpec that + && super.equals( other ) + && Objects.equals( this.fromClause, that.fromClause ) + && Objects.equals( this.selectClause, that.selectClause ) + && Objects.equals( this.whereClause, that.whereClause ) + && Objects.equals( this.groupByClauseExpressions, that.groupByClauseExpressions ) + && Objects.equals( this.havingClausePredicate, that.havingClausePredicate ); + } + + @Override + public int hashCode() { + return Objects.hash( super.hashCode(), + fromClause, selectClause, whereClause, + groupByClauseExpressions, havingClausePredicate ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectClause.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectClause.java index 15ceefc51914..cf905603cdfc 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectClause.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectClause.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.sqm.NodeBuilder; @@ -146,4 +147,16 @@ public JavaType getJavaTypeDescriptor() { public String getAlias() { return null; } + + @Override + public boolean equals(Object other) { + return other instanceof SqmSelectClause that + && distinct == that.distinct + && Objects.equals( this.selections, that.selections ); + } + + @Override + public int hashCode() { + return Objects.hash( distinct, selections ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java index 9a6630ae57d9..f1cdf20e44d6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java @@ -106,7 +106,10 @@ public SqmSelectStatement(Class resultJavaType, NodeBuilder nodeBuilder) { * in order to allow correct parameter handing. */ public SqmSelectStatement(SqmSelectStatement original) { - super( original.getQueryPart(), original.getCteStatementMap(), original.getResultType(), original.nodeBuilder() ); + super( original.getQueryPart(), + original.getCteStatementMap(), + original.getResultType(), + original.nodeBuilder() ); this.querySource = CRITERIA; } @@ -270,8 +273,8 @@ public void addParameter(SqmParameter parameter) { protected JpaCteCriteria withInternal(String name, AbstractQuery criteria) { if ( criteria instanceof SqmSubQuery ) { throw new IllegalArgumentException( - "Invalid query type provided to root query 'with' method, " + - "expecting a root query to use as CTE instead found a subquery" + "Invalid query type provided to root query 'with' method, " + + "expecting a root query to use as CTE instead found a subquery" ); } return super.withInternal( name, criteria ); @@ -286,8 +289,8 @@ protected JpaCteCriteria withInternal( AbstractQuery> recursiveCriteriaProducer) { if ( baseCriteria instanceof SqmSubQuery ) { throw new IllegalArgumentException( - "Invalid query type provided to root query 'with' method, " + - "expecting a root query to use as CTE instead found a subquery" + "Invalid query type provided to root query 'with' method, " + + "expecting a root query to use as CTE instead found a subquery" ); } return super.withInternal( name, baseCriteria, unionDistinct, recursiveCriteriaProducer ); @@ -523,13 +526,14 @@ private void validateComplianceFetchOffset() { public SqmSelectStatement createCountQuery() { final SqmSelectStatement copy = createCopy( noParamCopyContext(), Object.class ); final SqmQueryPart queryPart = copy.getQueryPart(); - final SqmQuerySpec querySpec; //TODO: detect queries with no 'group by', but aggregate functions // in 'select' list (we don't even need to hit the database to // know they return exactly one row) - if ( queryPart.isSimpleQueryPart() - && !( querySpec = (SqmQuerySpec) queryPart ).isDistinct() + if ( queryPart instanceof SqmQuerySpec querySpec + && !querySpec.isDistinct() && querySpec.getGroupingExpressions().isEmpty() ) { + // we can just remove any fetch joins and + // replace the select list with count(*) for ( SqmRoot root : querySpec.getRootList() ) { root.removeLeftFetchJoins(); } @@ -537,13 +541,13 @@ public SqmSelectStatement createCountQuery() { if ( querySpec.getFetch() == null && querySpec.getOffset() == null ) { querySpec.setOrderByClause( null ); } - return (SqmSelectStatement) copy; } else { + // we have to wrap query in an outer query aliasSelections( queryPart ); - final SqmSubQuery subquery = new SqmSubQuery<>( copy, queryPart, null, nodeBuilder() ); final SqmSelectStatement query = nodeBuilder().createQuery( Long.class ); + final SqmSubQuery subquery = new SqmSubQuery<>( query, queryPart, null, nodeBuilder() ); query.from( subquery ); query.select( nodeBuilder().count() ); if ( subquery.getFetch() == null && subquery.getOffset() == null ) { @@ -553,6 +557,10 @@ public SqmSelectStatement createCountQuery() { } } + /** + * Add synthetic aliases to all elements of the {@code select} + * list, allowing the query to be reused as a subquery. + */ private void aliasSelections(SqmQueryPart queryPart) { if ( queryPart.isSimpleQueryPart() ) { final SqmQuerySpec querySpec = queryPart.getFirstQuerySpec(); @@ -576,8 +584,18 @@ private void aliasSelection(JpaSelection selection, LinkedHashSet that + && Objects.equals( this.selectableNode, that.selectableNode ) + && Objects.equals( this.alias, that.alias ); + } + + @Override + public int hashCode() { + return Objects.hash( selectableNode, alias ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSortSpecification.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSortSpecification.java index 66319c5dfc83..51bafb5f4548 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSortSpecification.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSortSpecification.java @@ -34,7 +34,7 @@ public SqmSortSpecification( } public SqmSortSpecification( - SqmExpression sortExpression, + SqmExpression sortExpression, SortDirection sortOrder, Nulls nullPrecedence, boolean ignoreCase) { @@ -141,19 +141,15 @@ else if ( nullPrecedence != null ) { } @Override - public boolean equals(Object o) { - if ( this == o ) { + public boolean equals(Object other) { + if ( this == other ) { return true; } - else if ( !(o instanceof SqmSortSpecification that) ) { - return false; - } - else { - // used in SqmInterpretationsKey.equals() - return Objects.equals( sortExpression, that.sortExpression ) - && sortOrder == that.sortOrder - && nullPrecedence == that.nullPrecedence; - } + // used in SqmInterpretationsKey.equals() + return other instanceof SqmSortSpecification that + && Objects.equals( this.sortExpression, that.sortExpression ) + && this.sortOrder == that.sortOrder + && this.nullPrecedence == that.nullPrecedence; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSubQuery.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSubQuery.java index 37063efacade..f20d94cc13b9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSubQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSubQuery.java @@ -11,6 +11,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.function.Function; @@ -771,4 +772,20 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { hql.append( ')' ); } + @Override + public boolean equals(Object object) { + return object instanceof SqmSubQuery that + && Objects.equals( this.alias, that.alias ) + && super.equals( object ); + } + + @Override + public int hashCode() { + return Objects.hash( super.hashCode(), alias ); + } + + @Override + public String generateAlias() { + return parent.generateAlias(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/update/SqmUpdateStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/update/SqmUpdateStatement.java index 64ae48c8332b..727ff25e00e7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/update/SqmUpdateStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/update/SqmUpdateStatement.java @@ -7,6 +7,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import org.hibernate.HibernateException; @@ -79,7 +80,7 @@ public SqmUpdateStatement(Class targetEntity, SqmCriteriaNodeBuilder nodeBuil super( new SqmRoot<>( nodeBuilder.getDomainModel().entity( targetEntity ), - null, + "_0", !nodeBuilder.isJpaQueryComplianceEnabled(), nodeBuilder ), @@ -287,7 +288,22 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { SqmFromClause.appendJoins( root, hql, context ); SqmFromClause.appendTreatJoins( root, hql, context ); setClause.appendHqlString( hql, context ); - super.appendHqlString( hql, context ); } + + @Override + public boolean equals(Object node) { + return node instanceof SqmUpdateStatement that + && super.equals( node ) + && this.versioned == that.versioned + && Objects.equals( this.setClause, that.setClause ) + && Objects.equals( this.getTarget(), that.getTarget() ) + && Objects.equals( this.getWhereClause(), that.getWhereClause() ) + && Objects.equals( this.getCteStatements(), that.getCteStatements() ); + } + + @Override + public int hashCode() { + return Objects.hash( versioned, setClause, getTarget(), getWhereClause(), getCteStatements() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcParameterBindingsImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcParameterBindingsImpl.java index 92f2ef209155..ca1783a46227 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcParameterBindingsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcParameterBindingsImpl.java @@ -5,13 +5,11 @@ package org.hibernate.sql.exec.internal; import java.util.Collection; -import java.util.Collections; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.function.BiConsumer; -import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.metamodel.mapping.BasicValuedMapping; import org.hibernate.metamodel.mapping.JdbcMapping; @@ -28,6 +26,8 @@ import org.hibernate.type.BasicTypeReference; import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; +import static java.util.Collections.emptyList; + /** * Standard implementation of JdbcParameterBindings * @@ -50,9 +50,8 @@ public JdbcParameterBindingsImpl( if ( !parameterOccurrences.isEmpty() ) { bindingMap = new IdentityHashMap<>( parameterOccurrences.size() ); - final Dialect dialect = factory.getJdbcServices().getDialect(); final boolean paddingEnabled = factory.getSessionFactoryOptions().inClauseParameterPaddingEnabled(); - final int inExprLimit = dialect.getParameterCountLimit(); + final int inExprLimit = factory.getJdbcServices().getDialect().getParameterCountLimit(); for ( ParameterOccurrence occurrence : parameterOccurrences ) { final QueryParameterImplementor param = occurrence.parameter(); @@ -139,11 +138,8 @@ else if ( type instanceof BasicValuedMapping basicValuedMapping ) { } private BindableType determineParamType(QueryParameterImplementor param, QueryParameterBinding binding) { - BindableType type = binding.getBindType(); - if ( type == null ) { - type = param.getHibernateType(); - } - return type; + final BindableType type = binding.getBindType(); + return type == null ? param.getHibernateType() : type; } @Override @@ -151,30 +147,25 @@ public void addBinding(JdbcParameter parameter, JdbcParameterBinding binding) { if ( bindingMap == null ) { bindingMap = new IdentityHashMap<>(); } - bindingMap.put( parameter, binding ); } @Override public Collection getBindings() { - return bindingMap == null ? Collections.emptyList() : bindingMap.values(); + return bindingMap == null ? emptyList() : bindingMap.values(); } @Override public JdbcParameterBinding getBinding(JdbcParameter parameter) { - if ( bindingMap == null ) { - return null; - } - return bindingMap.get( parameter ); + return bindingMap == null ? null : bindingMap.get( parameter ); } @Override public void visitBindings(BiConsumer action) { - if ( bindingMap == null ) { - return; - } - for ( Map.Entry entry : bindingMap.entrySet() ) { - action.accept( entry.getKey(), entry.getValue() ); + if ( bindingMap != null ) { + for ( var entry : bindingMap.entrySet() ) { + action.accept( entry.getKey(), entry.getValue() ); + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/querycache/AbstractQueryCacheResultTransformerTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/querycache/AbstractQueryCacheResultTransformerTest.java index 6a509b0d60e5..d4f4a12106ac 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/querycache/AbstractQueryCacheResultTransformerTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/querycache/AbstractQueryCacheResultTransformerTest.java @@ -111,7 +111,7 @@ protected Object getResults(Session s, boolean isSingleResult) throws Exception query.setResultTransformer( getResultTransformer() ); } - return ( isSingleResult ? query.uniqueResult() : query.list() ); + return isSingleResult ? query.uniqueResult() : query.list(); } } From 9f58d545ae2b26133b61b1c7e722f64ef3f4a7aa Mon Sep 17 00:00:00 2001 From: Gavin King Date: Mon, 28 Apr 2025 12:10:27 +0200 Subject: [PATCH 3/5] fix some unnecessary use of raw types --- .../tree/expression/JpaCriteriaParameter.java | 4 ++-- .../SqmJpaCriteriaParameterWrapper.java | 4 ++-- .../tree/expression/SqmNamedParameter.java | 4 ++-- .../sqm/tree/expression/SqmParameter.java | 22 +++++++++---------- .../expression/SqmPositionalParameter.java | 4 ++-- .../ValueBindJpaCriteriaParameter.java | 2 +- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/JpaCriteriaParameter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/JpaCriteriaParameter.java index af5d1e28b858..7d9809bae60b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/JpaCriteriaParameter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/JpaCriteriaParameter.java @@ -148,8 +148,8 @@ private String name(SqmRenderContext context) { } @Override - public int compareTo(SqmParameter parameter) { - return parameter instanceof JpaCriteriaParameter + public int compareTo(SqmParameter parameter) { + return parameter instanceof JpaCriteriaParameter ? Integer.compare( hashCode(), parameter.hashCode() ) : 1; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmJpaCriteriaParameterWrapper.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmJpaCriteriaParameterWrapper.java index e58163b60d66..f748b7b9e8c5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmJpaCriteriaParameterWrapper.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmJpaCriteriaParameterWrapper.java @@ -129,8 +129,8 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { } @Override - public int compareTo(SqmParameter anotherParameter) { - return anotherParameter instanceof SqmJpaCriteriaParameterWrapper wrapper + public int compareTo(SqmParameter parameter) { + return parameter instanceof SqmJpaCriteriaParameterWrapper wrapper ? getJpaCriteriaParameter().compareTo( wrapper.getJpaCriteriaParameter() ) : 1; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmNamedParameter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmNamedParameter.java index 253a717db300..daebcc2fd008 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmNamedParameter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmNamedParameter.java @@ -83,8 +83,8 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { } @Override - public int compareTo(SqmParameter anotherParameter) { - return anotherParameter instanceof SqmNamedParameter namedParameter + public int compareTo(SqmParameter parameter) { + return parameter instanceof SqmNamedParameter namedParameter ? getName().compareTo( namedParameter.getName() ) : -1; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmParameter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmParameter.java index 6ee8f64384fd..0c29c5f1f8d8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmParameter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmParameter.java @@ -75,21 +75,21 @@ public interface SqmParameter extends SqmExpression, JpaParameterExpressio * support any previous extensions */ @Override - default int compareTo(SqmParameter anotherParameter) { - if ( this instanceof SqmNamedParameter one ) { - return anotherParameter instanceof SqmNamedParameter - ? one.getName().compareTo( anotherParameter.getName() ) + default int compareTo(SqmParameter parameter) { + if ( this instanceof SqmNamedParameter one ) { + return parameter instanceof SqmNamedParameter + ? one.getName().compareTo( parameter.getName() ) : -1; } - else if ( this instanceof SqmPositionalParameter one ) { - return anotherParameter instanceof SqmPositionalParameter - ? one.getPosition().compareTo( anotherParameter.getPosition() ) + else if ( this instanceof SqmPositionalParameter one ) { + return parameter instanceof SqmPositionalParameter + ? one.getPosition().compareTo( parameter.getPosition() ) : 1; } - else if ( this instanceof SqmJpaCriteriaParameterWrapper - && anotherParameter instanceof SqmJpaCriteriaParameterWrapper ) { - return Integer.compare( this.hashCode(), anotherParameter.hashCode() ); + else if ( this instanceof SqmJpaCriteriaParameterWrapper + && parameter instanceof SqmJpaCriteriaParameterWrapper ) { + return Integer.compare( this.hashCode(), parameter.hashCode() ); } - throw new HibernateException( "Unexpected SqmParameter type for comparison : " + this + " & " + anotherParameter ); + throw new HibernateException( "Unexpected SqmParameter type for comparison : " + this + " & " + parameter ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmPositionalParameter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmPositionalParameter.java index 38cc6ee43c25..59ff66f9376f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmPositionalParameter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmPositionalParameter.java @@ -85,8 +85,8 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { } @Override - public int compareTo(SqmParameter anotherParameter) { - return anotherParameter instanceof SqmPositionalParameter positionalParameter + public int compareTo(SqmParameter parameter) { + return parameter instanceof SqmPositionalParameter positionalParameter ? getPosition().compareTo( positionalParameter.getPosition() ) : 1; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/ValueBindJpaCriteriaParameter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/ValueBindJpaCriteriaParameter.java index 663651c7f99a..a01f97933242 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/ValueBindJpaCriteriaParameter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/ValueBindJpaCriteriaParameter.java @@ -51,7 +51,7 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) { @Override // TODO: fix this - public int compareTo(SqmParameter parameter) { + public int compareTo(SqmParameter parameter) { return this == parameter ? 0 : 1; } From eb831298e480602971cc2c3239373099c0b27f2b Mon Sep 17 00:00:00 2001 From: Gavin King Date: Mon, 28 Apr 2025 13:15:38 +0200 Subject: [PATCH 4/5] HHH-17002, HHH-18820, HHH-19391, HHH-18514 deal with anonymous CTE problem - just deprecate the method, since HQL doesn't allow anonymous CTEs - perhaps we need to do the same for the withRescursiveXxxxx() methods - I don't really see a better fix, since nested CTEs can be composed before composing them with the outer query (perhaps we could modify the aliases of all CTEs after the whole query is built) --- .../java/org/hibernate/query/criteria/JpaCteContainer.java | 4 ++++ .../hibernate/query/sqm/tree/AbstractSqmDmlStatement.java | 6 ++++-- .../query/sqm/tree/select/AbstractSqmSelectQuery.java | 6 ++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaCteContainer.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaCteContainer.java index 8303809855a3..eb13b047d0f3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaCteContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaCteContainer.java @@ -33,7 +33,11 @@ public interface JpaCteContainer extends JpaCriteriaNode { * which can be used for querying. * * @see JpaCriteriaQuery#from(JpaCteCriteria) + * + * @deprecated Use {@link #with(String, AbstractQuery)} and provide an explicit + * name for the CTE */ + @Deprecated(since = "7", forRemoval = true) JpaCteCriteria with(AbstractQuery criteria); /** diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmDmlStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmDmlStatement.java index 72c9e60285bc..79e31cf55f13 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmDmlStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmDmlStatement.java @@ -10,6 +10,7 @@ import org.hibernate.query.criteria.JpaRoot; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SqmQuerySource; +import org.hibernate.query.sqm.spi.SqmCreationHelper; import org.hibernate.query.sqm.tree.cte.SqmCteContainer; import org.hibernate.query.sqm.tree.cte.SqmCteStatement; import org.hibernate.query.sqm.tree.expression.SqmParameter; @@ -91,9 +92,10 @@ public JpaCteCriteria getCteCriteria(String cteName) { return (JpaCteCriteria) cteStatements.get( cteName ); } - @Override + @Override @Deprecated public JpaCteCriteria with(AbstractQuery criteria) { - return withInternal( generateAlias(), criteria ); + // Use of acquireUniqueAlias() results in interpretation cache miss + return withInternal( "_" + SqmCreationHelper.acquireUniqueAlias(), criteria ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/AbstractSqmSelectQuery.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/AbstractSqmSelectQuery.java index ea5a7ab94f13..f28940ef844a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/AbstractSqmSelectQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/AbstractSqmSelectQuery.java @@ -20,6 +20,7 @@ import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.criteria.JpaSetReturningFunction; import org.hibernate.query.sqm.NodeBuilder; +import org.hibernate.query.sqm.spi.SqmCreationHelper; import org.hibernate.query.sqm.tree.AbstractSqmNode; import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmRenderContext; @@ -117,9 +118,10 @@ public JpaCteCriteria getCteCriteria(String cteName) { return (JpaCteCriteria) cteStatements.get( cteName ); } - @Override + @Override @Deprecated public JpaCteCriteria with(AbstractQuery criteria) { - return withInternal( generateAlias(), criteria ); + // Use of acquireUniqueAlias() results in interpretation cache miss + return withInternal( "_" + SqmCreationHelper.acquireUniqueAlias(), criteria ); } @Override From 6b33971249d5fc5e217482c9689662cb26e95c61 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Tue, 29 Apr 2025 07:40:04 +0200 Subject: [PATCH 5/5] HHH-17002, HHH-18820, HHH-19391, HHH-18514 fix generated aliases Oracle disapproves of aliases of form "_1" --- .../java/org/hibernate/query/sqm/tree/AbstractSqmStatement.java | 2 +- .../org/hibernate/query/sqm/tree/select/SqmSelectStatement.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmStatement.java index b0f294d1b12c..2077d3b0208a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmStatement.java @@ -103,6 +103,6 @@ public Set> getParameters() { @Override public String generateAlias() { - return "_" + (++aliasCounter); + return "t_" + (++aliasCounter); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java index f1cdf20e44d6..4fd332a125c7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java @@ -596,6 +596,6 @@ else if ( !newSelections.contains( selection ) ) { @Override public String generateAlias() { - return "_" + (++aliasCounter); + return "t_" + (++aliasCounter); } }