6 - SQM based on JPA type system

- moving SQM-specific tests from wip/6.0
This commit is contained in:
Steve Ebersole 2019-07-25 14:06:54 -05:00 committed by Andrea Boriero
parent 5e19aee4a1
commit 5e8be067ca
12 changed files with 221 additions and 563 deletions

View File

@ -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<J> extends AbstractSqmPathSource<J> {
@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<J, ?> idAttribute = getSqmPathType().findIdAttribute();
if ( idAttribute != null && idAttribute.getName().equals( name ) ) {
return idAttribute;
}
throw new SemanticException( "Unknown sub-path name : " + name );
}
@Override

View File

@ -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<J>
}
@Override
public DomainType<?> getSqmPathType() {
public EntityDomainType<J> 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<? super J, ?> findAttribute(String name) {
final PersistentAttribute<? super J, ?> attribute = super.findAttribute( name );
if ( attribute != null ) {
return attribute;
}
if ( "id".equalsIgnoreCase( name ) ) {
//noinspection unchecked
final SingularPersistentAttribute<J, ?> idAttribute = findIdAttribute();
//noinspection RedundantIfStatement
if ( idAttribute != null ) {
return idAttribute;
}
}
return null;
}
@Override

View File

@ -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 ) {

View File

@ -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;
}
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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" );
}
}

View File

@ -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" );
}
}
}

View File

@ -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" );
}
}

View File

@ -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 ) );
}

View File

@ -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;

View File

@ -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 );
}
}
}