From 6f0a631917ff9338f5af144513ea6ab4e065044b Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Tue, 22 Nov 2022 14:25:36 +0100 Subject: [PATCH] HHH-15718 Polymorphic queries with condition do not work --- .../query/hql/internal/QuerySplitter.java | 36 ++++++++++++++----- .../domain/SqmPolymorphicRootDescriptor.java | 25 +++++++------ 2 files changed, 42 insertions(+), 19 deletions(-) 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 f39572749a..54bae5325e 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 @@ -91,7 +91,6 @@ import org.hibernate.query.sqm.tree.update.SqmUpdateStatement; import org.hibernate.type.descriptor.java.JavaType; import jakarta.persistence.criteria.AbstractQuery; -import jakarta.persistence.criteria.CriteriaQuery; /** * Handles splitting queries containing unmapped polymorphic references. @@ -710,12 +709,15 @@ public class QuerySplitter { public SqmBasicValuedSimplePath visitBasicValuedPath(SqmBasicValuedSimplePath path) { final SqmPathRegistry pathRegistry = getProcessingStateStack().getCurrent().getPathRegistry(); + final SqmPath lhs = findLhs( path, pathRegistry ); + final SqmBasicValuedSimplePath copy = new SqmBasicValuedSimplePath<>( - path.getNavigablePath(), + lhs.getNavigablePath().append( path.getNavigablePath().getLocalName() ), path.getReferencedPathSource(), - pathRegistry.findFromByPath( path.getLhs().getNavigablePath() ), + lhs, path.nodeBuilder() ); + pathRegistry.register( copy ); sqmPathCopyMap.put( path.getNavigablePath(), copy ); return copy; @@ -724,10 +726,11 @@ public class QuerySplitter { @Override public SqmEmbeddedValuedSimplePath visitEmbeddableValuedPath(SqmEmbeddedValuedSimplePath path) { final SqmPathRegistry pathRegistry = getProcessingStateStack().getCurrent().getPathRegistry(); + final SqmPath lhs = findLhs( path, pathRegistry ); final SqmEmbeddedValuedSimplePath copy = new SqmEmbeddedValuedSimplePath<>( - path.getNavigablePath(), + lhs.getNavigablePath().append( path.getNavigablePath().getLocalName() ), path.getReferencedPathSource(), - pathRegistry.findFromByPath( path.getLhs().getNavigablePath() ), + lhs, path.nodeBuilder() ); pathRegistry.register( copy ); @@ -738,10 +741,11 @@ public class QuerySplitter { @Override public SqmEntityValuedSimplePath visitEntityValuedPath(SqmEntityValuedSimplePath path) { final SqmPathRegistry pathRegistry = getProcessingStateStack().getCurrent().getPathRegistry(); + final SqmPath lhs = findLhs( path, pathRegistry ); final SqmEntityValuedSimplePath copy = new SqmEntityValuedSimplePath<>( - path.getNavigablePath(), + lhs.getNavigablePath().append( path.getNavigablePath().getLocalName() ), path.getReferencedPathSource(), - pathRegistry.findFromByPath( path.getLhs().getNavigablePath() ), + lhs, path.nodeBuilder() ); pathRegistry.register( copy ); @@ -752,10 +756,12 @@ public class QuerySplitter { @Override public SqmPluralValuedSimplePath visitPluralValuedPath(SqmPluralValuedSimplePath path) { final SqmPathRegistry pathRegistry = getProcessingStateStack().getCurrent().getPathRegistry(); + SqmPath lhs = findLhs( path, pathRegistry ); + final SqmPluralValuedSimplePath copy = new SqmPluralValuedSimplePath<>( path.getNavigablePath(), path.getReferencedPathSource(), - pathRegistry.findFromByPath( path.getLhs().getNavigablePath() ), + lhs, path.nodeBuilder() ); pathRegistry.register( copy ); @@ -763,13 +769,25 @@ public class QuerySplitter { return copy; } + private SqmPath findLhs(SqmPath path, SqmPathRegistry pathRegistry) { + final SqmPath lhs = path.getLhs(); + final SqmPath sqmFrom = sqmPathCopyMap.get( lhs.getNavigablePath() ); + if ( sqmFrom != null ) { + return pathRegistry.findFromByPath( sqmFrom.getNavigablePath() ); + } + else { + return (SqmPath) lhs.accept( this ); + } + } + @Override public SqmSelectClause visitSelectClause(SqmSelectClause selectClause) { SqmSelectClause copy = new SqmSelectClause( selectClause.isDistinct(), selectClause.nodeBuilder() ); for ( SqmSelection selection : selectClause.getSelections() ) { + SqmExpression selectableNode = (SqmExpression) selection.getSelectableNode().accept( this ); copy.addSelection( new SqmSelection<>( - (SqmExpression) selection.getSelectableNode().accept( this ), + selectableNode, selection.getAlias(), selectClause.nodeBuilder() ) diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java index 837fe63ed1..a96c07335f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java @@ -74,27 +74,32 @@ public class SqmPolymorphicRootDescriptor implements EntityDomainType { final List> subList = implementorsList.subList( 1, implementors.size() - 1 ); firstImplementor.visitAttributes( attribute -> { - // for each of its attributes, check whether the other implementors also expose it - for ( EntityDomainType navigable : subList ) { - if ( navigable.findAttribute( attribute.getName() ) == null ) { - // we found an implementor that does not expose that attribute, - // so break-out to the next attribute - break; - } - - // if we get here - they all had it. so put it in the workMap + if ( isACommonAttribute( subList, attribute ) ) { + // if isACommonAttribute - they all had it. so put it in the workMap // // todo (6.0) : Atm We use the attribute from the first implementor directly for each implementor // need to handle this in QuerySplitter somehow + workMap.put( attribute.getName(), attribute ); } - } ); } this.commonAttributes = Collections.unmodifiableMap( workMap ); } + private static boolean isACommonAttribute(List> subList, PersistentAttribute attribute) { + // for each of its attributes, check whether the other implementors also expose it + for ( EntityDomainType navigable : subList ) { + if ( navigable.findAttribute( attribute.getName() ) != null ) { + // we found an implementor that does not expose that attribute, + // so break-out to the next attribute + return false; + } + } + return true; + } + public Set> getImplementors() { return new HashSet<>( implementors ); }