initial work for LoadQueryInfluencer (EntityGraph, FetchProfile, etc) in SQM -> SQL AST transformation while building DomainResult/Fetch graph

This commit is contained in:
Steve Ebersole 2019-09-27 14:58:34 -05:00
parent e572202cd1
commit 032f03afa3
4 changed files with 63 additions and 68 deletions

View File

@ -17,7 +17,6 @@ import java.util.function.Supplier;
import org.hibernate.AssertionFailure;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.internal.util.collections.StandardStack;
import org.hibernate.metamodel.mapping.AttributeMapping;
@ -25,9 +24,7 @@ import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.internal.EmbeddedSqmPathSource;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.BinaryArithmeticOperator;
import org.hibernate.query.UnaryArithmeticOperator;
@ -158,9 +155,6 @@ public abstract class BaseSqmToSqlAstConverter
private final SqlAstCreationContext creationContext;
private final QueryOptions queryOptions;
private final LoadQueryInfluencers loadQueryInfluencers;
//private final Callback callback;
private final DomainParameterXref domainParameterXref;
private final QueryParameterBindings domainParameterBindings;
private final Map<JpaCriteriaParameter<?>,Supplier<SqmJpaCriteriaParameterWrapper<?>>> jpaCriteriaParamResolutions;
@ -180,18 +174,13 @@ public abstract class BaseSqmToSqlAstConverter
SqlAstCreationContext creationContext,
QueryOptions queryOptions,
DomainParameterXref domainParameterXref,
QueryParameterBindings domainParameterBindings,
// LoadQueryInfluencers loadQueryInfluencers,
// Callback callback) {
LoadQueryInfluencers loadQueryInfluencers) {
QueryParameterBindings domainParameterBindings) {
super( creationContext.getServiceRegistry() );
this.creationContext = creationContext;
this.queryOptions = queryOptions;
this.domainParameterXref = domainParameterXref;
this.domainParameterBindings = domainParameterBindings;
this.jpaCriteriaParamResolutions = domainParameterXref.getParameterResolutions().getJpaCriteriaParamResolutions();
this.loadQueryInfluencers = loadQueryInfluencers;
// this.callback = callback;
}
protected Stack<SqlAstProcessingState> getProcessingStateStack() {

View File

@ -7,23 +7,23 @@
package org.hibernate.query.sqm.sql.internal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.profile.FetchProfile;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.graph.spi.GraphImplementor;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.query.DynamicInstantiationNature;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.spi.QueryOptions;
@ -52,6 +52,7 @@ import org.hibernate.sql.results.internal.domain.instantiation.DynamicInstantiat
import org.hibernate.sql.results.spi.CircularFetchDetector;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.EntityResultNode;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
import org.hibernate.sql.results.spi.Fetchable;
@ -67,19 +68,27 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
public class StandardSqmSelectToSqlAstConverter
extends BaseSqmToSqlAstConverter
implements DomainResultCreationState, org.hibernate.query.sqm.sql.SqmSelectToSqlAstConverter {
private final LoadQueryInfluencers fetchInfluencers;
private final CircularFetchDetector circularFetchDetector = new CircularFetchDetector();
private final List<DomainResult> domainResults = new ArrayList<>();
private GraphImplementor<?> currentJpaGraphNode;
public StandardSqmSelectToSqlAstConverter(
QueryOptions queryOptions,
DomainParameterXref domainParameterXref,
QueryParameterBindings domainParameterBindings,
LoadQueryInfluencers influencers,
// Callback callback,
LoadQueryInfluencers fetchInfluencers,
SqlAstCreationContext creationContext) {
// super( creationContext, queryOptions, domainParameterXref, domainParameterBindings, influencers, callback );
super( creationContext, queryOptions, domainParameterXref, domainParameterBindings, influencers );
super( creationContext, queryOptions, domainParameterXref, domainParameterBindings );
this.fetchInfluencers = fetchInfluencers;
if ( fetchInfluencers != null ) {
if ( fetchInfluencers.getEffectiveEntityGraph().getSemantic() != null ) {
currentJpaGraphNode = fetchInfluencers.getEffectiveEntityGraph().getGraph();
}
}
}
@Override
@ -180,8 +189,6 @@ public class StandardSqmSelectToSqlAstConverter
return fetches;
}
private Set<Fetchable> processedFetchables;
private Fetch buildFetch(FetchParent fetchParent, Fetchable fetchable) {
// fetch has access to its parent in addition to the parent having its fetches.
//
@ -191,12 +198,14 @@ public class StandardSqmSelectToSqlAstConverter
final NavigablePath fetchablePath = fetchParent.getNavigablePath().append( fetchable.getFetchableName() );
final GraphImplementor<?> previousGraphNode = currentJpaGraphNode;
final String alias;
LockMode lockMode = LockMode.READ;
FetchTiming fetchTiming = fetchable.getMappedFetchStrategy().getTiming();
boolean joined = false;
final SqmAttributeJoin fetchedJoin = getFromClauseIndex().findFetchedJoinByPath( fetchablePath );
final String alias;
boolean joined;
if ( fetchedJoin != null ) {
// there was an explicit fetch in the SQM
@ -211,35 +220,34 @@ public class StandardSqmSelectToSqlAstConverter
}
else {
// there was not an explicit fetch in the SQM
alias = null;
if ( fetchable instanceof Joinable ) {
if ( processedFetchables == null ) {
processedFetchables = new HashSet<>();
}
final boolean added = processedFetchables.add( fetchable );
if ( ! added ) {
joined = false;
}
else {
joined = fetchTiming == FetchTiming.IMMEDIATE && fetchable.getMappedFetchStrategy().getStyle() == FetchStyle.JOIN;
// see if we have any "influencer" in effect that indicates
if ( this.currentJpaGraphNode != null && appliesTo( this.currentJpaGraphNode, fetchParent ) ) {
final AttributeNodeImplementor<?> attributeNode = this.currentJpaGraphNode.findAttributeNode( fetchable.getFetchableName() );
// todo (6.0) : need to account for `org.hibernate.graph.GraphSemantic` here as well
if ( attributeNode != null ) {
fetchTiming = FetchTiming.IMMEDIATE;
joined = true;
}
}
else {
joined = true;
else if ( fetchInfluencers.hasEnabledFetchProfiles() ) {
if ( fetchParent instanceof EntityResultNode ) {
final EntityResultNode entityFetchParent = (EntityResultNode) fetchParent;
final EntityMappingType entityMappingType = entityFetchParent.getEntityValuedModelPart().getEntityMappingType();
final String fetchParentEntityName = entityMappingType.getEntityName();
final String fetchableRole = fetchParentEntityName + "." + fetchable.getFetchableName();
for ( String enabledFetchProfileName : fetchInfluencers.getEnabledFetchProfileNames() ) {
final FetchProfile enabledFetchProfile = getCreationContext().getSessionFactory().getFetchProfile( enabledFetchProfileName );
final org.hibernate.engine.profile.Fetch profileFetch = enabledFetchProfile.getFetchByRole( fetchableRole );
fetchTiming = FetchTiming.IMMEDIATE;
joined = joined || profileFetch.getStyle() == org.hibernate.engine.profile.Fetch.Style.JOIN;
}
}
}
// todo (6.0) : account for EntityGraph
// it would adjust:
// * fetchTiming - make it IMMEDIATE
//
// todo (6.0) : how to handle
// * joined ? - sh
final TableGroup existingJoinedGroup = getFromClauseIndex().findTableGroup( fetchablePath );
if ( existingJoinedGroup != null ) {
// we can use this to trigger the fetch from the joined group.
@ -271,7 +279,7 @@ public class StandardSqmSelectToSqlAstConverter
final TableGroupJoin tableGroupJoin = ( (TableGroupJoinProducer) fetchable ).createTableGroupJoin(
fetchablePath,
lhs,
null,
alias,
JoinType.LEFT,
LockMode.NONE,
getSqlAliasBaseManager(),
@ -307,6 +315,23 @@ public class StandardSqmSelectToSqlAstConverter
e
);
}
finally {
currentJpaGraphNode = previousGraphNode;
}
}
private static boolean appliesTo(GraphImplementor<?> graphNode, FetchParent fetchParent) {
if ( ! ( fetchParent instanceof EntityResultNode ) ) {
return false;
}
final EntityResultNode entityFetchParent = (EntityResultNode) fetchParent;
final EntityMappingType entityFetchParentMappingType = entityFetchParent.getEntityValuedModelPart().getEntityMappingType();
assert graphNode.getGraphedType() instanceof EntityDomainType;
final EntityDomainType entityDomainType = (EntityDomainType) graphNode.getGraphedType();
return entityDomainType.getHibernateEntityName().equals( entityFetchParentMappingType.getEntityName() );
}
@Override

View File

@ -6,15 +6,14 @@
*/
package org.hibernate.query.sqm.tree.expression;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
import org.hibernate.query.ParameterMetadata;
import org.hibernate.query.criteria.JpaParameterExpression;
import org.hibernate.query.spi.QueryParameterImplementor;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
/**
@ -120,14 +119,6 @@ public class JpaCriteriaParameter<T>
return walker.visitJpaCriteriaParameter( this );
}
public SqmJpaCriteriaParameterWrapper<T> makeSqmParameter() {
return new SqmJpaCriteriaParameterWrapper<>(
getHibernateType(),
this,
nodeBuilder()
);
}
@Override
public NamedCallableQueryMemento.ParameterMemento toMemento() {
throw new UnsupportedOperationException( "ParameterMemento cannot be extracted from Criteria query parameter" );

View File

@ -6,22 +6,12 @@
*/
package org.hibernate.query.sqm.tree.expression;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.metamodel.model.domain.internal.DomainModelHelper;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
/**
* @author Steve Ebersole