major refactor to horrible instantiation of QueryEngine

This commit is contained in:
Gavin King 2024-09-09 22:59:16 +02:00
parent 2a999d68d2
commit 9f91f2dbff
38 changed files with 287 additions and 227 deletions

View File

@ -287,7 +287,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
}
@Override
public NamedObjectRepository buildNamedQueryRepository(SessionFactoryImplementor sessionFactory) {
public NamedObjectRepository buildNamedQueryRepository() {
throw new UnsupportedOperationException( "#buildNamedQueryRepository should not be called on InFlightMetadataCollector" );
}

View File

@ -71,6 +71,7 @@ import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.cfg.AvailableSettings.EVENT_LISTENER_PREFIX;
import static org.hibernate.internal.util.StringHelper.splitAtCommas;
import static org.hibernate.internal.util.collections.CollectionHelper.mapOfSize;
/**
* Container for configuration data collected during binding the metamodel.
@ -356,12 +357,12 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
}
@Override
public NamedObjectRepository buildNamedQueryRepository(SessionFactoryImplementor sessionFactory) {
public NamedObjectRepository buildNamedQueryRepository() {
return new NamedObjectRepositoryImpl(
CollectionHelper.mapOfSize( namedQueryMap.size() ),
CollectionHelper.mapOfSize( namedNativeQueryMap.size() ),
CollectionHelper.mapOfSize( namedProcedureCallMap.size() ),
CollectionHelper.mapOfSize( sqlResultSetMappingMap.size() )
mapOfSize( namedQueryMap.size() ),
mapOfSize( namedNativeQueryMap.size() ),
mapOfSize( namedProcedureCallMap.size() ),
mapOfSize( sqlResultSetMappingMap.size() )
);
}

View File

@ -259,8 +259,8 @@ public abstract class AbstractDelegatingMetadata implements MetadataImplementor
}
@Override
public NamedObjectRepository buildNamedQueryRepository(SessionFactoryImplementor sessionFactory) {
return delegate().buildNamedQueryRepository( sessionFactory );
public NamedObjectRepository buildNamedQueryRepository() {
return delegate().buildNamedQueryRepository();
}
@Override

View File

@ -46,7 +46,7 @@ public interface MetadataImplementor extends Metadata {
*/
SqmFunctionRegistry getFunctionRegistry();
NamedObjectRepository buildNamedQueryRepository(SessionFactoryImplementor sessionFactory);
NamedObjectRepository buildNamedQueryRepository();
@Incubating
void orderColumns(boolean forceOrdering);

View File

@ -25,7 +25,6 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.BaselineSessionEventsListenerBuilder;
import org.hibernate.jpa.spi.JpaCompliance;
import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode;
import org.hibernate.query.criteria.ValueHandlingMode;
import org.hibernate.query.spi.QueryEngineOptions;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
@ -242,10 +241,6 @@ public interface SessionFactoryOptions extends QueryEngineOptions {
boolean isFailOnPaginationOverCollectionFetchEnabled();
default ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHandlingMode() {
return ImmutableEntityUpdateQueryHandlingMode.WARNING;
}
/**
* The default catalog to use in generated SQL when a catalog wasn't specified in the mapping,
* neither explicitly nor implicitly (see the concept of implicit catalog in XML mapping).

View File

@ -227,7 +227,7 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im
settings = getSettings( options, serviceRegistry );
maskOutSensitiveInformation( settings );
deprecationCheck( settings );
LOG.debugf( "Instantiating SessionFactory with settings: %s", settings);
LOG.debugf( "Instantiating SessionFactory with settings: %s", settings );
sqlStringGenerationContext = createSqlStringGenerationContext( bootMetamodel, options, jdbcServices );
@ -280,7 +280,7 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im
// created, then we can split creation of QueryEngine
// and SqmFunctionRegistry, instantiating just the
// registry here, and doing the engine later
queryEngine = QueryEngineImpl.from( this, bootMetamodel );
queryEngine = QueryEngineImpl.from( bootMetamodel, options, this, serviceRegistry, settings, name );
// create runtime metamodels (mapping and JPA)
final RuntimeMetamodelsImpl runtimeMetamodelsImpl = new RuntimeMetamodelsImpl();

View File

@ -7,7 +7,6 @@
package org.hibernate.query;
import org.hibernate.Incubating;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.sqm.SqmExpressible;
/**
@ -30,7 +29,7 @@ public interface BindableType<J> {
}
/**
* Resolve this parameter type to the corresponding SqmExpressible
* Resolve this parameter type to the corresponding {@link SqmExpressible}
*/
SqmExpressible<J> resolveExpressible(SessionFactoryImplementor sessionFactory);
SqmExpressible<J> resolveExpressible(BindingContext bindingContext);
}

View File

@ -0,0 +1,27 @@
/*
* 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;
import org.hibernate.Incubating;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.model.domain.JpaMetamodel;
import org.hibernate.type.spi.TypeConfiguration;
/**
* A context within which a {@link BindableType} can be resolved
* to an instance of {@link org.hibernate.query.sqm.SqmExpressible}.
*
* @author Gavin King
*
* @since 7
*/
@Incubating
public interface BindingContext {
TypeConfiguration getTypeConfiguration();
JpaMetamodel getJpaMetamodel();
MappingMetamodel getMappingMetamodel();
}

View File

@ -13,9 +13,9 @@ import java.time.OffsetTime;
import java.time.ZonedDateTime;
import java.util.Calendar;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.query.BindableType;
import org.hibernate.query.BindingContext;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.JavaTypeHelper;
@ -39,9 +39,9 @@ public class BindingTypeHelper {
public <T> BindableType<T> resolveTemporalPrecision(
TemporalType precision,
BindableType<T> declaredParameterType,
SessionFactoryImplementor sessionFactory) {
BindingContext bindingContext) {
if ( precision != null ) {
final SqmExpressible<T> sqmExpressible = declaredParameterType.resolveExpressible( sessionFactory );
final SqmExpressible<T> sqmExpressible = declaredParameterType.resolveExpressible(bindingContext);
if ( !( JavaTypeHelper.isTemporal( sqmExpressible.getExpressibleJavaType() ) ) ) {
throw new UnsupportedOperationException(
"Cannot treat non-temporal parameter type with temporal precision"
@ -50,7 +50,7 @@ public class BindingTypeHelper {
final TemporalJavaType<T> temporalJtd = (TemporalJavaType<T>) sqmExpressible.getExpressibleJavaType();
if ( temporalJtd.getPrecision() != precision ) {
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
final TypeConfiguration typeConfiguration = bindingContext.getTypeConfiguration();
final TemporalJavaType<T> temporalTypeForPrecision;
// Special case java.util.Date, because TemporalJavaType#resolveTypeForPrecision doesn't support widening,
// since the main purpose of that method is to determine the final java type based on the reflective type

View File

@ -10,13 +10,13 @@ import org.hibernate.boot.model.FunctionContributions;
import org.hibernate.boot.model.FunctionContributor;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.query.spi.NativeQueryInterpreter;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.query.BindingContext;
import org.hibernate.query.hql.HqlTranslator;
import org.hibernate.query.hql.internal.StandardHqlTranslator;
import org.hibernate.query.hql.spi.SqmCreationOptions;
@ -32,7 +32,7 @@ import org.hibernate.query.sqm.spi.SqmCreationContext;
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
import org.hibernate.query.sqm.sql.StandardSqmTranslatorFactory;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.logging.Logger;
@ -40,7 +40,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import static java.util.Comparator.comparingInt;
@ -54,23 +53,31 @@ public class QueryEngineImpl implements QueryEngine {
private static final Logger LOG_HQL_FUNCTIONS = CoreLogging.logger("org.hibernate.HQL_FUNCTIONS");
public static QueryEngine from(SessionFactoryImplementor sessionFactory, MetadataImplementor metadata) {
final QueryEngineOptions options = sessionFactory.getSessionFactoryOptions();
final Dialect dialect = sessionFactory.getJdbcServices().getDialect();
public static QueryEngineImpl from(
MetadataImplementor metadata,
QueryEngineOptions options,
SqmCreationContext sqmCreationContext,
ServiceRegistryImplementor serviceRegistry,
Map<String,Object> properties,
String name) {
final Dialect dialect = serviceRegistry.requireService( JdbcServices.class ).getDialect();
return new QueryEngineImpl(
sessionFactory,
metadata.getTypeConfiguration(),
resolveHqlTranslator( options, dialect, sessionFactory, new SqmCreationOptionsStandard( options ) ),
resolveHqlTranslator( options, dialect, sqmCreationContext, new SqmCreationOptionsStandard( options ) ),
resolveSqmTranslatorFactory( options, dialect ),
createFunctionRegistry( sessionFactory, metadata, options, dialect ),
metadata.buildNamedQueryRepository( sessionFactory ),
buildInterpretationCache( sessionFactory::getStatistics, sessionFactory.getProperties() ),
sessionFactory.getServiceRegistry().getService(NativeQueryInterpreter.class)
createFunctionRegistry( serviceRegistry, metadata, options, dialect ),
metadata.buildNamedQueryRepository(),
buildInterpretationCache( serviceRegistry, properties ),
serviceRegistry.getService(NativeQueryInterpreter.class),
sqmCreationContext,
options,
options.getUuid(),
name
);
}
private static SqmFunctionRegistry createFunctionRegistry(
SessionFactoryImplementor sessionFactory,
ServiceRegistry serviceRegistry,
MetadataImplementor metadata,
QueryEngineOptions queryEngineOptions,
Dialect dialect) {
@ -84,21 +91,17 @@ public class QueryEngineImpl implements QueryEngine {
}
//TODO: probably better to turn this back into an anonymous class
final FunctionContributions functionContributions = new QueryEngineImpl.FunctionContributionsImpl(
sessionFactory.getServiceRegistry(),
metadata.getTypeConfiguration(),
sqmFunctionRegistry
);
for ( FunctionContributor contributor : sortedFunctionContributors( sessionFactory.getServiceRegistry() ) ) {
final FunctionContributions functionContributions =
new FunctionContributionsImpl( serviceRegistry, metadata.getTypeConfiguration(), sqmFunctionRegistry );
for ( FunctionContributor contributor : sortedFunctionContributors( serviceRegistry ) ) {
contributor.contributeFunctions( functionContributions );
}
dialect.initializeFunctionRegistry( functionContributions );
if ( LOG_HQL_FUNCTIONS.isDebugEnabled() ) {
sqmFunctionRegistry.getFunctionsByName().forEach(
entry -> LOG_HQL_FUNCTIONS.debug( entry.getValue().getSignature( entry.getKey() ) )
);
sqmFunctionRegistry.getFunctionsByName()
.forEach( entry -> LOG_HQL_FUNCTIONS.debug( entry.getValue().getSignature( entry.getKey() ) ) );
}
return sqmFunctionRegistry;
@ -114,14 +117,16 @@ public class QueryEngineImpl implements QueryEngine {
private final SqmFunctionRegistry sqmFunctionRegistry;
private QueryEngineImpl(
SessionFactoryImplementor sessionFactory,
TypeConfiguration typeConfiguration,
HqlTranslator hqlTranslator,
SqmTranslatorFactory sqmTranslatorFactory,
SqmFunctionRegistry functionRegistry,
NamedObjectRepository namedObjectRepository,
QueryInterpretationCache interpretationCache,
NativeQueryInterpreter nativeQueryInterpreter) {
NativeQueryInterpreter nativeQueryInterpreter,
BindingContext context,
QueryEngineOptions options,
String uuid, String name) {
this.typeConfiguration = typeConfiguration;
this.sqmFunctionRegistry = functionRegistry;
this.sqmTranslatorFactory = sqmTranslatorFactory;
@ -129,15 +134,13 @@ public class QueryEngineImpl implements QueryEngine {
this.namedObjectRepository = namedObjectRepository;
this.interpretationCache = interpretationCache;
this.nativeQueryInterpreter = nativeQueryInterpreter;
final SessionFactoryOptions sessionFactoryOptions = sessionFactory.getSessionFactoryOptions();
this.criteriaBuilder = new SqmCriteriaNodeBuilder(
sessionFactory.getUuid(),
sessionFactory.getName(),
this,
sessionFactoryOptions.getJpaCompliance().isJpaQueryComplianceEnabled(),
sessionFactoryOptions.getCriteriaValueHandlingMode(),
() -> sessionFactory
);
this.criteriaBuilder = createCriteriaBuilder( context, options, uuid, name );
}
private SqmCriteriaNodeBuilder createCriteriaBuilder(
BindingContext context, QueryEngineOptions options,
String uuid, String name) {
return new SqmCriteriaNodeBuilder( uuid, name, this, options, context );
}
private static HqlTranslator resolveHqlTranslator(
@ -171,10 +174,10 @@ public class QueryEngineImpl implements QueryEngine {
}
private static List<FunctionContributor> sortedFunctionContributors(ServiceRegistry serviceRegistry) {
Collection<FunctionContributor> functionContributors =
final Collection<FunctionContributor> functionContributors =
serviceRegistry.requireService(ClassLoaderService.class)
.loadJavaServices(FunctionContributor.class);
List<FunctionContributor> contributors = new ArrayList<>( functionContributors );
final List<FunctionContributor> contributors = new ArrayList<>( functionContributors );
contributors.sort(
comparingInt( FunctionContributor::ordinal )
.thenComparing( a -> a.getClass().getCanonicalName() )
@ -183,8 +186,7 @@ public class QueryEngineImpl implements QueryEngine {
}
private static QueryInterpretationCache buildInterpretationCache(
Supplier<StatisticsImplementor> statisticsSupplier,
Map<String, Object> properties) {
ServiceRegistry serviceRegistry, Map<String, Object> properties) {
final boolean explicitUseCache = ConfigurationHelper.getBoolean(
AvailableSettings.QUERY_PLAN_CACHE_ENABLED,
properties,
@ -202,11 +204,11 @@ public class QueryEngineImpl implements QueryEngine {
? explicitMaxPlanSize
: QueryEngine.DEFAULT_QUERY_PLAN_MAX_COUNT;
return new QueryInterpretationCacheStandardImpl( size, statisticsSupplier );
return new QueryInterpretationCacheStandardImpl( size, serviceRegistry );
}
else {
// disabled
return new QueryInterpretationCacheDisabledImpl( statisticsSupplier );
return new QueryInterpretationCacheDisabledImpl( serviceRegistry );
}
}
@ -299,5 +301,4 @@ public class QueryEngineImpl implements QueryEngine {
return serviceRegistry;
}
}
}

View File

@ -20,6 +20,7 @@ import org.hibernate.query.sql.spi.ParameterInterpretation;
import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.stat.spi.StatisticsImplementor;
/**
@ -27,10 +28,12 @@ import org.hibernate.stat.spi.StatisticsImplementor;
*/
public class QueryInterpretationCacheDisabledImpl implements QueryInterpretationCache {
private final Supplier<StatisticsImplementor> statisticsSupplier;
private final ServiceRegistry serviceRegistry;
public QueryInterpretationCacheDisabledImpl(Supplier<StatisticsImplementor> statisticsSupplier) {
this.statisticsSupplier = statisticsSupplier;
private StatisticsImplementor statistics;
public QueryInterpretationCacheDisabledImpl(ServiceRegistry serviceRegistry) {
this.serviceRegistry = serviceRegistry;
}
@Override
@ -43,9 +46,16 @@ public class QueryInterpretationCacheDisabledImpl implements QueryInterpretation
return 0;
}
private StatisticsImplementor getStatistics() {
if ( statistics == null ) {
statistics = serviceRegistry.requireService( StatisticsImplementor.class );
}
return statistics;
}
@Override
public <R> SelectQueryPlan<R> resolveSelectQueryPlan(Key key, Supplier<SelectQueryPlan<R>> creator) {
final StatisticsImplementor statistics = statisticsSupplier.get();
final StatisticsImplementor statistics = getStatistics();
if ( statistics.isStatisticsEnabled() ) {
statistics.queryPlanCacheMiss( key.getQueryString() );
}
@ -64,7 +74,7 @@ public class QueryInterpretationCacheDisabledImpl implements QueryInterpretation
@Override
public <R> HqlInterpretation<R> resolveHqlInterpretation(
String queryString, Class<R> expectedResultType, HqlTranslator translator) {
final StatisticsImplementor statistics = statisticsSupplier.get();
final StatisticsImplementor statistics = getStatistics();
final boolean stats = statistics.isStatisticsEnabled();
final long startTime = stats ? System.nanoTime() : 0L;

View File

@ -23,6 +23,7 @@ import org.hibernate.query.spi.SimpleHqlInterpretationImpl;
import org.hibernate.query.sql.spi.ParameterInterpretation;
import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.jboss.logging.Logger;
@ -40,17 +41,19 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
*/
private final BoundedConcurrentHashMap<Key, QueryPlan> queryPlanCache;
private final ServiceRegistry serviceRegistry;
private final BoundedConcurrentHashMap<Object, HqlInterpretation<?>> hqlInterpretationCache;
private final BoundedConcurrentHashMap<String, ParameterInterpretation> nativeQueryParamCache;
private final Supplier<StatisticsImplementor> statisticsSupplier;
public QueryInterpretationCacheStandardImpl(int maxQueryPlanCount, Supplier<StatisticsImplementor> statisticsSupplier) {
private StatisticsImplementor statistics;
public QueryInterpretationCacheStandardImpl(int maxQueryPlanCount, ServiceRegistry serviceRegistry) {
log.debugf( "Starting QueryInterpretationCache(%s)", maxQueryPlanCount );
this.queryPlanCache = new BoundedConcurrentHashMap<>( maxQueryPlanCount, 20, BoundedConcurrentHashMap.Eviction.LIRS );
this.hqlInterpretationCache = new BoundedConcurrentHashMap<>( maxQueryPlanCount, 20, BoundedConcurrentHashMap.Eviction.LIRS );
this.nativeQueryParamCache = new BoundedConcurrentHashMap<>( maxQueryPlanCount, 20, BoundedConcurrentHashMap.Eviction.LIRS );
this.statisticsSupplier = statisticsSupplier;
this.serviceRegistry = serviceRegistry;
}
@Override
@ -63,12 +66,19 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
return queryPlanCache.size();
}
private StatisticsImplementor getStatistics() {
if ( statistics == null ) {
statistics = serviceRegistry.requireService( StatisticsImplementor.class );
}
return statistics;
}
@Override
public <R> SelectQueryPlan<R> resolveSelectQueryPlan(
Key key,
Supplier<SelectQueryPlan<R>> creator) {
log.tracef( "QueryPlan#getSelectQueryPlan(%s)", key );
final StatisticsImplementor statistics = statisticsSupplier.get();
final StatisticsImplementor statistics = getStatistics();
final boolean stats = statistics.isStatisticsEnabled();
@SuppressWarnings("unchecked")
@ -105,7 +115,7 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
Class<R> expectedResultType,
HqlTranslator translator) {
log.tracef( "QueryPlan#resolveHqlInterpretation( `%s` )", queryString );
final StatisticsImplementor statistics = statisticsSupplier.get();
final StatisticsImplementor statistics = getStatistics();
final Object cacheKey = expectedResultType != null
? new HqlInterpretationCacheKey( queryString, expectedResultType )

View File

@ -9,6 +9,7 @@ package org.hibernate.query.spi;
import java.util.Map;
import org.hibernate.jpa.spi.JpaCompliance;
import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode;
import org.hibernate.query.criteria.ValueHandlingMode;
import org.hibernate.query.hql.HqlTranslator;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
@ -73,9 +74,16 @@ public interface QueryEngineOptions {
ValueHandlingMode getCriteriaValueHandlingMode();
default ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHandlingMode() {
return ImmutableEntityUpdateQueryHandlingMode.WARNING;
}
/**
* @see org.hibernate.cfg.AvailableSettings#PORTABLE_INTEGER_DIVISION
*/
boolean isPortableIntegerDivisionEnabled();
String getSessionFactoryName();
String getUuid();
}

View File

@ -10,9 +10,9 @@ import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.BindableType;
import org.hibernate.query.QueryArgumentException;
import org.hibernate.query.BindingContext;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.type.descriptor.java.JavaType;
@ -28,22 +28,22 @@ public class QueryParameterBindingValidator {
private QueryParameterBindingValidator() {
}
public void validate(BindableType<?> paramType, Object bind, SessionFactoryImplementor sessionFactory) {
validate( paramType, bind, null, sessionFactory );
public void validate(BindableType<?> paramType, Object bind, BindingContext bindingContext) {
validate( paramType, bind, null, bindingContext);
}
public void validate(
BindableType<?> paramType,
Object bind,
TemporalType temporalPrecision,
SessionFactoryImplementor sessionFactory) {
BindingContext bindingContext) {
if ( bind == null || paramType == null ) {
// nothing we can check
return;
}
final Class<?> parameterJavaType;
final SqmExpressible<?> sqmExpressible = paramType.resolveExpressible( sessionFactory );
final SqmExpressible<?> sqmExpressible = paramType.resolveExpressible(bindingContext);
if ( paramType.getBindableJavaType() != null ) {
parameterJavaType = paramType.getBindableJavaType();
}

View File

@ -17,9 +17,11 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.jpa.spi.JpaCompliance;
import org.hibernate.metamodel.model.domain.JpaMetamodel;
import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode;
import org.hibernate.query.NullPrecedence;
import org.hibernate.query.BindingContext;
import org.hibernate.query.SortDirection;
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
import org.hibernate.query.criteria.JpaCoalesce;
@ -78,7 +80,7 @@ import jakarta.persistence.criteria.Subquery;
* @author Steve Ebersole
*/
@SuppressWarnings("unchecked")
public interface NodeBuilder extends HibernateCriteriaBuilder {
public interface NodeBuilder extends HibernateCriteriaBuilder, BindingContext {
JpaMetamodel getDomainModel();
TypeConfiguration getTypeConfiguration();
@ -1194,5 +1196,7 @@ public interface NodeBuilder extends HibernateCriteriaBuilder {
BasicType<Character> getCharacterType();
SessionFactoryImplementor getSessionFactory();
JpaCompliance getJpaCompliance();
ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHandlingMode();
}

View File

@ -6,9 +6,9 @@
*/
package org.hibernate.query.sqm;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.query.BindableType;
import org.hibernate.query.BindingContext;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.type.descriptor.java.JavaType;
@ -36,7 +36,7 @@ public interface SqmExpressible<J> extends BindableType<J> {
}
@Override
default SqmExpressible<J> resolveExpressible(SessionFactoryImplementor sessionFactory) {
default SqmExpressible<J> resolveExpressible(BindingContext bindingContext) {
return this;
}

View File

@ -7,6 +7,7 @@
package org.hibernate.query.sqm.internal;
import java.io.InvalidObjectException;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
@ -31,18 +32,17 @@ import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.function.Supplier;
import org.hibernate.SessionFactory;
import org.hibernate.dialect.function.AvgFunction;
import org.hibernate.dialect.function.SumReturnTypeResolver;
import org.hibernate.dialect.function.array.DdlTypeHelper;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.SessionFactoryRegistry;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jpa.spi.JpaCompliance;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.JpaMetamodel;
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
@ -50,7 +50,9 @@ import org.hibernate.metamodel.model.domain.internal.BasicTypeImpl;
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.query.BindableType;
import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode;
import org.hibernate.query.NullPrecedence;
import org.hibernate.query.BindingContext;
import org.hibernate.query.ReturnableType;
import org.hibernate.query.SemanticException;
import org.hibernate.query.SortDirection;
@ -72,6 +74,7 @@ import org.hibernate.query.criteria.JpaWindow;
import org.hibernate.query.criteria.ValueHandlingMode;
import org.hibernate.query.criteria.spi.CriteriaBuilderExtension;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.spi.QueryEngineOptions;
import org.hibernate.query.sqm.BinaryArithmeticOperator;
import org.hibernate.query.sqm.ComparisonOperator;
import org.hibernate.query.sqm.FrameKind;
@ -205,10 +208,11 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
private final String uuid;
private final String name;
private final transient boolean jpaComplianceEnabled;
private final transient JpaCompliance jpaCompliance;
private final transient QueryEngine queryEngine;
private final transient Supplier<SessionFactoryImplementor> sessionFactory;
private transient ValueHandlingMode criteriaValueHandlingMode;
private final transient ImmutableEntityUpdateQueryHandlingMode immutableEntityUpdateQueryHandlingMode;
private final transient BindingContext bindingContext;
private transient BasicType<Boolean> booleanType;
private transient BasicType<Integer> integerType;
private transient BasicType<Long> longType;
@ -220,15 +224,15 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
public SqmCriteriaNodeBuilder(
String uuid, String name,
QueryEngine queryEngine,
boolean jpaComplianceEnabled,
ValueHandlingMode criteriaValueHandlingMode,
Supplier<SessionFactoryImplementor> sessionFactory) {
this.sessionFactory = sessionFactory;
QueryEngineOptions options,
BindingContext bindingContext) {
this.queryEngine = queryEngine;
this.uuid = uuid;
this.name = name;
this.jpaComplianceEnabled = jpaComplianceEnabled;
this.criteriaValueHandlingMode = criteriaValueHandlingMode;
this.jpaCompliance = options.getJpaCompliance();
this.criteriaValueHandlingMode = options.getCriteriaValueHandlingMode();
this.immutableEntityUpdateQueryHandlingMode = options.getImmutableEntityUpdateQueryHandlingMode();
this.bindingContext = bindingContext;
// load registered criteria builder extensions
this.extensions = new HashMap<>();
for ( CriteriaBuilderExtension extension : ServiceLoader.load( CriteriaBuilderExtension.class ) ) {
@ -243,7 +247,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public JpaMetamodel getDomainModel() {
return getSessionFactory().getJpaMetamodel();
return bindingContext.getJpaMetamodel();
}
@Override
@ -253,14 +257,18 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public boolean isJpaQueryComplianceEnabled() {
return jpaComplianceEnabled;
return jpaCompliance.isJpaQueryComplianceEnabled();
}
@Override
public SessionFactoryImplementor getSessionFactory() {
return sessionFactory.get();
public JpaCompliance getJpaCompliance() {
return jpaCompliance;
}
@Override
public ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHandlingMode() {
return immutableEntityUpdateQueryHandlingMode;
}
@Override
public BasicType<Boolean> getBooleanType() {
@ -329,7 +337,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public JpaMetamodelImplementor getJpaMetamodel() {
return getSessionFactory().getJpaMetamodel();
return (JpaMetamodelImplementor) bindingContext.getJpaMetamodel();
}
@Override
@ -349,8 +357,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public <T> SqmSelectStatement<T> createQuery(String hql, Class<T> resultClass) {
final SqmStatement<T> statement =
sessionFactory.get().getQueryEngine().getHqlTranslator()
.translate( hql, resultClass );
queryEngine.getHqlTranslator().translate( hql, resultClass );
if ( statement instanceof SqmSelectStatement ) {
return new SqmSelectStatement<>( (SqmSelectStatement<T>) statement );
}
@ -1545,7 +1552,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public <T> SqmLiteral<T> literal(T value) {
if ( value == null ) {
if ( jpaComplianceEnabled ) {
if ( jpaCompliance.isJpaQueryComplianceEnabled() ) {
throw new IllegalArgumentException( "literal value cannot be null" );
}
return new SqmLiteralNull<>( this );
@ -1553,13 +1560,14 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
else {
final BindableType<? super T> valueParamType = getParameterBindType( value );
final SqmExpressible<? super T> sqmExpressible =
valueParamType == null ? null : valueParamType.resolveExpressible( getSessionFactory() );
valueParamType == null ? null : valueParamType.resolveExpressible( this );
return new SqmLiteral<>( value, sqmExpressible, this );
}
}
private MappingMetamodelImplementor getMappingMetamodel() {
return getSessionFactory().getMappingMetamodel();
@Override
public MappingMetamodelImplementor getMappingMetamodel() {
return (MappingMetamodelImplementor) bindingContext.getMappingMetamodel();
}
@Override
@ -2086,7 +2094,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
else {
return bindableType.getBindableJavaType().isInstance( value )
|| bindableType.resolveExpressible( getSessionFactory() ).getExpressibleJavaType().isInstance( value );
|| bindableType.resolveExpressible( this ).getExpressibleJavaType().isInstance( value );
}
}
@ -2128,7 +2136,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
return new ValueBindJpaCriteriaParameter<>( bindableType, value, this );
}
final T coercedValue =
bindableType.resolveExpressible( getSessionFactory() ).getExpressibleJavaType()
bindableType.resolveExpressible( this ).getExpressibleJavaType()
.coerce(value, this::getTypeConfiguration );
if ( isInstance( bindableType, coercedValue ) ) {
return new ValueBindJpaCriteriaParameter<>( bindableType, coercedValue, this );
@ -2151,7 +2159,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
DomainType<E> elementType = null;
if ( bindableType != null ) {
final SqmExpressible<E> sqmExpressible = bindableType.resolveExpressible( getSessionFactory() );
final SqmExpressible<E> sqmExpressible = bindableType.resolveExpressible( this );
elementType = sqmExpressible.getSqmType();
}
if ( elementType == null ) {
@ -2958,6 +2966,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
*
* @throws InvalidObjectException Thrown if we could not resolve the factory by uuid/name.
*/
@Serial
private Object readResolve() throws InvalidObjectException {
LOG.trace( "Resolving serialized SqmCriteriaNodeBuilder" );
return locateSessionFactoryOnDeserialization( uuid, name ).getCriteriaBuilder();

View File

@ -24,6 +24,7 @@ import java.util.function.Function;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jpa.spi.JpaCompliance;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.Bindable;
@ -307,17 +308,15 @@ public class SqmUtil {
} while (declaringType.getPersistenceType() != Type.PersistenceType.ENTITY );
pathBuilder.insert(0, '.');
pathBuilder.insert( 0, attribute.getName() );
final EntityPersister entityDescriptor = sqmJoin.nodeBuilder()
.getSessionFactory()
.getMappingMetamodel()
.getEntityDescriptor( ( (EntityDomainType<?>) declaringType ).getHibernateEntityName() );
final EntityPersister entityDescriptor =
sqmJoin.nodeBuilder().getMappingMetamodel()
.getEntityDescriptor( ( (EntityDomainType<?>) declaringType ).getHibernateEntityName() );
return (EntityAssociationMapping) entityDescriptor.findByPath( pathBuilder.toString() );
}
else {
final EntityPersister entityDescriptor = sqmJoin.nodeBuilder()
.getSessionFactory()
.getMappingMetamodel()
.getEntityDescriptor( ( (EntityDomainType<?>) declaringType ).getHibernateEntityName() );
final EntityPersister entityDescriptor =
sqmJoin.nodeBuilder().getMappingMetamodel()
.getEntityDescriptor( ( (EntityDomainType<?>) declaringType ).getHibernateEntityName() );
return (EntityAssociationMapping) entityDescriptor.findAttributeMapping( attribute.getName() );
}
}
@ -999,7 +998,7 @@ public class SqmUtil {
}
private static void checkQueryReturnType(SqmQuerySpec<?> querySpec, Class<?> expectedResultClass) {
final SessionFactoryImplementor sessionFactory = querySpec.nodeBuilder().getSessionFactory();
final JpaCompliance jpaCompliance = querySpec.nodeBuilder().getJpaCompliance();
final List<SqmSelection<?>> selections = querySpec.getSelectClause().getSelections();
if ( selections == null || selections.isEmpty() ) {
// make sure there is at least one root
@ -1009,7 +1008,7 @@ public class SqmUtil {
}
// if there is a single root, use that as the selection
if ( sqmRoots.size() == 1 ) {
verifySingularSelectionType( expectedResultClass, sessionFactory, sqmRoots.get( 0 ) );
verifySingularSelectionType( expectedResultClass, jpaCompliance, sqmRoots.get( 0 ) );
}
else {
throw new IllegalArgumentException( "Criteria has multiple query roots" );
@ -1023,17 +1022,17 @@ public class SqmUtil {
? expectedResultClass.getComponentType()
: expectedResultClass;
for ( JpaSelection<?> selection : selectableNode.getSelectionItems() ) {
verifySelectionType( expectedSelectItemType, sessionFactory, (SqmSelectableNode<?>) selection );
verifySelectionType( expectedSelectItemType, jpaCompliance, (SqmSelectableNode<?>) selection );
}
}
else {
verifySingularSelectionType( expectedResultClass, sessionFactory, sqmSelection.getSelectableNode() );
verifySingularSelectionType( expectedResultClass, jpaCompliance, sqmSelection.getSelectableNode() );
}
}
else if ( expectedResultClass.isArray() ) {
final Class<?> componentType = expectedResultClass.getComponentType();
for ( SqmSelection<?> selection : selections ) {
verifySelectionType( componentType, sessionFactory, selection.getSelectableNode() );
verifySelectionType( componentType, jpaCompliance, selection.getSelectableNode() );
}
}
}
@ -1050,10 +1049,10 @@ public class SqmUtil {
*/
private static void verifySingularSelectionType(
Class<?> expectedResultClass,
SessionFactoryImplementor sessionFactory,
JpaCompliance jpaCompliance,
SqmSelectableNode<?> selectableNode) {
try {
verifySelectionType( expectedResultClass, sessionFactory, selectableNode );
verifySelectionType( expectedResultClass, jpaCompliance, selectableNode );
}
catch (QueryTypeMismatchException mismatchException) {
// Check for special case of a single selection item and implicit instantiation.
@ -1084,7 +1083,7 @@ public class SqmUtil {
private static <T> void verifySelectionType(
Class<T> expectedResultClass,
SessionFactoryImplementor sessionFactory,
JpaCompliance jpaCompliance,
SqmSelectableNode<?> selection) {
// special case for parameters in the select list
if ( selection instanceof SqmParameter ) {
@ -1097,18 +1096,18 @@ public class SqmUtil {
}
}
if ( !sessionFactory.getSessionFactoryOptions().getJpaCompliance().isJpaQueryComplianceEnabled() ) {
if ( !jpaCompliance.isJpaQueryComplianceEnabled() ) {
verifyResultType( expectedResultClass, selection.getExpressible() );
}
}
public static boolean isResultTypeAlwaysAllowed(Class<?> expectedResultClass) {
return expectedResultClass == null
|| expectedResultClass == Object.class
|| expectedResultClass == Object[].class
|| expectedResultClass == List.class
|| expectedResultClass == Map.class
|| expectedResultClass == Tuple.class;
|| expectedResultClass == Object.class
|| expectedResultClass == Object[].class
|| expectedResultClass == List.class
|| expectedResultClass == Map.class
|| expectedResultClass == Tuple.class;
}
protected static void verifyResultType(Class<?> resultClass, @Nullable SqmExpressible<?> selectionExpressible) {

View File

@ -8,7 +8,6 @@ package org.hibernate.query.sqm.internal;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.metamodel.EntityType;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
@ -16,6 +15,7 @@ import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.TupleType;
import org.hibernate.metamodel.model.domain.internal.EntityDiscriminatorSqmPathSource;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.BindingContext;
import org.hibernate.query.SemanticException;
import org.hibernate.query.sqm.BinaryArithmeticOperator;
import org.hibernate.query.sqm.SqmExpressible;
@ -29,7 +29,6 @@ import org.hibernate.query.sqm.tree.expression.SqmLiteralNull;
import org.hibernate.type.BasicPluralType;
import org.hibernate.type.BasicType;
import org.hibernate.type.QueryParameterJavaObjectType;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import java.time.temporal.Temporal;
@ -77,8 +76,8 @@ import static org.hibernate.type.descriptor.java.JavaTypeHelper.isUnknown;
* function application) is legal only when the entity types belong to the same mapped
* entity hierarchy.
*
* @see #assertComparable(Expression, Expression, SessionFactoryImplementor)
* @see #assertAssignable(String, SqmPath, SqmTypedNode, SessionFactoryImplementor)
* @see #assertComparable(Expression, Expression, BindingContext)
* @see #assertAssignable(String, SqmPath, SqmTypedNode, BindingContext)
*
* @author Gavin King
*/
@ -100,12 +99,12 @@ public class TypecheckUtil {
* @param lhsType the type of the expression on the LHS of the comparison operator
* @param rhsType the type of the expression on the RHS of the comparison operator
*
* @see #isTypeAssignable(SqmPathSource, SqmExpressible, SessionFactoryImplementor)
* @see #isTypeAssignable(SqmPathSource, SqmExpressible, BindingContext)
*/
public static boolean areTypesComparable(
SqmExpressible<?> lhsType,
SqmExpressible<?> rhsType,
SessionFactoryImplementor factory) {
BindingContext bindingContext) {
if ( lhsType == null || rhsType == null || lhsType == rhsType ) {
return true;
}
@ -139,7 +138,7 @@ public class TypecheckUtil {
// for tuple constructors, we must check each element
if ( lhsDomainType instanceof TupleType && rhsDomainType instanceof TupleType ) {
return areTupleTypesComparable( factory, (TupleType<?>) lhsDomainType, (TupleType<?>) rhsDomainType );
return areTupleTypesComparable(bindingContext, (TupleType<?>) lhsDomainType, (TupleType<?>) rhsDomainType );
}
// allow comparing an embeddable against a tuple literal
@ -153,17 +152,17 @@ public class TypecheckUtil {
// entities can be compared if they belong to the same inheritance hierarchy
if ( lhsDomainType instanceof EntityType && rhsDomainType instanceof EntityType ) {
return areEntityTypesComparable( (EntityType<?>) lhsDomainType, (EntityType<?>) rhsDomainType, factory );
return areEntityTypesComparable( (EntityType<?>) lhsDomainType, (EntityType<?>) rhsDomainType, bindingContext);
}
// entities can be compared to discriminators if they belong to
// the same inheritance hierarchy
if ( lhsDomainType instanceof EntityDiscriminatorSqmPathSource ) {
return isDiscriminatorTypeComparable( (EntityDiscriminatorSqmPathSource<?>) lhsDomainType, rhsDomainType, factory );
return isDiscriminatorTypeComparable( (EntityDiscriminatorSqmPathSource<?>) lhsDomainType, rhsDomainType, bindingContext);
}
if ( rhsDomainType instanceof EntityDiscriminatorSqmPathSource ) {
return isDiscriminatorTypeComparable( (EntityDiscriminatorSqmPathSource<?>) rhsDomainType, lhsDomainType, factory );
return isDiscriminatorTypeComparable( (EntityDiscriminatorSqmPathSource<?>) rhsDomainType, lhsDomainType, bindingContext);
}
// Treat the expressions as comparable if they belong to the same
@ -173,7 +172,7 @@ public class TypecheckUtil {
// enums, user-defined types, etc.
if ( lhsDomainType instanceof JdbcMapping && rhsDomainType instanceof JdbcMapping ) {
if ( areJdbcMappingsComparable( (JdbcMapping) lhsDomainType, (JdbcMapping) rhsDomainType, factory ) ) {
if ( areJdbcMappingsComparable( (JdbcMapping) lhsDomainType, (JdbcMapping) rhsDomainType, bindingContext) ) {
return true;
}
}
@ -195,14 +194,14 @@ public class TypecheckUtil {
private static boolean areJdbcMappingsComparable(
JdbcMapping lhsJdbcMapping,
JdbcMapping rhsJdbcMapping,
SessionFactoryImplementor factory) {
BindingContext bindingContext) {
if ( areJdbcTypesComparable( lhsJdbcMapping.getJdbcType(), rhsJdbcMapping.getJdbcType() ) ) {
return true;
}
// converters are implicitly applied to the other side when its domain type is compatible
else if ( lhsJdbcMapping.getValueConverter() != null || rhsJdbcMapping.getValueConverter() != null ) {
final JdbcMapping lhsDomainMapping = getDomainJdbcType( lhsJdbcMapping, factory );
final JdbcMapping rhsDomainMapping = getDomainJdbcType( rhsJdbcMapping, factory );
final JdbcMapping lhsDomainMapping = getDomainJdbcType( lhsJdbcMapping, bindingContext);
final JdbcMapping rhsDomainMapping = getDomainJdbcType( rhsJdbcMapping, bindingContext);
return lhsDomainMapping != null && rhsDomainMapping != null && areJdbcTypesComparable(
lhsDomainMapping.getJdbcType(),
rhsDomainMapping.getJdbcType()
@ -220,11 +219,11 @@ public class TypecheckUtil {
|| lhsJdbcType.isNumber() && rhsJdbcType.isNumber();
}
private static JdbcMapping getDomainJdbcType(JdbcMapping jdbcMapping, SessionFactoryImplementor factory) {
private static JdbcMapping getDomainJdbcType(JdbcMapping jdbcMapping, BindingContext bindingContext) {
if ( jdbcMapping.getValueConverter() != null ) {
final BasicType<?> basicType = factory.getTypeConfiguration().getBasicTypeForJavaType(
jdbcMapping.getValueConverter().getDomainJavaType().getJavaType()
);
final BasicType<?> basicType =
bindingContext.getTypeConfiguration()
.getBasicTypeForJavaType( jdbcMapping.getValueConverter().getDomainJavaType().getJavaType() );
if ( basicType != null ) {
return basicType.getJdbcMapping();
}
@ -255,7 +254,7 @@ public class TypecheckUtil {
}
private static boolean areTupleTypesComparable(
SessionFactoryImplementor factory,
BindingContext bindingContext,
TupleType<?> lhsTuple,
TupleType<?> rhsTuple) {
if ( rhsTuple.componentCount() != lhsTuple.componentCount() ) {
@ -263,7 +262,7 @@ public class TypecheckUtil {
}
else {
for ( int i = 0; i < lhsTuple.componentCount(); i++ ) {
if ( !areTypesComparable( lhsTuple.get(i), rhsTuple.get(i), factory ) ) {
if ( !areTypesComparable( lhsTuple.get(i), rhsTuple.get(i), bindingContext) ) {
return false;
}
}
@ -273,32 +272,32 @@ public class TypecheckUtil {
private static boolean areEntityTypesComparable(
EntityType<?> lhsType, EntityType<?> rhsType,
SessionFactoryImplementor factory) {
EntityPersister lhsEntity = getEntityDescriptor( factory, lhsType.getName() );
EntityPersister rhsEntity = getEntityDescriptor( factory, rhsType.getName() );
BindingContext bindingContext) {
EntityPersister lhsEntity = getEntityDescriptor(bindingContext, lhsType.getName() );
EntityPersister rhsEntity = getEntityDescriptor(bindingContext, rhsType.getName() );
return lhsEntity.getRootEntityName().equals( rhsEntity.getRootEntityName() );
}
private static boolean isDiscriminatorTypeComparable(
EntityDiscriminatorSqmPathSource<?> lhsDiscriminator, SqmExpressible<?> rhsType,
SessionFactoryImplementor factory) {
BindingContext bindingContext) {
String entityName = lhsDiscriminator.getEntityDomainType().getHibernateEntityName();
EntityPersister lhsEntity = factory.getMappingMetamodel().getEntityDescriptor( entityName );
EntityPersister lhsEntity = bindingContext.getMappingMetamodel().getEntityDescriptor( entityName );
if ( rhsType instanceof EntityType ) {
String rhsEntityName = ((EntityType<?>) rhsType).getName();
EntityPersister rhsEntity = getEntityDescriptor( factory, rhsEntityName );
EntityPersister rhsEntity = getEntityDescriptor(bindingContext, rhsEntityName );
return lhsEntity.getRootEntityName().equals( rhsEntity.getRootEntityName() );
}
else if ( rhsType instanceof EntityDiscriminatorSqmPathSource ) {
EntityDiscriminatorSqmPathSource<?> discriminator = (EntityDiscriminatorSqmPathSource<?>) rhsType;
String rhsEntityName = discriminator.getEntityDomainType().getHibernateEntityName();
EntityPersister rhsEntity = factory.getMappingMetamodel().getEntityDescriptor( rhsEntityName );
EntityPersister rhsEntity = bindingContext.getMappingMetamodel().getEntityDescriptor( rhsEntityName );
return rhsEntity.getRootEntityName().equals( lhsEntity.getRootEntityName() );
}
else {
BasicType<?> discriminatorType = (BasicType<?>)
lhsDiscriminator.getEntityMapping().getDiscriminatorMapping().getMappedType();
return areTypesComparable( discriminatorType, rhsType, factory );
return areTypesComparable( discriminatorType, rhsType, bindingContext);
}
}
@ -306,11 +305,11 @@ public class TypecheckUtil {
* @param targetType the type of the path expression to which a value is assigned
* @param expressionType the type of the value expression being assigned to the path
*
* @see #areTypesComparable(SqmExpressible, SqmExpressible, SessionFactoryImplementor)
* @see #areTypesComparable(SqmExpressible, SqmExpressible, BindingContext)
*/
private static boolean isTypeAssignable(
SqmPathSource<?> targetType, SqmExpressible<?> expressionType,
SessionFactoryImplementor factory) {
BindingContext bindingContext) {
if ( targetType == null || expressionType == null || targetType == expressionType ) {
return true;
@ -319,7 +318,7 @@ public class TypecheckUtil {
// entities can be assigned if they belong to the same inheritance hierarchy
if ( targetType instanceof EntityType && expressionType instanceof EntityType ) {
return isEntityTypeAssignable( (EntityType<?>) targetType, (EntityType<?>) expressionType, factory );
return isEntityTypeAssignable( (EntityType<?>) targetType, (EntityType<?>) expressionType, bindingContext);
}
// Treat the expression as assignable to the target path if they belong
@ -367,21 +366,21 @@ public class TypecheckUtil {
private static boolean isEntityTypeAssignable(
EntityType<?> lhsType, EntityType<?> rhsType,
SessionFactoryImplementor factory) {
EntityPersister lhsEntity = getEntityDescriptor( factory, lhsType.getName() );
EntityPersister rhsEntity = getEntityDescriptor( factory, rhsType.getName() );
BindingContext bindingContext) {
EntityPersister lhsEntity = getEntityDescriptor(bindingContext, lhsType.getName() );
EntityPersister rhsEntity = getEntityDescriptor(bindingContext, rhsType.getName() );
return lhsEntity.isSubclassEntityName( rhsEntity.getEntityName() );
}
private static EntityPersister getEntityDescriptor(SessionFactoryImplementor factory, String name) {
return factory.getMappingMetamodel()
.getEntityDescriptor( factory.getJpaMetamodel().qualifyImportableName( name ) );
private static EntityPersister getEntityDescriptor(BindingContext bindingContext, String name) {
return bindingContext.getMappingMetamodel()
.getEntityDescriptor( bindingContext.getJpaMetamodel().qualifyImportableName( name ) );
}
/**
* @see TypecheckUtil#assertAssignable(String, SqmPath, SqmTypedNode, SessionFactoryImplementor)
* @see TypecheckUtil#assertAssignable(String, SqmPath, SqmTypedNode, BindingContext)
*/
public static void assertComparable(Expression<?> x, Expression<?> y, SessionFactoryImplementor factory) {
public static void assertComparable(Expression<?> x, Expression<?> y, BindingContext bindingContext) {
final SqmExpression<?> left = (SqmExpression<?>) x;
final SqmExpression<?> right = (SqmExpression<?>) y;
final Integer leftTupleLength = left.getTupleLength();
@ -401,7 +400,7 @@ public class TypecheckUtil {
if ( !( left instanceof SqmLiteralNull ) && !( right instanceof SqmLiteralNull ) ) {
final SqmExpressible<?> leftType = left.getExpressible();
final SqmExpressible<?> rightType = right.getExpressible();
if ( !areTypesComparable( leftType, rightType, factory ) ) {
if ( !areTypesComparable( leftType, rightType, bindingContext) ) {
throw new SemanticException(
String.format(
"Cannot compare left expression of type '%s' with right expression of type '%s'",
@ -414,12 +413,12 @@ public class TypecheckUtil {
}
/**
* @see TypecheckUtil#assertComparable(Expression, Expression, SessionFactoryImplementor)
* @see TypecheckUtil#assertComparable(Expression, Expression, BindingContext)
*/
public static void assertAssignable(
String hqlString,
SqmPath<?> targetPath, SqmTypedNode<?> expression,
SessionFactoryImplementor factory) {
BindingContext bindingContext) {
// allow assigning literal null to things
if ( expression instanceof SqmLiteralNull ) {
// TODO: check that the target path is nullable
@ -427,7 +426,7 @@ public class TypecheckUtil {
else {
SqmPathSource<?> targetType = targetPath.getNodeType();
SqmExpressible<?> expressionType = expression.getNodeType();
if ( !isTypeAssignable( targetType, expressionType, factory ) ) {
if ( !isTypeAssignable( targetType, expressionType, bindingContext) ) {
throw new SemanticException(
String.format(
"Cannot assign expression of type '%s' to target path '%s' of type '%s'",

View File

@ -8,6 +8,7 @@ package org.hibernate.query.sqm.spi;
import org.hibernate.Incubating;
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
import org.hibernate.query.BindingContext;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.service.ServiceRegistry;
@ -19,7 +20,7 @@ import org.hibernate.type.spi.TypeConfiguration;
* @author Steve Ebersole
*/
@Incubating
public interface SqmCreationContext {
public interface SqmCreationContext extends BindingContext {
/**
* Access to the domain model metadata
*/

View File

@ -6162,7 +6162,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
}
}
final SqmExpressible<?> paramSqmType = paramType.resolveExpressible( creationContext.getSessionFactory() );
final SqmExpressible<?> paramSqmType = paramType.resolveExpressible( creationContext );
if ( paramSqmType instanceof SqmPath ) {
final MappingModelExpressible<?> modelPart = determineValueMapping( (SqmPath<?>) paramSqmType );

View File

@ -196,7 +196,7 @@ public abstract class AbstractSqmPath<T> extends AbstractSqmExpression<T> implem
@SuppressWarnings("unchecked")
public SqmPath<?> get(String attributeName) {
final SqmPathSource<?> subNavigable =
getResolvedModel().getSubPathSource( attributeName, nodeBuilder().getSessionFactory().getJpaMetamodel() );
getResolvedModel().getSubPathSource( attributeName, nodeBuilder().getJpaMetamodel() );
return resolvePath( attributeName, subNavigable );
}

View File

@ -54,7 +54,7 @@ public class JpaCriteriaParameter<T>
if ( type == null ) {
return null;
}
return type.resolveExpressible( nodeBuilder.getSessionFactory() );
return type.resolveExpressible( nodeBuilder );
}
@Override

View File

@ -15,9 +15,9 @@ import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetTime;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.model.domain.internal.EmbeddedSqmPathSource;
import org.hibernate.query.BindableType;
import org.hibernate.query.BindingContext;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.BinaryArithmeticOperator;
@ -37,26 +37,18 @@ import org.hibernate.usertype.internal.OffsetTimeCompositeUserType;
*/
public class SqmExpressionHelper {
public static <T> SqmExpressible<T> toSqmType(BindableType<T> parameterType, SqmCreationState creationState) {
return toSqmType( parameterType, creationState.getCreationContext().getNodeBuilder().getSessionFactory() );
return toSqmType( parameterType, creationState.getCreationContext() );
}
public static <T> SqmExpressible<T> toSqmType(BindableType<T> anticipatedType, NodeBuilder nodeBuilder) {
return toSqmType( anticipatedType, nodeBuilder.getSessionFactory() );
}
// public static <T> SqmExpressible<T> toSqmType(BindableType<T> anticipatedType, TypeConfiguration typeConfiguration) {
// return toSqmType( anticipatedType, typeConfiguration.getSessionFactory() );
// }
public static <T> SqmExpressible<T> toSqmType(BindableType<T> anticipatedType, SessionFactoryImplementor sessionFactory) {
public static <T> SqmExpressible<T> toSqmType(
BindableType<T> anticipatedType, BindingContext bindingContext) {
if ( anticipatedType == null ) {
return null;
}
final SqmExpressible<T> sqmExpressible = anticipatedType.resolveExpressible( sessionFactory );
final SqmExpressible<T> sqmExpressible = anticipatedType.resolveExpressible(bindingContext);
assert sqmExpressible != null;
return sqmExpressible;
}
public static SqmLiteral<Timestamp> timestampLiteralFrom(String literalText, SqmCreationState creationState) {

View File

@ -90,11 +90,11 @@ public abstract class AbstractSqmInsertStatement<T> extends AbstractSqmDmlStatem
null
);
}
final SessionFactoryImplementor factory = nodeBuilder().getSessionFactory();
for ( int i = 0; i < expressionsSize; i++ ) {
final SqmTypedNode<?> expression = expressions.get( i );
final SqmPath<?> targetPath = insertionTargetPaths.get(i);
assertAssignable( null, targetPath, expression, factory );
assertAssignable( null, targetPath, expression, nodeBuilder() );
// if ( expression.getNodeJavaType() == null ) {
// continue;
// }

View File

@ -83,7 +83,7 @@ public class SqmConflictUpdateAction<T> implements SqmNode, JpaConflictUpdateAct
else {
expression = (SqmExpression) nodeBuilder().value( value );
}
assertAssignable( null, sqmPath, expression, nodeBuilder().getSessionFactory() );
assertAssignable( null, sqmPath, expression, nodeBuilder() );
applyAssignment( sqmPath, expression );
return this;
}

View File

@ -34,8 +34,8 @@ public class SqmBetweenPredicate extends AbstractNegatableSqmPredicate {
this.lowerBound = lowerBound;
this.upperBound = upperBound;
assertComparable( expression, lowerBound, nodeBuilder.getSessionFactory() );
assertComparable( expression, upperBound, nodeBuilder.getSessionFactory() );
assertComparable( expression, lowerBound, nodeBuilder );
assertComparable( expression, upperBound, nodeBuilder );
final SqmExpressible<?> expressibleType = QueryHelper.highestPrecedenceType(
expression.getExpressible(),

View File

@ -43,7 +43,7 @@ public class SqmComparisonPredicate extends AbstractNegatableSqmPredicate {
this.rightHandExpression = rightHandExpression;
this.operator = operator;
assertComparable( leftHandExpression, rightHandExpression, nodeBuilder.getSessionFactory() );
assertComparable( leftHandExpression, rightHandExpression, nodeBuilder );
final SqmExpressible<?> expressibleType = QueryHelper.highestPrecedenceType(
leftHandExpression.getExpressible(),
@ -59,7 +59,7 @@ public class SqmComparisonPredicate extends AbstractNegatableSqmPredicate {
this.leftHandExpression = affirmativeForm.leftHandExpression;
this.rightHandExpression = affirmativeForm.rightHandExpression;
this.operator = affirmativeForm.operator;
assertComparable( leftHandExpression, rightHandExpression, nodeBuilder().getSessionFactory() );
assertComparable( leftHandExpression, rightHandExpression, nodeBuilder() );
}
@Override

View File

@ -136,7 +136,7 @@ public class SqmInListPredicate<T> extends AbstractNegatableSqmPredicate impleme
}
private void implyListElementType(SqmExpression<?> expression) {
assertComparable( getTestExpression(), expression, nodeBuilder().getSessionFactory() );
assertComparable( getTestExpression(), expression, nodeBuilder() );
expression.applyInferableType(
QueryHelper.highestPrecedenceType2( getTestExpression().getExpressible(), expression.getExpressible() )
);

View File

@ -42,7 +42,7 @@ public class SqmInSubQueryPredicate<T> extends AbstractNegatableSqmPredicate imp
this.testExpression = testExpression;
this.subQueryExpression = subQueryExpression;
assertComparable( testExpression, subQueryExpression, nodeBuilder.getSessionFactory() );
assertComparable( testExpression, subQueryExpression, nodeBuilder );
final SqmExpressible<?> expressibleType = QueryHelper.highestPrecedenceType2(
testExpression.getExpressible(),

View File

@ -39,7 +39,7 @@ public class SqmMemberOfPredicate extends AbstractNegatableSqmPredicate {
final SimpleDomainType<?> simpleDomainType = pluralPath.getReferencedPathSource().getElementType();
if ( !areTypesComparable(leftHandExpression.getNodeType(), simpleDomainType, nodeBuilder.getSessionFactory()) ) {
if ( !areTypesComparable( leftHandExpression.getNodeType(), simpleDomainType, nodeBuilder ) ) {
throw new SemanticException(
String.format(
"Cannot compare left expression of type '%s' with right expression of type '%s'",

View File

@ -12,7 +12,6 @@ import java.util.Map;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.persister.entity.EntityPersister;
@ -37,10 +36,8 @@ import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.ParameterExpression;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Subquery;
import jakarta.persistence.metamodel.EntityType;
import jakarta.persistence.metamodel.SingularAttribute;
import org.checkerframework.checker.nullness.qual.Nullable;
@ -135,12 +132,11 @@ public class SqmUpdateStatement<T>
}
private void verifyImmutableEntityUpdate(String hql) {
final SessionFactoryImplementor factory = nodeBuilder().getSessionFactory();
final EntityPersister persister =
factory.getMappingMetamodel().getEntityDescriptor( getTarget().getEntityName() );
nodeBuilder().getMappingMetamodel().getEntityDescriptor( getTarget().getEntityName() );
if ( !persister.isMutable() ) {
final ImmutableEntityUpdateQueryHandlingMode mode =
factory.getSessionFactoryOptions().getImmutableEntityUpdateQueryHandlingMode();
nodeBuilder().getImmutableEntityUpdateQueryHandlingMode();
final String querySpaces = Arrays.toString( persister.getQuerySpaces() );
switch ( mode ) {
case WARNING:
@ -155,13 +151,12 @@ public class SqmUpdateStatement<T>
}
private void verifyUpdateTypesMatch() {
final SessionFactoryImplementor factory = nodeBuilder().getSessionFactory();
final List<SqmAssignment<?>> assignments = getSetClause().getAssignments();
for ( int i = 0; i < assignments.size(); i++ ) {
final SqmAssignment<?> assignment = assignments.get( i );
final SqmPath<?> targetPath = assignment.getTargetPath();
final SqmExpression<?> expression = assignment.getValue();
assertAssignable( null, targetPath, expression, factory );
assertAssignable( null, targetPath, expression, nodeBuilder() );
}
}
@ -207,7 +202,7 @@ public class SqmUpdateStatement<T>
else {
expression = (SqmExpression) nodeBuilder().value( value );
}
assertAssignable( null, sqmPath, expression, nodeBuilder().getSessionFactory() );
assertAssignable( null, sqmPath, expression, nodeBuilder() );
applyAssignment( sqmPath, expression );
return this;
}

View File

@ -8,6 +8,7 @@ package org.hibernate.sql.ast.spi;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.query.BindingContext;
import org.hibernate.service.ServiceRegistry;
/**
@ -16,7 +17,7 @@ import org.hibernate.service.ServiceRegistry;
*
* @author Steve Ebersole
*/
public interface SqlAstCreationContext {
public interface SqlAstCreationContext extends BindingContext {
/**
* The SessionFactory
*/

View File

@ -8,7 +8,7 @@ package org.hibernate.type;
import java.io.Serializable;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.BindingContext;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.query.BindableType;
import org.hibernate.query.sqm.SqmExpressible;
@ -83,7 +83,7 @@ public final class BasicTypeReference<T> implements BindableType<T>, Serializabl
}
@Override
public SqmExpressible<T> resolveExpressible(SessionFactoryImplementor sessionFactory) {
return sessionFactory.getTypeConfiguration().getBasicTypeRegistry().resolve( this );
public SqmExpressible<T> resolveExpressible(BindingContext bindingContext) {
return bindingContext.getTypeConfiguration().getBasicTypeRegistry().resolve( this );
}
}

View File

@ -37,6 +37,7 @@ import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.BindingContext;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.jdbc.JdbcType;
@ -844,8 +845,8 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
}
@Override
public SqmExpressible<?> resolveExpressible(SessionFactoryImplementor sessionFactory) {
return sessionFactory.getJpaMetamodel().embeddable( getReturnedClass() );
public SqmExpressible<?> resolveExpressible(BindingContext bindingContext) {
return bindingContext.getJpaMetamodel().embeddable( getReturnedClass() );
}
@Override

View File

@ -12,6 +12,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.ast.spi.AfterLoadAction;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.model.domain.JpaMetamodel;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.service.ServiceRegistry;
@ -19,6 +20,7 @@ import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.exec.spi.Callback;
import org.hibernate.testing.orm.junit.BaseSessionFactoryFunctionalTest;
import org.hibernate.type.spi.TypeConfiguration;
/**
* @author Steve Ebersole
@ -80,6 +82,16 @@ public abstract class BaseSqmUnitTest
return sessionFactory().getRuntimeMetamodels().getMappingMetamodel();
}
@Override
public TypeConfiguration getTypeConfiguration() {
return sessionFactory().getTypeConfiguration();
}
@Override
public JpaMetamodel getJpaMetamodel() {
return sessionFactory().getJpaMetamodel();
}
@Override
public ServiceRegistry getServiceRegistry() {
return sessionFactory().getServiceRegistry();

View File

@ -6,8 +6,8 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.query.BindingContext;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.query.BindableType;
import org.hibernate.query.sqm.SqmExpressible;
@ -35,7 +35,7 @@ public class ArrayType implements UserType<Array>, BindableType<Array>, BasicVal
}
@Override
public SqmExpressible<Array> resolveExpressible(SessionFactoryImplementor sessionFactory) {
public SqmExpressible<Array> resolveExpressible(BindingContext bindingContext) {
// really a UserType should not implement BindableType
throw new UnsupportedOperationException();
}

View File

@ -82,7 +82,6 @@ import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.query.criteria.ValueHandlingMode;
import org.hibernate.query.hql.HqlTranslator;
import org.hibernate.query.hql.internal.StandardHqlTranslator;
import org.hibernate.query.hql.spi.SqmCreationOptions;
@ -152,6 +151,8 @@ public abstract class MockSessionFactory
private final MetadataImplementor bootModel;
private final MetadataContext metadataContext;
private final NodeBuilder nodeBuilder;
public MockSessionFactory() {
serviceRegistry = StandardServiceRegistryImpl.create(
@ -222,6 +223,8 @@ public abstract class MockSessionFactory
functionFactory.hypotheticalOrderedSetAggregates();
functionFactory.windowFunctions();
typeConfiguration.scope((SessionFactoryImplementor) this);
nodeBuilder = new SqmCriteriaNodeBuilder("", "", this, this, this);
}
@Override
@ -460,7 +463,7 @@ public abstract class MockSessionFactory
@Override
public QueryInterpretationCache getInterpretationCache() {
return new QueryInterpretationCacheDisabledImpl(this::getStatistics);
return new QueryInterpretationCacheDisabledImpl( serviceRegistry );
}
@Override
@ -475,14 +478,7 @@ public abstract class MockSessionFactory
@Override
public NodeBuilder getCriteriaBuilder() {
return new SqmCriteriaNodeBuilder(
"",
"",
this,
false,
ValueHandlingMode.INLINE,
() -> MockSessionFactory.this
);
return nodeBuilder;
}
@Override