diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntitySqmPathSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntitySqmPathSource.java index 672ca3b774..c7958dc11f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntitySqmPathSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntitySqmPathSource.java @@ -7,6 +7,9 @@ package org.hibernate.metamodel.model.domain.internal; import org.hibernate.metamodel.model.domain.EntityDomainType; +import org.hibernate.metamodel.model.domain.PersistentAttribute; +import org.hibernate.metamodel.model.domain.SingularPersistentAttribute; +import org.hibernate.query.SemanticException; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.produce.spi.SqmCreationState; @@ -32,7 +35,17 @@ public class EntitySqmPathSource extends AbstractSqmPathSource { @Override public SqmPathSource findSubPathSource(String name) { - return (SqmPathSource) getSqmPathType().findAttribute( name ); + final PersistentAttribute attribute = getSqmPathType().findAttribute( name ); + if ( attribute != null ) { + return (SqmPathSource) attribute; + } + + final SingularPersistentAttribute idAttribute = getSqmPathType().findIdAttribute(); + if ( idAttribute != null && idAttribute.getName().equals( name ) ) { + return idAttribute; + } + + throw new SemanticException( "Unknown sub-path name : " + name ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java index 425cd73027..90f4dca2da 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java @@ -13,10 +13,11 @@ import org.hibernate.graph.internal.SubGraphImpl; import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.mapping.PersistentClass; import org.hibernate.metamodel.model.domain.AbstractIdentifiableType; -import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.IdentifiableDomainType; import org.hibernate.metamodel.model.domain.JpaMetamodel; +import org.hibernate.metamodel.model.domain.PersistentAttribute; +import org.hibernate.metamodel.model.domain.SingularPersistentAttribute; import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.produce.spi.SqmCreationState; import org.hibernate.query.sqm.tree.domain.SqmPath; @@ -66,13 +67,41 @@ public class EntityTypeImpl } @Override - public DomainType getSqmPathType() { + public EntityDomainType getSqmPathType() { return this; } @Override public SqmPathSource findSubPathSource(String name) { - return (SqmPathSource) findAttribute( name ); + final PersistentAttribute attribute = findAttribute( name ); + if ( attribute != null ) { + return (SqmPathSource) attribute; + } + + if ( "id".equalsIgnoreCase( name ) ) { + // todo (6.0) : probably need special handling here for non-aggregated composite ids + } + + return null; + } + + @Override + public PersistentAttribute findAttribute(String name) { + final PersistentAttribute attribute = super.findAttribute( name ); + if ( attribute != null ) { + return attribute; + } + + if ( "id".equalsIgnoreCase( name ) ) { + //noinspection unchecked + final SingularPersistentAttribute idAttribute = findIdAttribute(); + //noinspection RedundantIfStatement + if ( idAttribute != null ) { + return idAttribute; + } + } + + return null; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/DomainPathPart.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/DomainPathPart.java index 74d49bb739..2bbf2565f3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/DomainPathPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/DomainPathPart.java @@ -7,6 +7,7 @@ package org.hibernate.query.hql.internal; import org.hibernate.NotYetImplementedFor6Exception; +import org.hibernate.query.SemanticException; import org.hibernate.query.hql.spi.SemanticPathPart; import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.produce.spi.SqmCreationState; @@ -33,6 +34,9 @@ public class DomainPathPart implements SemanticPathPart { SqmCreationState creationState) { final SqmPath lhs = currentPath; final SqmPathSource subPathSource = lhs.getReferencedPathSource().findSubPathSource( name ); + if ( subPathSource == null ) { + throw new SemanticException( "Cannot resolve path (`" + name + "`) relative to `" + lhs.getNavigablePath() + "`" ); + } //noinspection unchecked currentPath = subPathSource.createSqmPath( lhs, creationState ); if ( isTerminal ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/QualifiedJoinPathConsumer.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/QualifiedJoinPathConsumer.java index 81aa6d6578..6c7412c33a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/QualifiedJoinPathConsumer.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/QualifiedJoinPathConsumer.java @@ -6,6 +6,8 @@ */ package org.hibernate.query.hql.internal; +import org.hibernate.metamodel.model.domain.EntityDomainType; +import org.hibernate.query.NavigablePath; import org.hibernate.query.SemanticException; import org.hibernate.query.hql.spi.DotIdentifierConsumer; import org.hibernate.query.hql.spi.SemanticPathPart; @@ -15,16 +17,22 @@ import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.produce.spi.SqmCreationProcessingState; import org.hibernate.query.sqm.produce.spi.SqmCreationState; import org.hibernate.query.sqm.tree.SqmJoinType; +import org.hibernate.query.sqm.tree.domain.SqmPolymorphicRootDescriptor; import org.hibernate.query.sqm.tree.from.SqmAttributeJoin; +import org.hibernate.query.sqm.tree.from.SqmEntityJoin; import org.hibernate.query.sqm.tree.from.SqmFrom; import org.hibernate.query.sqm.tree.from.SqmRoot; +import org.jboss.logging.Logger; + /** * Specialized "intermediate" SemanticPathPart for processing domain model paths * * @author Steve Ebersole */ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer { + private static final Logger log = Logger.getLogger( QualifiedJoinPathConsumer.class ); + private final SqmCreationState creationState; private final SqmRoot sqmRoot; @@ -32,7 +40,7 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer { private final boolean fetch; private final String alias; - private SqmFrom currentPath; + private ConsumerDelegate delegate; public QualifiedJoinPathConsumer( SqmRoot sqmRoot, @@ -47,25 +55,28 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer { this.creationState = creationState; } + @Override + public SemanticPathPart getConsumedPart() { + return delegate.getConsumedPart(); + } + @Override public void consumeIdentifier(String identifier, boolean isBase, boolean isTerminal) { if ( isBase ) { - assert currentPath == null; - - this.currentPath = resolvePathBase( identifier, isTerminal, creationState ); + assert delegate == null; + delegate = resolveBase( identifier, isTerminal ); } else { - assert currentPath != null; - currentPath = createJoin( currentPath, identifier, isTerminal, creationState ); + assert delegate != null; + delegate.consumeIdentifier( identifier, isTerminal ); } } - private SqmFrom resolvePathBase(String identifier, boolean isTerminal, SqmCreationState creationState) { + private ConsumerDelegate resolveBase(String identifier, boolean isTerminal) { final SqmCreationProcessingState processingState = creationState.getCurrentProcessingState(); final SqmPathRegistry pathRegistry = processingState.getPathRegistry(); final SqmFrom pathRootByAlias = pathRegistry.findFromByAlias( identifier ); - if ( pathRootByAlias != null ) { // identifier is an alias (identification variable) @@ -73,23 +84,61 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer { throw new SemanticException( "Cannot join to root : " + identifier ); } - return pathRootByAlias; + return new AttributeJoinDelegate( + pathRootByAlias, + joinType, + fetch, + alias, + creationState + ); } final SqmFrom pathRootByExposedNavigable = pathRegistry.findFromExposing( identifier ); if ( pathRootByExposedNavigable != null ) { - return createJoin( pathRootByExposedNavigable, identifier, isTerminal, creationState ); + return new AttributeJoinDelegate( + createJoin( pathRootByExposedNavigable, identifier, isTerminal ), + joinType, + fetch, + alias, + creationState + ); } - // todo (6.0) : another alternative here is an entity-join (entity name as rhs rather than attribute path) - // - need to account for that here, which may need delayed resolution in the case of a - // qualified entity reference (FQN) + // otherwise, assume we have a qualified entity name - delay resolution until we + // process the final token - throw new SemanticException( "Could not determine how to resolve qualified join base : " + identifier ); + return new ExpectingEntityJoinDelegate( + identifier, + isTerminal, + sqmRoot, + joinType, + alias, + fetch, + creationState + ); } - private SqmFrom createJoin(SqmFrom lhs, String identifier, boolean isTerminal, SqmCreationState creationState) { - final SqmPathSource subPathSource = lhs.getReferencedPathSource().findSubPathSource( identifier ); + private SqmFrom createJoin(SqmFrom lhs, String identifier, boolean isTerminal) { + return createJoin( + lhs, + identifier, + joinType, + alias, + fetch, + isTerminal, + creationState + ); + } + + private static SqmFrom createJoin( + SqmFrom lhs, + String name, + SqmJoinType joinType, + String alias, + boolean fetch, + boolean isTerminal, + SqmCreationState creationState) { + final SqmPathSource subPathSource = lhs.getReferencedPathSource().findSubPathSource( name ); final SqmAttributeJoin join = ( (SqmJoinable) subPathSource ).createSqmJoin( lhs, joinType, @@ -97,13 +146,114 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer { fetch, creationState ); + //noinspection unchecked lhs.addSqmJoin( join ); creationState.getCurrentProcessingState().getPathRegistry().register( join ); return join; } - @Override - public SemanticPathPart getConsumedPart() { - return currentPath; + private interface ConsumerDelegate { + void consumeIdentifier(String identifier, boolean isTerminal); + SemanticPathPart getConsumedPart(); + } + + private static class AttributeJoinDelegate implements ConsumerDelegate { + private final SqmCreationState creationState; + + private final SqmJoinType joinType; + private final boolean fetch; + private final String alias; + + private SqmFrom currentPath; + + public AttributeJoinDelegate( + SqmFrom base, + SqmJoinType joinType, + boolean fetch, + String alias, + SqmCreationState creationState) { + this.joinType = joinType; + this.fetch = fetch; + this.alias = alias; + this.creationState = creationState; + + this.currentPath = base; + } + + @Override + public void consumeIdentifier(String identifier, boolean isTerminal) { + currentPath = createJoin( + currentPath, + identifier, + joinType, + alias, + fetch, + isTerminal, + creationState + ); + } + + @Override + public SemanticPathPart getConsumedPart() { + return currentPath; + } + } + + private static class ExpectingEntityJoinDelegate implements ConsumerDelegate { + private final SqmCreationState creationState; + private final SqmRoot sqmRoot; + + private final SqmJoinType joinType; + private final boolean fetch; + private final String alias; + + private NavigablePath path = new NavigablePath(); + + private SqmEntityJoin join; + + public ExpectingEntityJoinDelegate( + String identifier, + boolean isTerminal, + SqmRoot sqmRoot, + SqmJoinType joinType, + String alias, + boolean fetch, + SqmCreationState creationState) { + this.creationState = creationState; + this.sqmRoot = sqmRoot; + this.joinType = joinType; + this.fetch = fetch; + this.alias = alias; + + consumeIdentifier( identifier, isTerminal ); + } + + @Override + public void consumeIdentifier(String identifier, boolean isTerminal) { + path = path.append( identifier ); + + if ( isTerminal ) { + final EntityDomainType joinedEntityType = creationState.getCreationContext() + .getJpaMetamodel() + .resolveHqlEntityReference( path.getFullPath() ); + if ( joinedEntityType == null ) { + throw new SemanticException( "Could not resolve join path - " + path.getFullPath() ); + } + + assert ! ( joinedEntityType instanceof SqmPolymorphicRootDescriptor ); + + if ( fetch ) { + log.debugf( "Ignoring fetch on entity join : %s(%s)", joinedEntityType.getHibernateEntityName(), alias ); + } + + join = new SqmEntityJoin<>( joinedEntityType, alias, joinType, sqmRoot ); + creationState.getCurrentProcessingState().getPathRegistry().register( join ); + } + } + + @Override + public SemanticPathPart getConsumedPart() { + return join; + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/QualifiedJoinPredicatePathConsumer.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/QualifiedJoinPredicatePathConsumer.java index 87192a0801..36aae2c236 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/QualifiedJoinPredicatePathConsumer.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/QualifiedJoinPredicatePathConsumer.java @@ -22,15 +22,12 @@ import org.hibernate.query.sqm.tree.from.SqmRoot; * @author Steve Ebersole */ public class QualifiedJoinPredicatePathConsumer extends BasicDotIdentifierConsumer { - private final SqmRoot sqmRoot; private final SqmQualifiedJoin sqmJoin; public QualifiedJoinPredicatePathConsumer( - SqmRoot sqmRoot, SqmQualifiedJoin sqmJoin, SqmCreationState creationState) { super( creationState ); - this.sqmRoot = sqmRoot; this.sqmJoin = sqmJoin; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticPathPartDelayedResolution.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticPathPartDelayedResolution.java deleted file mode 100644 index bf6269490e..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticPathPartDelayedResolution.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.query.hql.internal; - -import java.lang.reflect.Field; - -import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; -import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; -import org.hibernate.metamodel.model.domain.EntityDomainType; -import org.hibernate.query.SemanticException; -import org.hibernate.query.hql.spi.SemanticPathPart; -import org.hibernate.query.sqm.produce.spi.SqmCreationContext; -import org.hibernate.query.sqm.produce.spi.SqmCreationState; -import org.hibernate.query.sqm.tree.domain.SqmPath; -import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral; -import org.hibernate.query.sqm.tree.expression.SqmExpression; -import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral; -import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType; -import org.hibernate.type.descriptor.java.EnumJavaTypeDescriptor; - -/** - * A delayed resolution of a non-terminal path part - * - * @author Steve Ebersole - */ -public class SemanticPathPartDelayedResolution implements SemanticPathPart, FullyQualifiedReflectivePathSource { - private final FullyQualifiedReflectivePathSource parent; - - // todo (6.0) : consider reusing this PossiblePackageRoot instance, updating the state fields - // - we'd still add to the stack, but we'd save the instantiations - - private final String fullPath; - private final String localName; - - @SuppressWarnings("WeakerAccess") - public SemanticPathPartDelayedResolution(String name) { - this( null, name ); - } - - @SuppressWarnings("WeakerAccess") - public SemanticPathPartDelayedResolution( - FullyQualifiedReflectivePathSource parent, - String localName) { - this.parent = parent; - this.localName = localName; - - this.fullPath = parent == null ? localName : parent.append( localName ).getFullPath(); - } - - @Override - public FullyQualifiedReflectivePathSource getParent() { - return parent; - } - - @Override - public String getLocalName() { - return localName; - } - - @Override - public String getFullPath() { - return fullPath; - } - - @Override - public SemanticPathPartDelayedResolution append(String subPathName) { - throw new UnsupportedOperationException( "Use #resolvePathPart instead" ); - } - - @Override - public SemanticPathPart resolvePathPart( - String subName, - boolean isTerminal, - SqmCreationState creationState) { - final String combinedName = this.fullPath + '.' + subName; - - final SqmCreationContext creationContext = creationState.getCreationContext(); - - if ( isTerminal ) { - final EntityDomainType entityTypeByName = creationContext.getJpaMetamodel().entity( combinedName ); - if ( entityTypeByName != null ) { - //noinspection unchecked - return new SqmLiteralEntityType( entityTypeByName, creationContext.getNodeBuilder() ); - } - - // the incoming subName could be a field or enum reference relative to this combinedName - // which would mean the combinedName must be a class name - final ClassLoaderService classLoaderService = creationContext - .getServiceRegistry() - .getService( ClassLoaderService.class ); - - // todo (6.0) : would be nice to leverage imported names here - try { - final Class referencedClass = classLoaderService.classForName( combinedName ); - - if ( referencedClass.isEnum() ) { - try { - //noinspection unchecked - final Enum enumValue = Enum.valueOf( referencedClass, subName ); - //noinspection unchecked - return new SqmEnumLiteral( - enumValue, - (EnumJavaTypeDescriptor) creationContext.getJpaMetamodel() - .getTypeConfiguration() - .getJavaTypeDescriptorRegistry() - .resolveDescriptor( referencedClass ), - subName, - creationContext.getNodeBuilder() - ); - } - catch (Exception e) { - // ignore - it could still potentially be a static field reference - } - } - - try { - final Field field = referencedClass.getDeclaredField( subName ); - //noinspection unchecked - return new SqmFieldLiteral<>( - field.get( null ), - creationContext.getJpaMetamodel() - .getTypeConfiguration() - .getJavaTypeDescriptorRegistry() - .resolveDescriptor( referencedClass ), - subName, - creationContext.getNodeBuilder() - ); - } - catch (Exception e) { - // ignore - fall through to the exception below - } - } - catch (ClassLoadingException e) { - // ignore - we will hit the exception below - } - - throw new SemanticException( "Could not resolve path terminal : " + combinedName + '.' + subName ); - } - else { - - return new SemanticPathPartDelayedResolution( this, subName ); - } - } - - @Override - public SqmPath resolveIndexedAccess( - SqmExpression selector, - boolean isTerminal, - SqmCreationState creationState) { - return null; - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticPathPartJoinPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticPathPartJoinPredicate.java deleted file mode 100644 index 681cff63df..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticPathPartJoinPredicate.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.query.hql.internal; - -import java.util.Locale; - -import org.hibernate.query.SemanticException; -import org.hibernate.query.hql.spi.SemanticPathPart; -import org.hibernate.query.hql.spi.SqmPathRegistry; -import org.hibernate.query.sqm.produce.spi.SqmCreationProcessingState; -import org.hibernate.query.sqm.produce.spi.SqmCreationState; -import org.hibernate.query.sqm.tree.domain.SqmPath; -import org.hibernate.query.sqm.tree.expression.SqmExpression; -import org.hibernate.query.sqm.tree.from.SqmFrom; - -/** - * @author Steve Ebersole - */ -public class SemanticPathPartJoinPredicate implements SemanticPathPart { - private final SqmFrom joinLhs; - - @SuppressWarnings("WeakerAccess") - public SemanticPathPartJoinPredicate(SqmFrom joinLhs) { - super(); - this.joinLhs = joinLhs; - } - - @Override - public SemanticPathPart resolvePathPart( - String name, - boolean isTerminal, - SqmCreationState creationState) { - final SqmCreationProcessingState processingState = creationState.getCurrentProcessingState(); - final SqmPathRegistry pathRegistry = processingState.getPathRegistry(); - - // #1 - name is joinLhs alias - if ( name.equals( joinLhs.getExplicitAlias() ) ) { - return joinLhs; - } - - // #2 - name is alias for another SqmFrom - final SqmFrom fromByAlias = pathRegistry.findFromByAlias( name ); - if ( fromByAlias != null ) { - validatePathRoot( fromByAlias ); - return fromByAlias; - } - - // #3 - name is a unqualified attribute reference relative to the current processing state - final SqmFrom fromExposing = pathRegistry.findFromExposing( name ); - if ( fromExposing != null ) { - validatePathRoot( fromExposing ); - return fromExposing; - } - - if ( ! isTerminal ) { - return new SemanticPathPartDelayedResolution( name ); - } - - throw new SemanticException( "Could not resolve path root used in join predicate: " + name ); - } - - private void validatePathRoot(SqmPath path) { - if ( ! path.findRoot().equals( joinLhs.findRoot() ) ) { - throw new SemanticException( - String.format( - Locale.ROOT, - "Qualified join predicate path [%s] referred to from-clause root other that the join rhs", - path.getNavigablePath().getFullPath() - ) - ); - } - } - - @Override - public SqmPath resolveIndexedAccess( - SqmExpression selector, - boolean isTerminal, - SqmCreationState creationState) { - throw new SemanticException( "Illegal index-access as join predicate root" ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticPathPartQualifiedJoinPath.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticPathPartQualifiedJoinPath.java deleted file mode 100644 index b1977c1685..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticPathPartQualifiedJoinPath.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.query.hql.internal; - -import org.hibernate.metamodel.model.domain.EntityDomainType; -import org.hibernate.query.SemanticException; -import org.hibernate.query.hql.spi.SemanticPathPart; -import org.hibernate.query.hql.spi.SqmPathRegistry; -import org.hibernate.query.sqm.SqmJoinable; -import org.hibernate.query.sqm.produce.spi.SqmCreationProcessingState; -import org.hibernate.query.sqm.produce.spi.SqmCreationState; -import org.hibernate.query.sqm.tree.SqmJoinType; -import org.hibernate.query.sqm.tree.domain.SqmPath; -import org.hibernate.query.sqm.tree.expression.SqmExpression; -import org.hibernate.query.sqm.tree.from.SqmAttributeJoin; -import org.hibernate.query.sqm.tree.from.SqmEntityJoin; -import org.hibernate.query.sqm.tree.from.SqmFrom; -import org.hibernate.query.sqm.tree.from.SqmRoot; - -/** - * SemanticPathPart handling specific to processing a qualified join path - * - * @author Steve Ebersole - */ -public class SemanticPathPartQualifiedJoinPath implements SemanticPathPart { - private final SqmRoot sqmRoot; - - private final SqmJoinType joinType; - private final boolean fetch; - private final String alias; - - @SuppressWarnings("WeakerAccess") - public SemanticPathPartQualifiedJoinPath(SqmRoot sqmRoot, SqmJoinType joinType, boolean fetch, String alias) { - this.sqmRoot = sqmRoot; - this.joinType = joinType; - this.fetch = fetch; - this.alias = alias; - } - - @Override - public SemanticPathPart resolvePathPart( - String name, - boolean isTerminal, - SqmCreationState creationState) { - final SqmCreationProcessingState processingState = creationState.getCurrentProcessingState(); - final SqmPathRegistry pathRegistry = processingState.getPathRegistry(); - - final SqmFrom fromByAlias = pathRegistry.findFromByAlias( name ); - if ( fromByAlias != null ) { - return fromByAlias; - } - - final SqmFrom fromExposing = pathRegistry.findFromExposing( name ); - if ( fromExposing != null ) { - final SqmAttributeJoin join = ( (SqmJoinable) fromExposing.getReferencedPathSource().findSubPathSource( - name ) ).createSqmJoin( - fromExposing, - joinType, - isTerminal ? alias : null, - fetch, - creationState - ); - pathRegistry.register( join ); - return join; - } - - // otherwise it has to be an entity join - - if ( isTerminal ) { - final EntityDomainType entityType = processingState.getCreationState() - .getCreationContext() - .getJpaMetamodel() - .entity( name ); - if ( entityType == null ) { - throw new SemanticException( "Could not resolve qualified join path: " + name ); - } - final SqmEntityJoin entityJoin = new SqmEntityJoin<>( entityType, alias, joinType, sqmRoot ); - pathRegistry.register( entityJoin ); - return entityJoin; - } - - return new SemanticPathPartDelayedEntityJoinHandler( name, sqmRoot, joinType, alias ); - } - - @Override - public SqmPath resolveIndexedAccess( - SqmExpression selector, - boolean isTerminal, - SqmCreationState creationState) { - throw new SemanticException( "Illegal index-access as qualified join path" ); - } - - private static class SemanticPathPartDelayedEntityJoinHandler implements SemanticPathPart { - private final SqmRoot sqmRoot; - - private final SqmJoinType joinType; - private final String alias; - - private String pathSoFar; - - private SemanticPathPartDelayedEntityJoinHandler( - String baseName, - SqmRoot sqmRoot, - SqmJoinType joinType, - String alias) { - this.sqmRoot = sqmRoot; - this.joinType = joinType; - this.alias = alias; - - this.pathSoFar = baseName; - } - - @Override - public SemanticPathPart resolvePathPart( - String name, - boolean isTerminal, - SqmCreationState creationState) { - pathSoFar = pathSoFar + '.' + name; - if ( ! isTerminal ) { - return this; - } - - final SqmCreationProcessingState processingState = creationState.getCurrentProcessingState(); - final SqmPathRegistry pathRegistry = processingState.getPathRegistry(); - - final EntityDomainType entityType = processingState.getCreationState() - .getCreationContext() - .getJpaMetamodel() - .entity( name ); - if ( entityType == null ) { - throw new SemanticException( "Could not resolve qualified join path: " + name ); - } - final SqmEntityJoin entityJoin = new SqmEntityJoin<>( entityType, alias, joinType, sqmRoot ); - pathRegistry.register( entityJoin ); - - return entityJoin; - } - - @Override - public SqmPath resolveIndexedAccess( - SqmExpression selector, - boolean isTerminal, - SqmCreationState creationState) { - throw new SemanticException( "Illegal index-access as qualified join path" ); - } - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticPathPartRoot.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticPathPartRoot.java deleted file mode 100644 index fc634c817f..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticPathPartRoot.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.query.hql.internal; - -import org.hibernate.metamodel.model.domain.EntityDomainType; -import org.hibernate.query.SemanticException; -import org.hibernate.query.hql.spi.SemanticPathPart; -import org.hibernate.query.hql.spi.SqmPathRegistry; -import org.hibernate.query.sqm.produce.spi.SqmCreationContext; -import org.hibernate.query.sqm.produce.spi.SqmCreationState; -import org.hibernate.query.sqm.tree.domain.SqmPath; -import org.hibernate.query.sqm.tree.expression.SqmExpression; -import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType; -import org.hibernate.query.sqm.tree.from.SqmFrom; - -/** - * @author Steve Ebersole - */ -public class SemanticPathPartRoot implements SemanticPathPart { - public SemanticPathPartRoot() { - } - - @Override - public SemanticPathPart resolvePathPart( - String name, - boolean isTerminal, - SqmCreationState creationState) { - // At this point we have a "root reference"... the first path part in - // a potential series of path parts - - final SqmPathRegistry pathRegistry = creationState.getProcessingStateStack().getCurrent().getPathRegistry(); - final SqmCreationContext creationContext = creationState.getCreationContext(); - - // this root reference could be any of: - // 1) a from-element alias - // 2) an unqualified attribute name exposed from one (and only one!) from-element - // 3) an unqualified (imported) entity name - - // #1 - final SqmFrom aliasedFromElement = pathRegistry.findFromByAlias( name ); - if ( aliasedFromElement != null ) { - return aliasedFromElement; - } - - - // #2 - final SqmFrom unqualifiedAttributeOwner = pathRegistry.findFromExposing( name ); - if ( unqualifiedAttributeOwner != null ) { - return unqualifiedAttributeOwner.resolvePathPart( name, false, creationState ); - } - - // #3 - final EntityDomainType entityTypeByName = creationContext.getJpaMetamodel().entity( name ); - if ( entityTypeByName != null ) { - //noinspection unchecked - return new SqmLiteralEntityType( entityTypeByName, creationState.getCreationContext().getNodeBuilder() ); - } - - if ( ! isTerminal ) { - return new SemanticPathPartDelayedResolution( name ); - } - - throw new SemanticException( "Could not resolve path root : " + name ); - } - - @Override - public SqmPath resolveIndexedAccess( - SqmExpression selector, - boolean isTerminal, - SqmCreationState creationState) { - throw new SemanticException( "Path cannot start with index-access" ); - } -} 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 37d8c15cff..bd125ecc6b 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 @@ -1004,7 +1004,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre } if ( parserJoin.qualifiedJoinPredicate() != null ) { - dotIdentifierConsumerStack.push( new QualifiedJoinPredicatePathConsumer( sqmRoot, join, this ) ); + dotIdentifierConsumerStack.push( new QualifiedJoinPredicatePathConsumer( join, this ) ); try { join.setJoinPredicate( (SqmPredicate) parserJoin.qualifiedJoinPredicate().predicate().accept( this ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryEngine.java b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryEngine.java index c5f3742fa8..c909b7c27f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryEngine.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryEngine.java @@ -23,7 +23,7 @@ import org.hibernate.query.internal.QueryInterpretationCacheStandardImpl; import org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder; import org.hibernate.query.hql.SemanticQueryProducer; import org.hibernate.query.sqm.produce.function.SqmFunctionRegistry; -import org.hibernate.query.sqm.produce.internal.SemanticQueryProducerImpl; +import org.hibernate.query.hql.internal.SemanticQueryProducerImpl ; import org.hibernate.query.sqm.produce.internal.SqmCreationOptionsStandard; import org.hibernate.query.sqm.produce.spi.SqmCreationContext; import org.hibernate.query.sqm.produce.spi.SqmCreationOptions; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/internal/SemanticQueryProducerImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/internal/SemanticQueryProducerImpl.java deleted file mode 100644 index 0691102d60..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/internal/SemanticQueryProducerImpl.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.query.sqm.produce.internal; - -import org.hibernate.QueryException; -import org.hibernate.query.hql.internal.HqlParseTreeBuilder; -import org.hibernate.query.hql.internal.HqlParseTreePrinter; -import org.hibernate.query.hql.internal.HqlParser; -import org.hibernate.query.hql.internal.SemanticQueryBuilder; -import org.hibernate.query.sqm.InterpretationException; -import org.hibernate.query.hql.SemanticQueryProducer; -import org.hibernate.query.sqm.produce.spi.SqmCreationContext; -import org.hibernate.query.sqm.produce.spi.SqmCreationOptions; -import org.hibernate.query.sqm.tree.SqmStatement; - -/** - * Standard implementation of SemanticQueryInterpreter - * - * @author Steve Ebersole - */ -public class SemanticQueryProducerImpl implements SemanticQueryProducer { - private final SqmCreationContext sqmCreationContext; - private final SqmCreationOptions sqmCreationOptions; - - public SemanticQueryProducerImpl( - SqmCreationContext sqmCreationContext, - SqmCreationOptions sqmCreationOptions) { - this.sqmCreationContext = sqmCreationContext; - this.sqmCreationOptions = sqmCreationOptions; - } - - @Override - public SqmStatement interpret(String query) { -// final ParsingContext parsingContext = ; - - // first, ask Antlr to build the parse tree - final HqlParser parser = HqlParseTreeBuilder.INSTANCE.parseHql( query ); - - // Log the parse tree (if enabled) - HqlParseTreePrinter.logStatementParseTree( parser ); - - // then we perform semantic analysis and build the semantic representation... - try { - final SqmStatement sqmStatement = SemanticQueryBuilder.buildSemanticModel( - parser.statement(), - sqmCreationOptions, - sqmCreationContext - ); - - SqmTreePrinter.logTree( sqmStatement ); - - return sqmStatement; - } - catch (QueryException e) { - throw e; - } - catch (Exception e) { - throw new InterpretationException( query, e ); - } - } -}