Skip to content

HHH-17002, HHH-18820, HHH-19391, HHH-18514 equals() and hashCode() for SQM nodes #10139

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -63,7 +63,6 @@ public H2UnnestFunction(int maximumArraySize) {
protected <T> SelfRenderingSqmSetReturningFunction<T> generateSqmSetReturningFunctionExpression(
List<? extends SqmTypedNode<?>> arguments,
QueryEngine queryEngine) {
//noinspection unchecked
return new SelfRenderingSqmSetReturningFunction<>(
this,
this,
Original file line number Diff line number Diff line change
@@ -13,6 +13,8 @@
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.spi.NavigablePath;

import java.util.Objects;

public class AnyDiscriminatorSqmPath<T> extends AbstractSqmPath<T> implements DiscriminatorSqmPath<T> {

protected AnyDiscriminatorSqmPath(
@@ -46,4 +48,16 @@ public AnyDiscriminatorSqmPathSource<T> getExpressible() {
// return (AnyDiscriminatorSqmPathSource<T>) getNodeType();
return (AnyDiscriminatorSqmPathSource<T>) getReferencedPathSource();
}


@Override
public boolean equals(Object object) {
return object instanceof AnyDiscriminatorSqmPath<?> that
&& Objects.equals( this.getLhs(), that.getLhs() );
}

@Override
public int hashCode() {
return getLhs().hashCode();
}
}
Original file line number Diff line number Diff line change
@@ -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<T> copy(SqmCopyContext context) {
public <X> X accept(SemanticQueryWalker<X> 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();
}
}
Original file line number Diff line number Diff line change
@@ -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
*
@@ -72,6 +74,16 @@ public <X> X accept(SemanticQueryWalker<X> walker) {
return entityDescriptor.hasSubclasses()
? walker.visitDiscriminatorPath( this )
: walker.visitEntityTypeLiteralExpression( new SqmLiteralEntityType( entityDomainType, nodeBuilder() ) );
}

@Override
public boolean equals(Object object) {
return object instanceof EntityDiscriminatorSqmPath<?> that
&& Objects.equals( this.getLhs(), that.getLhs() );
}

@Override
public int hashCode() {
return getLhs().hashCode();
}
}
Original file line number Diff line number Diff line change
@@ -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)
<T> JpaCteCriteria<T> with(AbstractQuery<T> criteria);

/**
Original file line number Diff line number Diff line change
@@ -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 <R> SqmSelectStatement<R>[] split(SqmSelectStatement<R> 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<R>[] sqmSelectStatement = new SqmSelectStatement[] { statement };
return sqmSelectStatement;
}

final SqmPolymorphicRootDescriptor<R> unmappedPolymorphicDescriptor = (SqmPolymorphicRootDescriptor<R>) unmappedPolymorphicReference.getReferencedPathSource();
final Set<EntityDomainType<? extends R>> implementors = unmappedPolymorphicDescriptor.getImplementors();
final var unmappedPolymorphicDescriptor =
(SqmPolymorphicRootDescriptor<R>)
unmappedPolymorphicReference.getReferencedPathSource();
var implementors = unmappedPolymorphicDescriptor.getImplementors();
@SuppressWarnings("unchecked")
final SqmSelectStatement<R>[] 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 <R> SqmDeleteStatement<R>[] split(SqmDeleteStatement<R> 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<R>[] sqmDeleteStatement = new SqmDeleteStatement[] { statement };
return sqmDeleteStatement;
}

final SqmPolymorphicRootDescriptor<R> unmappedPolymorphicDescriptor =
(SqmPolymorphicRootDescriptor<R>) unmappedPolymorphicReference.getReferencedPathSource();
final Set<EntityDomainType<? extends R>> implementors = unmappedPolymorphicDescriptor.getImplementors();
final var unmappedPolymorphicDescriptor =
(SqmPolymorphicRootDescriptor<R>)
unmappedPolymorphicReference.getReferencedPathSource();
final var implementors = unmappedPolymorphicDescriptor.getImplementors();
@SuppressWarnings("unchecked")
final SqmDeleteStatement<R>[] 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;
}
}
Original file line number Diff line number Diff line change
@@ -1221,7 +1221,7 @@ private SqmFromClause buildInferredFromClause(HqlParser.SelectClauseContext sele
final EntityDomainType<R> entityDescriptor = getResultEntity();
if ( entityDescriptor != null ) {
final SqmRoot<R> sqmRoot =
new SqmRoot<>( entityDescriptor, null, false, creationContext.getNodeBuilder() );
new SqmRoot<>( entityDescriptor, "_0", false, creationContext.getNodeBuilder() );
processingStateStack.getCurrent().getPathRegistry().register( sqmRoot );
fromClause.addRoot( sqmRoot );
}
Original file line number Diff line number Diff line change
@@ -134,24 +134,21 @@ public class SqmTreeCreationHelper {
*/
public static <E> void handleRootAsCrossJoin(
HqlParser.EntityWithJoinsContext entityWithJoinsContext,
SqmRoot<?> sqmPrimaryRoot,
SqmRoot<E> sqmPrimaryRoot,
SemanticQueryBuilder<?> sqmBuilder) {
final HqlParser.RootEntityContext fromRootContext = (HqlParser.RootEntityContext) entityWithJoinsContext.fromRoot();
final HqlParser.RootEntityContext fromRootContext =
(HqlParser.RootEntityContext) entityWithJoinsContext.fromRoot();

//noinspection unchecked
final SqmRoot<E> sqmRoot = (SqmRoot<E>) 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<?,E> pseudoCrossJoin = new SqmEntityJoin<>(
final SqmEntityJoin<E,E> 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();
Original file line number Diff line number Diff line change
@@ -162,7 +162,7 @@ public <P> QueryParameterBinding<P> getBinding(String name) {

@Override
public void validate() {
for ( Map.Entry<QueryParameter<?>, QueryParameterBinding<?>> entry : parameterBindingMap.entrySet() ) {
for ( var entry : parameterBindingMap.entrySet() ) {
if ( !entry.getValue().isBound() ) {
final QueryParameter<?> queryParameter = entry.getKey();
if ( queryParameter.isNamed() ) {
Original file line number Diff line number Diff line change
@@ -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;
@@ -255,4 +256,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();
}
}
Original file line number Diff line number Diff line change
@@ -138,28 +138,31 @@ public void appendHqlString(StringBuilder hql, SqmRenderContext context) {
final List<? extends SqmTypedNode<?>> 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<SqmSortSpecification> 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( ')' );
}
Original file line number Diff line number Diff line change
@@ -208,38 +208,21 @@ public QuerySqmImpl(
SqmStatement<R> criteria,
boolean copyAst,
Class<R> 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 );

domainParameterXref = DomainParameterXref.from( sqm );
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() ) {
Original file line number Diff line number Diff line change
@@ -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
Loading