HHH-17006, HHH-13016 various refactorings/cleanups before fix
- Misc cleanups and fixes to incorrect generic typing of some operations - Try to fix bodgy type inference algorithm for case/when expressions
This commit is contained in:
parent
5daf7a0354
commit
c74d6fa86f
|
@ -350,7 +350,7 @@ public class SessionFactoryDelegatingImpl implements SessionFactoryImplementor,
|
|||
}
|
||||
|
||||
@Override @Deprecated
|
||||
public <T> BindableType<? extends T> resolveParameterBindType(T bindValue) {
|
||||
public <T> BindableType<? super T> resolveParameterBindType(T bindValue) {
|
||||
return delegate.resolveParameterBindType( bindValue );
|
||||
}
|
||||
|
||||
|
|
|
@ -217,7 +217,7 @@ public interface SessionFactoryImplementor
|
|||
* @deprecated Use {@link #getMappingMetamodel()}.{@link MappingMetamodelImplementor#resolveParameterBindType(Object)}
|
||||
*/
|
||||
@Override @Deprecated(since = "6.2", forRemoval = true)
|
||||
<T> BindableType<? extends T> resolveParameterBindType(T bindValue);
|
||||
<T> BindableType<? super T> resolveParameterBindType(T bindValue);
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getMappingMetamodel()}.{@link MappingMetamodelImplementor#resolveParameterBindType(Class)}
|
||||
|
|
|
@ -9,6 +9,10 @@ package org.hibernate.internal;
|
|||
import org.hibernate.proxy.LazyInitializer;
|
||||
import org.hibernate.query.BindableType;
|
||||
import org.hibernate.query.spi.QueryParameterBindingTypeResolver;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.descriptor.java.EnumJavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.internal.BasicTypeImpl;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
@ -32,32 +36,52 @@ public abstract class QueryParameterBindingTypeResolverImpl implements QueryPara
|
|||
return getMappingMetamodel().resolveQueryParameterType( javaType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BindableType<? extends T> resolveParameterBindType(T bindValue) {
|
||||
@Override @SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public <T> BindableType<? super T> resolveParameterBindType(T bindValue) {
|
||||
if ( bindValue == null ) {
|
||||
// we can't guess
|
||||
return null;
|
||||
}
|
||||
|
||||
final LazyInitializer lazyInitializer = extractLazyInitializer( bindValue );
|
||||
final Class<?> clazz = lazyInitializer != null ? lazyInitializer.getPersistentClass() : bindValue.getClass();
|
||||
final Class<T> clazz = unproxiedClass( bindValue );
|
||||
|
||||
// Resolve superclass bindable type if necessary, as we don't register types for e.g. Inet4Address
|
||||
Class<?> c = clazz;
|
||||
Class<? super T> c = clazz;
|
||||
do {
|
||||
final BindableType<?> type = resolveParameterBindType( c );
|
||||
final BindableType<? super T> type = resolveParameterBindType( c );
|
||||
if ( type != null ) {
|
||||
//noinspection unchecked
|
||||
return (BindableType<? extends T>) type;
|
||||
return type;
|
||||
}
|
||||
c = c.getSuperclass();
|
||||
}
|
||||
while ( c != Object.class );
|
||||
if ( !clazz.isEnum() && Serializable.class.isAssignableFrom( clazz ) ) {
|
||||
//noinspection unchecked
|
||||
return (BindableType<? extends T>) resolveParameterBindType( Serializable.class );
|
||||
|
||||
if ( clazz.isEnum() ) {
|
||||
return null;//createEnumType( (Class) clazz );
|
||||
}
|
||||
return null;
|
||||
else if ( Serializable.class.isAssignableFrom( clazz ) ) {
|
||||
return (BindableType<? super T>) resolveParameterBindType( Serializable.class );
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private <E extends Enum<E>> BasicType<E> createEnumType(Class<E> enumClass) {
|
||||
final EnumJavaType<E> enumJavaType = new EnumJavaType<>( enumClass );
|
||||
final JdbcType jdbcType =
|
||||
// we don't know whether to map the enum as ORDINAL or STRING,
|
||||
// so just accept the default from the TypeConfiguration, which
|
||||
// is usually ORDINAL (the default according to JPA)
|
||||
enumJavaType.getRecommendedJdbcType( getTypeConfiguration().getCurrentBaseSqlTypeIndicators() );
|
||||
return new BasicTypeImpl<>( enumJavaType, jdbcType );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> Class<T> unproxiedClass(T bindValue) {
|
||||
final LazyInitializer lazyInitializer = extractLazyInitializer( bindValue );
|
||||
final Class<?> result = lazyInitializer != null ? lazyInitializer.getPersistentClass() : bindValue.getClass();
|
||||
return (Class<T>) result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -832,23 +832,19 @@ public class MappingMetamodelImpl extends QueryParameterBindingTypeResolverImpl
|
|||
final JavaTypeRegistry javaTypeRegistry = getTypeConfiguration().getJavaTypeRegistry();
|
||||
final JavaType<T> javaType = javaTypeRegistry.findDescriptor( javaClass );
|
||||
if ( javaType != null ) {
|
||||
final JdbcType recommendedJdbcType = javaType.getRecommendedJdbcType( getTypeConfiguration().getCurrentBaseSqlTypeIndicators() );
|
||||
final JdbcType recommendedJdbcType =
|
||||
javaType.getRecommendedJdbcType( getTypeConfiguration().getCurrentBaseSqlTypeIndicators() );
|
||||
if ( recommendedJdbcType != null ) {
|
||||
return getTypeConfiguration().getBasicTypeRegistry().resolve(
|
||||
javaType,
|
||||
recommendedJdbcType
|
||||
);
|
||||
return getTypeConfiguration().getBasicTypeRegistry().resolve( javaType, recommendedJdbcType );
|
||||
}
|
||||
}
|
||||
|
||||
if ( javaClass.isArray() && javaTypeRegistry.findDescriptor( javaClass.getComponentType() ) != null ) {
|
||||
final JavaType<T> resolvedJavaType = javaTypeRegistry.resolveDescriptor( javaClass );
|
||||
final JdbcType recommendedJdbcType = resolvedJavaType.getRecommendedJdbcType( getTypeConfiguration().getCurrentBaseSqlTypeIndicators() );
|
||||
final JdbcType recommendedJdbcType =
|
||||
resolvedJavaType.getRecommendedJdbcType( getTypeConfiguration().getCurrentBaseSqlTypeIndicators() );
|
||||
if ( recommendedJdbcType != null ) {
|
||||
return getTypeConfiguration().getBasicTypeRegistry().resolve(
|
||||
resolvedJavaType,
|
||||
recommendedJdbcType
|
||||
);
|
||||
return getTypeConfiguration().getBasicTypeRegistry().resolve( resolvedJavaType, recommendedJdbcType );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.hibernate.query.hql.spi.SqmCreationState;
|
|||
import org.hibernate.query.sqm.NodeBuilder;
|
||||
import org.hibernate.query.sqm.SqmExpressible;
|
||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||
import org.hibernate.query.sqm.spi.SqmCreationContext;
|
||||
import org.hibernate.query.sqm.tree.SqmCopyContext;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
||||
|
@ -32,6 +33,7 @@ import org.hibernate.type.descriptor.java.EnumJavaType;
|
|||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
||||
import jakarta.persistence.criteria.Expression;
|
||||
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -65,22 +67,24 @@ public class FullyQualifiedReflectivePathTerminal
|
|||
@SuppressWarnings("unchecked")
|
||||
private Function<SemanticQueryWalker, ?> resolveTerminalSemantic() {
|
||||
return semanticQueryWalker -> {
|
||||
final ClassLoaderService cls = creationState.getCreationContext().getServiceRegistry().getService( ClassLoaderService.class );
|
||||
final SqmCreationContext creationContext = creationState.getCreationContext();
|
||||
final ClassLoaderService cls =
|
||||
creationContext.getServiceRegistry().requireService( ClassLoaderService.class );
|
||||
final String fullPath = getFullPath();
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// See if it is an entity-type literal
|
||||
|
||||
final EntityDomainType<?> entityDescriptor = creationState.getCreationContext().getJpaMetamodel().entity( fullPath );
|
||||
final EntityDomainType<?> entityDescriptor = creationContext.getJpaMetamodel().entity( fullPath );
|
||||
if ( entityDescriptor != null ) {
|
||||
return new SqmLiteralEntityType( entityDescriptor, creationState.getCreationContext().getNodeBuilder() );
|
||||
return new SqmLiteralEntityType<>( entityDescriptor, creationContext.getNodeBuilder() );
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// See if it is a Class FQN
|
||||
|
||||
try {
|
||||
final Class namedClass = cls.classForName( fullPath );
|
||||
final Class<?> namedClass = cls.classForName( fullPath );
|
||||
if ( namedClass != null ) {
|
||||
return semanticQueryWalker.visitFullyQualifiedClass( namedClass );
|
||||
}
|
||||
|
@ -88,46 +92,47 @@ public class FullyQualifiedReflectivePathTerminal
|
|||
catch (ClassLoadingException ignore) {
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Check the parent path as a Class FQN, meaning the terminal is a field or
|
||||
// enum-value
|
||||
|
||||
final String parentFullPath = getParent().getFullPath();
|
||||
try {
|
||||
final Class namedClass = cls.classForName( parentFullPath );
|
||||
final Class<?> namedClass = cls.classForName( parentFullPath );
|
||||
if ( namedClass != null ) {
|
||||
if ( namedClass.isEnum() ) {
|
||||
return new SqmEnumLiteral(
|
||||
Enum.valueOf( namedClass, getLocalName() ),
|
||||
(EnumJavaType) creationState.getCreationContext().getTypeConfiguration().getJavaTypeRegistry().resolveDescriptor(
|
||||
namedClass,
|
||||
() -> new EnumJavaType( namedClass )
|
||||
),
|
||||
getLocalName(),
|
||||
nodeBuilder()
|
||||
);
|
||||
}
|
||||
else {
|
||||
final Field field = namedClass.getField( getLocalName() );
|
||||
return new SqmFieldLiteral(
|
||||
field,
|
||||
creationState.getCreationContext().getTypeConfiguration().getJavaTypeRegistry().resolveDescriptor(
|
||||
namedClass,
|
||||
() -> new EnumJavaType( namedClass )
|
||||
),
|
||||
nodeBuilder()
|
||||
);
|
||||
}
|
||||
return createEnumOrFieldLiteral( namedClass );
|
||||
}
|
||||
}
|
||||
catch (ClassLoadingException | NoSuchFieldException ignore) {
|
||||
}
|
||||
|
||||
throw new HqlInterpretationException( "Unsure how to handle semantic path terminal - " + fullPath );
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private SqmExpression createEnumOrFieldLiteral(Class namedClass) throws NoSuchFieldException {
|
||||
if ( namedClass.isEnum() ) {
|
||||
return new SqmEnumLiteral(
|
||||
Enum.valueOf( namedClass, getLocalName() ),
|
||||
(EnumJavaType) javaTypeRegistry()
|
||||
.resolveDescriptor( namedClass, () -> new EnumJavaType( namedClass ) ),
|
||||
getLocalName(),
|
||||
nodeBuilder()
|
||||
);
|
||||
}
|
||||
else {
|
||||
return new SqmFieldLiteral(
|
||||
namedClass.getField( getLocalName() ),
|
||||
javaTypeRegistry()
|
||||
.resolveDescriptor( namedClass, () -> new EnumJavaType( namedClass ) ),
|
||||
nodeBuilder()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private JavaTypeRegistry javaTypeRegistry() {
|
||||
return creationState.getCreationContext().getTypeConfiguration().getJavaTypeRegistry();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -3094,7 +3094,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
final int size = ctx.simpleCaseWhen().size();
|
||||
final SqmCaseSimple caseExpression = new SqmCaseSimple<>(
|
||||
(SqmExpression<?>) ctx.expressionOrPredicate().accept( this ),
|
||||
null,
|
||||
size,
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
|
@ -3118,11 +3117,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
@Override @SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public SqmCaseSearched<?> visitSearchedCaseList(HqlParser.SearchedCaseListContext ctx) {
|
||||
final int size = ctx.searchedCaseWhen().size();
|
||||
final SqmCaseSearched caseExpression = new SqmCaseSearched<>(
|
||||
null,
|
||||
size,
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
final SqmCaseSearched caseExpression = new SqmCaseSearched<>( size, creationContext.getNodeBuilder() );
|
||||
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
final HqlParser.SearchedCaseWhenContext searchedCaseWhenContext = ctx.searchedCaseWhen( i );
|
||||
|
@ -3697,22 +3692,23 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
final String originalText = text;
|
||||
text = text.substring( 2 );
|
||||
try {
|
||||
final Number value;
|
||||
final BasicDomainType<? extends Number> type;
|
||||
if ( text.endsWith( "l" ) || text.endsWith( "L" ) ) {
|
||||
text = text.substring( 0, text.length() - 1 );
|
||||
value = Long.parseUnsignedLong( text, 16 );
|
||||
type = resolveExpressibleTypeBasic( Long.class );
|
||||
final long value = Long.parseUnsignedLong( text, 16 );
|
||||
return new SqmLiteral<>(
|
||||
value,
|
||||
resolveExpressibleTypeBasic( Long.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
else {
|
||||
value = Integer.parseUnsignedInt( text, 16 );
|
||||
type = resolveExpressibleTypeBasic( Integer.class );
|
||||
final int value = Integer.parseUnsignedInt( text, 16 );
|
||||
return new SqmLiteral<>(
|
||||
value,
|
||||
resolveExpressibleTypeBasic( Integer.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
return new SqmLiteral<>(
|
||||
value,
|
||||
type,
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new LiteralNumberFormatException(
|
||||
|
@ -4113,7 +4109,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
// The SQL standard says the default is three periods `...`
|
||||
fillerExpression = new SqmLiteral<>(
|
||||
"...",
|
||||
secondArgument.getNodeType(),
|
||||
resolveExpressibleTypeBasic( String.class ),
|
||||
secondArgument.nodeBuilder()
|
||||
);
|
||||
}
|
||||
|
@ -4130,47 +4126,31 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
|
||||
@Override
|
||||
public List<SqmTypedNode<?>> visitGenericFunctionArguments(HqlParser.GenericFunctionArgumentsContext ctx) {
|
||||
final int size = ctx.getChildCount();
|
||||
final int lastIndex = size - 1;
|
||||
// Shift 1 bit instead of division by 2
|
||||
final int estimateArgumentCount = size >> 1;
|
||||
final List<SqmTypedNode<?>> arguments = new ArrayList<>( estimateArgumentCount );
|
||||
int i = 0;
|
||||
|
||||
boolean distinct = false;
|
||||
final ParseTree firstChild = ctx.getChild( 0 );
|
||||
if ( firstChild instanceof HqlParser.DatetimeFieldContext ) {
|
||||
arguments.add( toDurationUnit( (SqmExtractUnit<?>) firstChild.accept( this ) ) );
|
||||
i += 2;
|
||||
final List<HqlParser.ExpressionOrPredicateContext> argumentContexts = ctx.expressionOrPredicate();
|
||||
int count = argumentContexts.size();
|
||||
final List<SqmTypedNode<?>> arguments = new ArrayList<>( count+1 );
|
||||
final HqlParser.DatetimeFieldContext datetimeFieldContext = ctx.datetimeField();
|
||||
if ( datetimeFieldContext != null ) {
|
||||
arguments.add( toDurationUnit( (SqmExtractUnit<?>) datetimeFieldContext.accept( this ) ) );
|
||||
}
|
||||
else if ( firstChild instanceof TerminalNode ) {
|
||||
distinct = true;
|
||||
i++;
|
||||
for ( int i = 0; i < count-1; i++ ) {
|
||||
final HqlParser.ExpressionOrPredicateContext argumentContext = argumentContexts.get(i);
|
||||
arguments.add( (SqmTypedNode<?>) argumentContext.accept( this ) );
|
||||
}
|
||||
// we handle the last argument differently...
|
||||
final HqlParser.ExpressionOrPredicateContext argumentContext = argumentContexts.get( count-1 );
|
||||
arguments.add( visitFinalFunctionArgument( argumentContext ) );
|
||||
|
||||
for ( ; i < size; i += 2 ) {
|
||||
// we handle the final argument differently...
|
||||
if ( i == lastIndex ) {
|
||||
arguments.add( visitFinalFunctionArgument( ctx.getChild( i ) ) );
|
||||
}
|
||||
else {
|
||||
arguments.add( (SqmTypedNode<?>) ctx.getChild( i ).accept( this ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( distinct ) {
|
||||
if ( ctx.DISTINCT() != null ) {
|
||||
final NodeBuilder nodeBuilder = getCreationContext().getNodeBuilder();
|
||||
if ( arguments.size() == 1 ) {
|
||||
arguments.set( 0, new SqmDistinct<>( (SqmExpression<?>) arguments.get( 0 ), nodeBuilder ) );
|
||||
}
|
||||
else {
|
||||
final List<SqmTypedNode<?>> newArguments = new ArrayList<>( 1 );
|
||||
//noinspection unchecked
|
||||
newArguments.add(
|
||||
new SqmDistinct<>(
|
||||
new SqmTuple<>( (List<SqmExpression<?>>) (List<?>) arguments, nodeBuilder ), nodeBuilder
|
||||
)
|
||||
);
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<SqmExpression<?>> expressions = (List<SqmExpression<?>>) (List<?>) arguments;
|
||||
newArguments.add( new SqmDistinct<>( new SqmTuple<>( expressions, nodeBuilder ), nodeBuilder ) );
|
||||
return newArguments;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ 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.query.sqm.tree.select.SqmSelectStatement;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
|
|
@ -27,7 +27,7 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
import jakarta.persistence.TemporalType;
|
||||
|
||||
/**
|
||||
* The standard Hibernate QueryParameterBinding implementation
|
||||
* The standard implementation of {@link QueryParameterBinding}.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -38,11 +38,11 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
|
|||
private boolean isBound;
|
||||
private boolean isMultiValued;
|
||||
|
||||
private BindableType<? extends T> bindType;
|
||||
private BindableType<? super T> bindType;
|
||||
private MappingModelExpressible<T> type;
|
||||
private TemporalType explicitTemporalPrecision;
|
||||
|
||||
private T bindValue;
|
||||
private Object bindValue;
|
||||
private Collection<? extends T> bindValues;
|
||||
|
||||
/**
|
||||
|
@ -67,7 +67,7 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
|
|||
}
|
||||
|
||||
@Override
|
||||
public BindableType<? extends T> getBindType() {
|
||||
public BindableType<? super T> getBindType() {
|
||||
return bindType;
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,8 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
|
|||
throw new IllegalStateException( "Binding is multi-valued; illegal call to #getBindValue" );
|
||||
}
|
||||
|
||||
return bindValue;
|
||||
//TODO: I believe this cast is unsound due to coercion
|
||||
return (T) bindValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -105,13 +106,17 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
|
|||
return;
|
||||
}
|
||||
|
||||
final Object coerced;
|
||||
if ( ! sessionFactory.getSessionFactoryOptions().getJpaCompliance().isLoadByIdComplianceEnabled() ) {
|
||||
try {
|
||||
if ( bindType != null ) {
|
||||
value = coerce( value, bindType );
|
||||
coerced = coerce( value, bindType );
|
||||
}
|
||||
else if ( queryParameter.getHibernateType() != null ) {
|
||||
value = coerce( value, queryParameter.getHibernateType() );
|
||||
coerced = coerce( value, queryParameter.getHibernateType() );
|
||||
}
|
||||
else {
|
||||
coerced = value;
|
||||
}
|
||||
}
|
||||
catch (CoercionException ce) {
|
||||
|
@ -125,57 +130,64 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
validate( value );
|
||||
|
||||
if ( resolveJdbcTypeIfNecessary && bindType == null && value == null ) {
|
||||
bindType = getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( "null" );
|
||||
else {
|
||||
coerced = value;
|
||||
}
|
||||
|
||||
validate( coerced );
|
||||
|
||||
if ( value == null ) {
|
||||
// needed when setting a null value to the parameter of a native SQL query
|
||||
// TODO: this does not look like a very disciplined way to handle this
|
||||
bindNull( resolveJdbcTypeIfNecessary );
|
||||
}
|
||||
else {
|
||||
bindValue( coerced );
|
||||
}
|
||||
bindValue( value );
|
||||
}
|
||||
|
||||
private T coerce(T value, BindableType<? extends T> parameterType) {
|
||||
private void bindNull(boolean resolveJdbcTypeIfNecessary) {
|
||||
isBound = true;
|
||||
bindValue = null;
|
||||
if ( resolveJdbcTypeIfNecessary && bindType == null ) {
|
||||
bindType = getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( "null" );
|
||||
}
|
||||
}
|
||||
|
||||
private Object coerce(T value, BindableType<? super T> parameterType) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final SqmExpressible<? extends T> sqmExpressible = parameterType.resolveExpressible( sessionFactory );
|
||||
final SqmExpressible<? super T> sqmExpressible = parameterType.resolveExpressible( sessionFactory );
|
||||
assert sqmExpressible != null;
|
||||
return sqmExpressible.getExpressibleJavaType().coerce( value, this );
|
||||
}
|
||||
|
||||
private boolean handleAsMultiValue(T value, BindableType<T> bindableType) {
|
||||
if ( ! queryParameter.allowsMultiValuedBinding() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( value == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( value instanceof Collection
|
||||
&& ( bindableType != null && !bindableType.getBindableJavaType().isInstance( value )
|
||||
|| ( bindableType == null && !isRegisteredAsBasicType( value.getClass() ) ) ) ) {
|
||||
if ( queryParameter.allowsMultiValuedBinding()
|
||||
&& value instanceof Collection
|
||||
&& ( bindableType == null
|
||||
? !isRegisteredAsBasicType( value.getClass() )
|
||||
: !bindableType.getBindableJavaType().isInstance( value ) ) ) {
|
||||
//noinspection unchecked
|
||||
setBindValues( (Collection<T>) value );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRegisteredAsBasicType(Class<?> valueClass) {
|
||||
return getTypeConfiguration().getBasicTypeForJavaType( valueClass ) != null;
|
||||
}
|
||||
|
||||
private void bindValue(T value) {
|
||||
this.isBound = true;
|
||||
this.bindValue = value;
|
||||
|
||||
if ( bindType == null ) {
|
||||
if ( value != null ) {
|
||||
this.bindType = sessionFactory.getMappingMetamodel().resolveParameterBindType( value );
|
||||
}
|
||||
private void bindValue(Object value) {
|
||||
isBound = true;
|
||||
bindValue = value;
|
||||
if ( bindType == null && value != null ) {
|
||||
bindType = sessionFactory.getMappingMetamodel().resolveParameterBindType( value );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,19 +198,23 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
|
|||
}
|
||||
|
||||
if ( clarifiedType != null ) {
|
||||
this.bindType = clarifiedType;
|
||||
bindType = clarifiedType;
|
||||
}
|
||||
|
||||
final Object coerced;
|
||||
if ( bindType != null ) {
|
||||
value = coerce( value, bindType );
|
||||
coerced = coerce( value, bindType );
|
||||
}
|
||||
else if ( queryParameter.getHibernateType() != null ) {
|
||||
value = coerce( value, queryParameter.getHibernateType() );
|
||||
coerced = coerce( value, queryParameter.getHibernateType() );
|
||||
}
|
||||
else {
|
||||
coerced = value;
|
||||
}
|
||||
|
||||
validate( value, clarifiedType );
|
||||
validate( coerced, clarifiedType );
|
||||
|
||||
bindValue( value );
|
||||
bindValue( coerced );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -211,10 +227,11 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
|
|||
bindType = queryParameter.getHibernateType();
|
||||
}
|
||||
|
||||
final Object coerced;
|
||||
if ( ! sessionFactory.getSessionFactoryOptions().getJpaCompliance().isLoadByIdComplianceEnabled() ) {
|
||||
if ( bindType != null ) {
|
||||
try {
|
||||
value = coerce( value, bindType );
|
||||
coerced = coerce( value, bindType );
|
||||
}
|
||||
catch (CoercionException ex) {
|
||||
throw new IllegalArgumentException(
|
||||
|
@ -229,13 +246,19 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
|
|||
}
|
||||
}
|
||||
else if ( queryParameter.getHibernateType() != null ) {
|
||||
value = coerce( value, queryParameter.getHibernateType() );
|
||||
coerced = coerce( value, queryParameter.getHibernateType() );
|
||||
}
|
||||
else {
|
||||
coerced = value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
coerced = value;
|
||||
}
|
||||
|
||||
validate( value, temporalTypePrecision );
|
||||
validate( coerced, temporalTypePrecision );
|
||||
|
||||
bindValue( value );
|
||||
bindValue( coerced );
|
||||
setExplicitTemporalPrecision( temporalTypePrecision );
|
||||
}
|
||||
|
||||
|
@ -289,22 +312,16 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
|
|||
setExplicitTemporalPrecision( temporalTypePrecision );
|
||||
}
|
||||
|
||||
private void setExplicitTemporalPrecision(TemporalType temporalTypePrecision) {
|
||||
private void setExplicitTemporalPrecision(TemporalType precision) {
|
||||
explicitTemporalPrecision = precision;
|
||||
if ( bindType == null || JavaTypeHelper.isTemporal( determineJavaType( bindType ) ) ) {
|
||||
this.bindType = BindingTypeHelper.INSTANCE.resolveTemporalPrecision(
|
||||
temporalTypePrecision,
|
||||
bindType,
|
||||
sessionFactory
|
||||
);
|
||||
bindType = BindingTypeHelper.INSTANCE.resolveTemporalPrecision( precision, bindType, sessionFactory );
|
||||
}
|
||||
|
||||
this.explicitTemporalPrecision = temporalTypePrecision;
|
||||
}
|
||||
|
||||
private JavaType<? extends T> determineJavaType(BindableType<? extends T> bindType) {
|
||||
final SqmExpressible<? extends T> sqmExpressible = bindType.resolveExpressible( sessionFactory );
|
||||
private JavaType<? super T> determineJavaType(BindableType<? super T> bindType) {
|
||||
final SqmExpressible<? super T> sqmExpressible = bindType.resolveExpressible( sessionFactory );
|
||||
assert sqmExpressible != null;
|
||||
|
||||
return sqmExpressible.getExpressibleJavaType();
|
||||
}
|
||||
|
||||
|
@ -320,14 +337,14 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
|
|||
if ( bindType == null || bindType.getBindableJavaType() == Object.class || type instanceof ModelPart ) {
|
||||
if ( type instanceof BindableType<?> ) {
|
||||
final boolean changed = bindType != null && type != bindType;
|
||||
this.bindType = (BindableType<T>) type;
|
||||
bindType = (BindableType<T>) type;
|
||||
return changed;
|
||||
}
|
||||
else if ( type instanceof BasicValuedMapping ) {
|
||||
final JdbcMapping jdbcMapping = ( (BasicValuedMapping) type ).getJdbcMapping();
|
||||
if ( jdbcMapping instanceof BindableType<?> ) {
|
||||
final boolean changed = bindType != null && jdbcMapping != bindType;
|
||||
this.bindType = (BindableType<T>) jdbcMapping;
|
||||
bindType = (BindableType<T>) jdbcMapping;
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
|
@ -335,15 +352,15 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
|
|||
return false;
|
||||
}
|
||||
|
||||
private void validate(T value) {
|
||||
private void validate(Object value) {
|
||||
QueryParameterBindingValidator.INSTANCE.validate( getBindType(), value, sessionFactory );
|
||||
}
|
||||
|
||||
private void validate(T value, BindableType<?> clarifiedType) {
|
||||
private void validate(Object value, BindableType<?> clarifiedType) {
|
||||
QueryParameterBindingValidator.INSTANCE.validate( clarifiedType, value, sessionFactory );
|
||||
}
|
||||
|
||||
private void validate(T value, TemporalType clarifiedTemporalType) {
|
||||
private void validate(Object value, TemporalType clarifiedTemporalType) {
|
||||
QueryParameterBindingValidator.INSTANCE.validate( getBindType(), value, clarifiedTemporalType, sessionFactory );
|
||||
}
|
||||
|
||||
|
|
|
@ -237,7 +237,7 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
if ( binding.isMultiValued() ) {
|
||||
final Iterator<?> iterator = binding.getBindValues().iterator();
|
||||
Object firstNonNullBindValue = null;
|
||||
if ( iterator.hasNext() && firstNonNullBindValue == null ) {
|
||||
if ( iterator.hasNext() ) {
|
||||
firstNonNullBindValue = iterator.next();
|
||||
}
|
||||
if ( firstNonNullBindValue != null ) {
|
||||
|
|
|
@ -17,7 +17,7 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
/**
|
||||
/**
|
||||
* The value/type binding information for a particular query parameter. Supports
|
||||
* both single-valued and multi-valued binds
|
||||
* both single-valued and multivalued binds
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -30,7 +30,7 @@ public interface QueryParameterBinding<T> {
|
|||
boolean isBound();
|
||||
|
||||
/**
|
||||
* Is the binding multi-valued?
|
||||
* Is the binding multivalued?
|
||||
*/
|
||||
boolean isMultiValued();
|
||||
|
||||
|
@ -39,7 +39,7 @@ public interface QueryParameterBinding<T> {
|
|||
*
|
||||
* @return The currently associated Type
|
||||
*/
|
||||
BindableType<? extends T> getBindType();
|
||||
BindableType<? super T> getBindType();
|
||||
|
||||
/**
|
||||
* If the parameter represents a temporal type, return the explicitly
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.query.spi;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.metamodel.MappingMetamodel;
|
||||
import org.hibernate.query.BindableType;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
@ -20,8 +21,9 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
public interface QueryParameterBindingTypeResolver {
|
||||
<T> BindableType<? extends T> resolveParameterBindType(T bindValue);
|
||||
<T> BindableType<? super T> resolveParameterBindType(T bindValue);
|
||||
<T> BindableType<T> resolveParameterBindType(Class<T> clazz);
|
||||
TypeConfiguration getTypeConfiguration();
|
||||
MappingMetamodel getMappingMetamodel();
|
||||
|
|
|
@ -118,12 +118,12 @@ public interface SqmPathSource<J> extends SqmExpressible<J>, Bindable<J>, SqmExp
|
|||
|
||||
@Override
|
||||
default SqmExpressible<J> getExpressible() {
|
||||
return (SqmExpressible<J>) getSqmPathType();
|
||||
return getSqmPathType();
|
||||
}
|
||||
|
||||
@Override
|
||||
default DomainType<J> getSqmType() {
|
||||
return (DomainType<J>) getSqmPathType();
|
||||
return getSqmPathType();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,10 +9,9 @@ package org.hibernate.query.sqm.internal;
|
|||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
|
||||
/**
|
||||
* todo (6.0) : how is this different from {@link org.hibernate.query.sqm.tree.jpa.ParameterCollector}?
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
// todo (6.0) : how is this different from org.hibernate.query.sqm.tree.jpa.ParameterCollector?
|
||||
public interface ParameterCollector {
|
||||
void addParameter(SqmParameter<?> parameter);
|
||||
}
|
||||
|
|
|
@ -243,8 +243,9 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
public BasicType<Boolean> getBooleanType() {
|
||||
final BasicType<Boolean> booleanType = this.booleanType;
|
||||
if ( booleanType == null ) {
|
||||
return this.booleanType = getTypeConfiguration().getBasicTypeRegistry()
|
||||
.resolve( StandardBasicTypes.BOOLEAN );
|
||||
return this.booleanType =
|
||||
getTypeConfiguration().getBasicTypeRegistry()
|
||||
.resolve( StandardBasicTypes.BOOLEAN );
|
||||
}
|
||||
return booleanType;
|
||||
}
|
||||
|
@ -253,7 +254,9 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
public BasicType<Integer> getIntegerType() {
|
||||
final BasicType<Integer> integerType = this.integerType;
|
||||
if ( integerType == null ) {
|
||||
return this.integerType = getTypeConfiguration().getBasicTypeForJavaType( Integer.class );
|
||||
return this.integerType =
|
||||
getTypeConfiguration().getBasicTypeRegistry()
|
||||
.resolve( StandardBasicTypes.INTEGER );
|
||||
}
|
||||
return integerType;
|
||||
}
|
||||
|
@ -262,7 +265,9 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
public BasicType<Character> getCharacterType() {
|
||||
final BasicType<Character> characterType = this.characterType;
|
||||
if ( characterType == null ) {
|
||||
return this.characterType = getTypeConfiguration().getBasicTypeForJavaType( Character.class );
|
||||
return this.characterType =
|
||||
getTypeConfiguration().getBasicTypeRegistry()
|
||||
.resolve( StandardBasicTypes.CHARACTER );
|
||||
}
|
||||
return characterType;
|
||||
}
|
||||
|
@ -297,7 +302,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
sessionFactory.get().getQueryEngine().getHqlTranslator()
|
||||
.translate( hql, resultClass );
|
||||
if ( statement instanceof SqmSelectStatement ) {
|
||||
return new SqmSelectStatement<>((SqmSelectStatement<T>) statement);
|
||||
return new SqmSelectStatement<>( (SqmSelectStatement<T>) statement );
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Not a 'select' statement");
|
||||
|
@ -362,13 +367,13 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
@SuppressWarnings("unchecked")
|
||||
private <T> JpaCriteriaQuery<T> setOperation(
|
||||
SetOperator operator,
|
||||
CriteriaQuery<? extends T> query1,
|
||||
CriteriaQuery<? extends T> criteriaQuery,
|
||||
CriteriaQuery<?>... queries) {
|
||||
final Class<T> resultType = (Class<T>) query1.getResultType();
|
||||
final Class<T> resultType = (Class<T>) criteriaQuery.getResultType();
|
||||
final List<SqmQueryPart<T>> queryParts = new ArrayList<>( queries.length + 1 );
|
||||
final Map<String, SqmCteStatement<?>> cteStatements = new LinkedHashMap<>();
|
||||
final SqmSelectStatement<T> selectStatement1 = (SqmSelectStatement<T>) query1;
|
||||
collectQueryPartsAndCtes( selectStatement1, queryParts, cteStatements );
|
||||
final SqmSelectStatement<T> selectStatement = (SqmSelectStatement<T>) criteriaQuery;
|
||||
collectQueryPartsAndCtes( selectStatement, queryParts, cteStatements );
|
||||
for ( CriteriaQuery<?> query : queries ) {
|
||||
if ( query.getResultType() != resultType ) {
|
||||
throw new IllegalArgumentException( "Result type of all operands must match" );
|
||||
|
@ -379,7 +384,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
new SqmQueryGroup<>( this, operator, queryParts ),
|
||||
resultType,
|
||||
cteStatements,
|
||||
selectStatement1.getQuerySource(),
|
||||
selectStatement.getQuerySource(),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
@ -387,13 +392,13 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
@SuppressWarnings("unchecked")
|
||||
private <T> JpaSubQuery<T> setOperation(
|
||||
SetOperator operator,
|
||||
Subquery<? extends T> query1,
|
||||
Subquery<? extends T> subquery,
|
||||
Subquery<?>... queries) {
|
||||
final Class<T> resultType = (Class<T>) query1.getResultType();
|
||||
final SqmQuery<T> parent = (SqmQuery<T>) query1.getParent();
|
||||
final Class<T> resultType = (Class<T>) subquery.getResultType();
|
||||
final SqmQuery<T> parent = (SqmQuery<T>) subquery.getParent();
|
||||
final List<SqmQueryPart<T>> queryParts = new ArrayList<>( queries.length + 1 );
|
||||
final Map<String, SqmCteStatement<?>> cteStatements = new LinkedHashMap<>();
|
||||
collectQueryPartsAndCtes( (SqmSelectQuery<T>) query1, queryParts, cteStatements );
|
||||
collectQueryPartsAndCtes( (SqmSelectQuery<T>) subquery, queryParts, cteStatements );
|
||||
for ( Subquery<?> query : queries ) {
|
||||
if ( query.getResultType() != resultType ) {
|
||||
throw new IllegalArgumentException( "Result type of all operands must match" );
|
||||
|
@ -440,11 +445,9 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
|
||||
@Override
|
||||
public SqmPredicate wrap(Expression<Boolean> expression) {
|
||||
if ( expression instanceof SqmPredicate ) {
|
||||
return (SqmPredicate) expression;
|
||||
}
|
||||
|
||||
return new SqmBooleanExpressionPredicate( (SqmExpression<Boolean>) expression, this );
|
||||
return expression instanceof SqmPredicate
|
||||
? (SqmPredicate) expression
|
||||
: new SqmBooleanExpressionPredicate( (SqmExpression<Boolean>) expression, this );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -582,7 +585,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
@Override
|
||||
public JpaSearchOrder asc(JpaCteCriteriaAttribute x, boolean nullsFirst) {
|
||||
return new SqmSearchClauseSpecification(
|
||||
(SqmCteTableColumn) x,
|
||||
(SqmCteTableColumn) x,
|
||||
SortDirection.ASCENDING,
|
||||
nullsFirst ? NullPrecedence.FIRST : NullPrecedence.LAST
|
||||
);
|
||||
|
@ -619,20 +622,13 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
return tuple( tupleType, asList( expressions ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override @SuppressWarnings("unchecked")
|
||||
public <R> SqmTuple<R> tuple(Class<R> tupleType, List<? extends SqmExpression<?>> expressions) {
|
||||
final TypeConfiguration typeConfiguration = getTypeConfiguration();
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<SqmExpression<?>> sqmExpressions = (List<SqmExpression<?>>) expressions;
|
||||
final SqmExpressible<R> expressibleType;
|
||||
if ( tupleType == null || tupleType == Object[].class ) {
|
||||
//noinspection unchecked
|
||||
expressibleType = (DomainType<R>) typeConfiguration.resolveTupleType( sqmExpressions );
|
||||
}
|
||||
else {
|
||||
expressibleType = getDomainModel().embeddable( tupleType );
|
||||
}
|
||||
return tuple( expressibleType, sqmExpressions );
|
||||
final SqmExpressible<R> expressibleType =
|
||||
tupleType == null || tupleType == Object[].class
|
||||
? (DomainType<R>) getTypeConfiguration().resolveTupleType( expressions )
|
||||
: getDomainModel().embeddable( tupleType );
|
||||
return tuple( expressibleType, expressions );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -646,11 +642,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
//noinspection unchecked
|
||||
tupleType = (DomainType<R>) getTypeConfiguration().resolveTupleType( sqmExpressions );
|
||||
}
|
||||
return new SqmTuple<>(
|
||||
new ArrayList<>( sqmExpressions ),
|
||||
tupleType,
|
||||
this
|
||||
);
|
||||
return new SqmTuple<>( new ArrayList<>( sqmExpressions ), tupleType, this );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -673,12 +665,9 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
@Override
|
||||
public <Y> JpaCompoundSelection<Y> array(Class<Y> resultClass, List<? extends JpaSelection<?>> selections) {
|
||||
checkMultiselect( selections );
|
||||
final JavaType<Y> javaType = getTypeConfiguration().getJavaTypeRegistry().getDescriptor( resultClass );
|
||||
//noinspection unchecked
|
||||
return new SqmJpaCompoundSelection<>(
|
||||
(List<SqmSelectableNode<?>>) selections,
|
||||
getTypeConfiguration().getJavaTypeRegistry().getDescriptor( resultClass ),
|
||||
this
|
||||
);
|
||||
return new SqmJpaCompoundSelection<>( (List<SqmSelectableNode<?>>) selections, javaType, this );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -704,12 +693,9 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
}
|
||||
|
||||
for ( Selection<?> argument : arguments ) {
|
||||
final SqmSelectableNode<?> arg = (SqmSelectableNode<?>) argument;
|
||||
instantiation.addArgument(
|
||||
new SqmDynamicInstantiationArgument<>(
|
||||
(SqmSelectableNode<?>) argument,
|
||||
argument.getAlias(),
|
||||
this
|
||||
)
|
||||
new SqmDynamicInstantiationArgument<>( arg, argument.getAlias(), this )
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1135,18 +1121,14 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
return new SqmLiteralNull<>( this );
|
||||
}
|
||||
|
||||
SqmExpressible<T> expressible = resolveInferredType( value, typeInferenceSource, getTypeConfiguration() );
|
||||
final SqmExpressible<T> expressible = resolveInferredType( value, typeInferenceSource, getTypeConfiguration() );
|
||||
if ( expressible.getExpressibleJavaType().isInstance( value ) ) {
|
||||
return new SqmLiteral<>( value, expressible, this );
|
||||
}
|
||||
// Just like in HQL, we allow coercion of literal values to the inferred type
|
||||
T coercedValue = expressible.getExpressibleJavaType().coerce( value, this::getTypeConfiguration );
|
||||
if (expressible.getExpressibleJavaType().isInstance( coercedValue )) {
|
||||
return new SqmLiteral<>(
|
||||
coercedValue,
|
||||
expressible,
|
||||
this
|
||||
);
|
||||
final T coercedValue = expressible.getExpressibleJavaType().coerce( value, this::getTypeConfiguration );
|
||||
if ( expressible.getExpressibleJavaType().isInstance( coercedValue ) ) {
|
||||
return new SqmLiteral<>( coercedValue, expressible, this );
|
||||
}
|
||||
else {
|
||||
// ignore typeInferenceSource and fallback the value type
|
||||
|
@ -1188,13 +1170,12 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
}
|
||||
return new SqmLiteralNull<>( this );
|
||||
}
|
||||
|
||||
final BindableType<? extends T> valueParamType = getMappingMetamodel().resolveParameterBindType( value );
|
||||
final SqmExpressible<? extends T> sqmExpressible = valueParamType == null
|
||||
? null
|
||||
: valueParamType.resolveExpressible( getSessionFactory() );
|
||||
|
||||
return new SqmLiteral<>( value, sqmExpressible, this );
|
||||
else {
|
||||
final BindableType<? super T> valueParamType = getParameterBindType( value );
|
||||
final SqmExpressible<? super T> sqmExpressible =
|
||||
valueParamType == null ? null : valueParamType.resolveExpressible( getSessionFactory() );
|
||||
return new SqmLiteral<>( value, sqmExpressible, this );
|
||||
}
|
||||
}
|
||||
|
||||
private MappingMetamodelImplementor getMappingMetamodel() {
|
||||
|
@ -1233,12 +1214,15 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
// No basic types are registered for enum java types, we have to use an untyped null literal in this case
|
||||
return new SqmLiteralNull<>( this );
|
||||
}
|
||||
final BasicType<T> basicTypeForJavaType = getTypeConfiguration().getBasicTypeForJavaType( resultClass );
|
||||
// if there's no basic type, it might be an entity type
|
||||
final SqmExpressible<T> sqmExpressible = basicTypeForJavaType == null
|
||||
? getDomainModel().managedType( resultClass )
|
||||
: basicTypeForJavaType;
|
||||
return new SqmLiteralNull<>( sqmExpressible, this );
|
||||
else {
|
||||
final BasicType<T> basicTypeForJavaType = getTypeConfiguration().getBasicTypeForJavaType( resultClass );
|
||||
// if there's no basic type, it might be an entity type
|
||||
final SqmExpressible<T> sqmExpressible =
|
||||
basicTypeForJavaType == null
|
||||
? getDomainModel().managedType( resultClass )
|
||||
: basicTypeForJavaType;
|
||||
return new SqmLiteralNull<>( sqmExpressible, this );
|
||||
}
|
||||
}
|
||||
|
||||
class MultiValueParameterType<T> implements SqmExpressible<T> {
|
||||
|
@ -1587,10 +1571,18 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
|
||||
@Override
|
||||
public <T> SqmFunction<T> function(String name, Class<T> type, Expression<?>[] args) {
|
||||
SqmFunctionDescriptor functionTemplate = getFunctionDescriptor( name );
|
||||
final BasicType<T> resultType = getTypeConfiguration().standardBasicTypeForJavaType( type );
|
||||
return getFunctionTemplate( name, resultType ).generateSqmExpression(
|
||||
expressionList( args ),
|
||||
resultType,
|
||||
getQueryEngine()
|
||||
);
|
||||
}
|
||||
|
||||
private <T> SqmFunctionDescriptor getFunctionTemplate(String name, BasicType<T> resultType) {
|
||||
final SqmFunctionDescriptor functionTemplate = getFunctionDescriptor( name );
|
||||
if ( functionTemplate == null ) {
|
||||
functionTemplate = new NamedSqmFunctionDescriptor(
|
||||
return new NamedSqmFunctionDescriptor(
|
||||
name,
|
||||
true,
|
||||
null,
|
||||
|
@ -1598,12 +1590,9 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
null
|
||||
);
|
||||
}
|
||||
|
||||
return functionTemplate.generateSqmExpression(
|
||||
expressionList( args ),
|
||||
resultType,
|
||||
getQueryEngine()
|
||||
);
|
||||
else {
|
||||
return functionTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<SqmExpression<?>> expressionList(Expression<?>[] jpaExpressions) {
|
||||
|
@ -1659,97 +1648,69 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
* Creates an expression for the value with the given "type inference" information
|
||||
*/
|
||||
public <T> SqmExpression<T> value(T value, SqmExpression<? extends T> typeInferenceSource) {
|
||||
if ( value instanceof SqmExpression ) {
|
||||
return (SqmExpression<T>) value;
|
||||
}
|
||||
if ( inlineValue( value ) ) {
|
||||
return literal( value, typeInferenceSource );
|
||||
}
|
||||
|
||||
final BindableType<T> bindableType = resolveInferredParameterType(
|
||||
value,
|
||||
typeInferenceSource,
|
||||
getTypeConfiguration()
|
||||
);
|
||||
if ( bindableType == null || isInstance( bindableType, value ) ) {
|
||||
return new ValueBindJpaCriteriaParameter<>(
|
||||
bindableType,
|
||||
value,
|
||||
this
|
||||
);
|
||||
}
|
||||
final SqmExpressible<T> expressible = bindableType.resolveExpressible( getSessionFactory() );
|
||||
T coercedValue = expressible.getExpressibleJavaType().coerce( value, this::getTypeConfiguration );
|
||||
if ( isInstance( bindableType, coercedValue ) ) {
|
||||
return new ValueBindJpaCriteriaParameter<>(
|
||||
bindableType,
|
||||
coercedValue,
|
||||
this
|
||||
);
|
||||
}
|
||||
else {
|
||||
// ignore typeInferenceSource and fallback the value type
|
||||
return new ValueBindJpaCriteriaParameter<>(
|
||||
getMappingMetamodel().resolveParameterBindType( value ),
|
||||
value,
|
||||
this
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> boolean isInstance(BindableType<T> bindableType, T value) {
|
||||
if ( bindableType instanceof SqmExpressible<?> ) {
|
||||
return ( (SqmExpressible<T>) bindableType ).getExpressibleJavaType().isInstance( value );
|
||||
}
|
||||
if ( bindableType.getBindableJavaType().isInstance( value ) ) {
|
||||
return true;
|
||||
}
|
||||
return bindableType.resolveExpressible( getSessionFactory() )
|
||||
.getExpressibleJavaType()
|
||||
.isInstance( value );
|
||||
}
|
||||
|
||||
private static <T> BindableType<T> resolveInferredParameterType(
|
||||
T value,
|
||||
SqmExpression<? extends T> typeInferenceSource,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
if ( typeInferenceSource != null ) {
|
||||
if ( typeInferenceSource instanceof BindableType ) {
|
||||
//noinspection unchecked
|
||||
return (BindableType<T>) typeInferenceSource;
|
||||
}
|
||||
|
||||
if ( typeInferenceSource.getNodeType() != null ) {
|
||||
//noinspection unchecked
|
||||
return (BindableType<T>) typeInferenceSource.getNodeType();
|
||||
}
|
||||
}
|
||||
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
return (BasicType<T>) typeConfiguration.getBasicTypeForJavaType( value.getClass() );
|
||||
return inlineValue( value ) ? literal( value, typeInferenceSource ) : valueParameter( value, typeInferenceSource );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> SqmExpression<T> value(T value) {
|
||||
if ( value instanceof SqmExpression ) {
|
||||
return (SqmExpression<T>) value;
|
||||
}
|
||||
if ( inlineValue( value ) ) {
|
||||
return literal( value );
|
||||
return inlineValue( value ) ? literal( value ) : valueParameter( value );
|
||||
}
|
||||
|
||||
private <T> boolean isInstance(BindableType<T> bindableType, T value) {
|
||||
if ( bindableType instanceof SqmExpressible<?> ) {
|
||||
final SqmExpressible<?> expressible = (SqmExpressible<?>) bindableType;
|
||||
return expressible.getExpressibleJavaType().isInstance( value );
|
||||
}
|
||||
else {
|
||||
return new ValueBindJpaCriteriaParameter<>(
|
||||
getMappingMetamodel().resolveParameterBindType( value ),
|
||||
value,
|
||||
this
|
||||
);
|
||||
return bindableType.getBindableJavaType().isInstance( value )
|
||||
|| bindableType.resolveExpressible( getSessionFactory() ).getExpressibleJavaType().isInstance( value );
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> BindableType<T> resolveInferredParameterType(
|
||||
T value,
|
||||
SqmExpression<? extends T> typeInferenceSource,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
|
||||
if ( typeInferenceSource != null ) {
|
||||
if ( typeInferenceSource instanceof BindableType ) {
|
||||
return (BindableType<T>) typeInferenceSource;
|
||||
}
|
||||
if ( typeInferenceSource.getNodeType() != null ) {
|
||||
return (BindableType<T>) typeInferenceSource.getNodeType();
|
||||
}
|
||||
}
|
||||
|
||||
return value == null ? null : (BasicType<T>) typeConfiguration.getBasicTypeForJavaType( value.getClass() );
|
||||
}
|
||||
|
||||
private <T> ValueBindJpaCriteriaParameter<T> valueParameter(T value, SqmExpression<? extends T> typeInferenceSource) {
|
||||
final BindableType<T> bindableType =
|
||||
resolveInferredParameterType( value, typeInferenceSource, getTypeConfiguration() );
|
||||
if ( bindableType == null || isInstance( bindableType, value) ) {
|
||||
return new ValueBindJpaCriteriaParameter<>( bindableType, value, this );
|
||||
}
|
||||
final T coercedValue =
|
||||
bindableType.resolveExpressible( getSessionFactory() ).getExpressibleJavaType()
|
||||
.coerce(value, this::getTypeConfiguration );
|
||||
if ( isInstance( bindableType, coercedValue ) ) {
|
||||
return new ValueBindJpaCriteriaParameter<>( bindableType, coercedValue, this );
|
||||
}
|
||||
else {
|
||||
// ignore typeInferenceSource and fall back the value type
|
||||
return new ValueBindJpaCriteriaParameter<>( getParameterBindType( value ), value, this );
|
||||
}
|
||||
}
|
||||
|
||||
private <T> ValueBindJpaCriteriaParameter<T> valueParameter(T value) {
|
||||
return new ValueBindJpaCriteriaParameter<>( getParameterBindType( value ), value, this );
|
||||
}
|
||||
|
||||
private <T> BindableType<? super T> getParameterBindType(T value) {
|
||||
return getMappingMetamodel().resolveParameterBindType( value );
|
||||
}
|
||||
|
||||
private <T> boolean inlineValue(T value) {
|
||||
return criteriaValueHandlingMode == ValueHandlingMode.INLINE;
|
||||
// || is a literal enum mapped to a PostgreSQL named 'enum' type
|
||||
|
@ -1772,11 +1733,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
|
||||
@Override
|
||||
public <C extends Collection<?>> SqmExpression<Integer> size(C collection) {
|
||||
return new SqmLiteral<>(
|
||||
collection.size(),
|
||||
getIntegerType(),
|
||||
this
|
||||
);
|
||||
return new SqmLiteral<>( collection.size(), getIntegerType(), this );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1791,13 +1748,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
( (SqmExpression<? extends Y>) x ).getExpressible(),
|
||||
( (SqmExpression<? extends Y>) y ).getExpressible()
|
||||
);
|
||||
return new SqmCoalesce<>(
|
||||
sqmExpressible,
|
||||
2,
|
||||
this
|
||||
)
|
||||
.value(x)
|
||||
.value(y);
|
||||
return new SqmCoalesce<>( sqmExpressible, 2, this ).value(x).value(y);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1817,15 +1768,14 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
}
|
||||
|
||||
private <Y> SqmExpression<Y> createNullifFunctionNode(SqmExpression<Y> first, SqmExpression<Y> second) {
|
||||
//noinspection unchecked
|
||||
final ReturnableType<Y> type = (ReturnableType<Y>) highestPrecedenceType(
|
||||
first.getExpressible(),
|
||||
second.getExpressible()
|
||||
).getSqmType();
|
||||
|
||||
final DomainType<? extends Y> type =
|
||||
highestPrecedenceType( first.getExpressible(), second.getExpressible() )
|
||||
.getSqmType();
|
||||
@SuppressWarnings("unchecked")
|
||||
final ReturnableType<Y> resultType = (ReturnableType<Y>) type;
|
||||
return getFunctionDescriptor("nullif").generateSqmExpression(
|
||||
asList( first, second ),
|
||||
type,
|
||||
resultType,
|
||||
getQueryEngine()
|
||||
);
|
||||
}
|
||||
|
@ -1910,8 +1860,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
|
||||
@Override
|
||||
public SqmPredicate not(Expression<Boolean> restriction) {
|
||||
final SqmPredicate predicate = wrap( restriction );
|
||||
return predicate.not();
|
||||
return wrap( restriction ).not();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,7 +20,6 @@ import org.hibernate.metamodel.model.domain.EntityDomainType;
|
|||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
import org.hibernate.metamodel.model.domain.PersistentAttribute;
|
||||
import org.hibernate.query.sqm.NodeBuilder;
|
||||
import org.hibernate.query.sqm.SqmExpressible;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
import org.hibernate.query.sqm.tree.SqmCopyContext;
|
||||
import org.hibernate.query.sqm.tree.expression.AbstractSqmExpression;
|
||||
|
@ -175,8 +174,7 @@ public abstract class AbstractSqmPath<T> extends AbstractSqmExpression<T> implem
|
|||
if ( subPathSource == null ) {
|
||||
return new SqmLiteral<>(
|
||||
referencedPathSource.getBindableJavaType(),
|
||||
(SqmExpressible<? extends Class<? extends T>>) (SqmExpressible<?>)
|
||||
nodeBuilder().getTypeConfiguration().getBasicTypeForJavaType( Class.class ),
|
||||
nodeBuilder().getTypeConfiguration().getBasicTypeForJavaType( Class.class ),
|
||||
nodeBuilder()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -23,12 +23,16 @@ import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
|||
public class SqmFkExpression<T> extends AbstractSqmExpression<T> {
|
||||
private final SqmEntityValuedSimplePath<?> toOnePath;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public SqmFkExpression(SqmEntityValuedSimplePath<?> toOnePath, NodeBuilder criteriaBuilder) {
|
||||
//noinspection unchecked
|
||||
super( (SqmExpressible<? extends T>) ( (IdentifiableDomainType<?>) toOnePath.getNodeType() ).getIdType(), criteriaBuilder );
|
||||
super( (SqmExpressible<? super T>) pathDomainType( toOnePath ).getIdType(), criteriaBuilder );
|
||||
this.toOnePath = toOnePath;
|
||||
}
|
||||
|
||||
private static IdentifiableDomainType<?> pathDomainType(SqmEntityValuedSimplePath<?> toOnePath) {
|
||||
return (IdentifiableDomainType<?>) toOnePath.getNodeType();
|
||||
}
|
||||
|
||||
public SqmEntityValuedSimplePath<?> getToOnePath() {
|
||||
return toOnePath;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ import static org.hibernate.query.internal.QueryHelper.highestPrecedenceType2;
|
|||
*/
|
||||
public abstract class AbstractSqmExpression<T> extends AbstractJpaSelection<T> implements SqmExpression<T> {
|
||||
|
||||
public AbstractSqmExpression(SqmExpressible<? extends T> type, NodeBuilder criteriaBuilder) {
|
||||
public AbstractSqmExpression(SqmExpressible<? super T> type, NodeBuilder criteriaBuilder) {
|
||||
super( type, criteriaBuilder );
|
||||
}
|
||||
|
||||
|
@ -41,16 +41,6 @@ public abstract class AbstractSqmExpression<T> extends AbstractJpaSelection<T> i
|
|||
|
||||
@Override
|
||||
public void applyInferableType(SqmExpressible<?> type) {
|
||||
// if ( type == null ) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// final SqmExpressible<?> oldType = getNodeType();
|
||||
//
|
||||
// final SqmExpressible<?> newType = highestPrecedenceType( oldType, type );
|
||||
// if ( newType != null && newType != oldType ) {
|
||||
// internalApplyInferableType( newType );
|
||||
// }
|
||||
}
|
||||
|
||||
protected void internalApplyInferableType(SqmExpressible<?> newType) {
|
||||
|
@ -64,44 +54,48 @@ public abstract class AbstractSqmExpression<T> extends AbstractJpaSelection<T> i
|
|||
setExpressibleType( highestPrecedenceType2( newType, getExpressible() ) );
|
||||
}
|
||||
|
||||
private <B> SqmExpression<B> castToBasicType(Class<B> javaType) {
|
||||
return castAs( nodeBuilder().getTypeConfiguration().getBasicTypeForJavaType( javaType ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<Long> asLong() {
|
||||
return castAs( nodeBuilder().getTypeConfiguration().getBasicTypeForJavaType( Long.class ) );
|
||||
return castToBasicType( Long.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<Integer> asInteger() {
|
||||
return castAs( nodeBuilder().getTypeConfiguration().getBasicTypeForJavaType( Integer.class ) );
|
||||
return castToBasicType( Integer.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<Float> asFloat() {
|
||||
return castAs( nodeBuilder().getTypeConfiguration().getBasicTypeForJavaType( Float.class ) );
|
||||
return castToBasicType( Float.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<Double> asDouble() {
|
||||
return castAs( nodeBuilder().getTypeConfiguration().getBasicTypeForJavaType( Double.class ) );
|
||||
return castToBasicType( Double.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<BigDecimal> asBigDecimal() {
|
||||
return castAs( nodeBuilder().getTypeConfiguration().getBasicTypeForJavaType( BigDecimal.class ) );
|
||||
return castToBasicType( BigDecimal.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<BigInteger> asBigInteger() {
|
||||
return castAs( nodeBuilder().getTypeConfiguration().getBasicTypeForJavaType( BigInteger.class ) );
|
||||
return castToBasicType( BigInteger.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<String> asString() {
|
||||
return castAs( nodeBuilder().getTypeConfiguration().getBasicTypeForJavaType( String.class ) );
|
||||
return castToBasicType( String.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> SqmExpression<X> as(Class<X> type) {
|
||||
return nodeBuilder().cast(this, type);
|
||||
return nodeBuilder().cast( this, type );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,7 +8,6 @@ package org.hibernate.query.sqm.tree.expression;
|
|||
|
||||
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||
import org.hibernate.query.BindableType;
|
||||
import org.hibernate.query.internal.QueryHelper;
|
||||
import org.hibernate.query.sqm.NodeBuilder;
|
||||
import org.hibernate.query.sqm.SqmExpressible;
|
||||
|
||||
|
@ -30,13 +29,16 @@ public abstract class AbstractSqmParameter<T> extends AbstractSqmExpression<T> i
|
|||
|
||||
@Override
|
||||
public void applyInferableType(SqmExpressible<?> type) {
|
||||
if ( type == null ) {
|
||||
return;
|
||||
if ( type != null ) {
|
||||
if ( type instanceof PluralPersistentAttribute ) {
|
||||
final PluralPersistentAttribute<?, ?, ?> pluralPersistentAttribute =
|
||||
(PluralPersistentAttribute<?, ?, ?>) type;
|
||||
internalApplyInferableType( pluralPersistentAttribute.getElementType() );
|
||||
}
|
||||
else {
|
||||
internalApplyInferableType( type );
|
||||
}
|
||||
}
|
||||
else if ( type instanceof PluralPersistentAttribute<?, ?, ?> ) {
|
||||
type = ( (PluralPersistentAttribute<?, ?, ?>) type ).getElementType();
|
||||
}
|
||||
internalApplyInferableType( type );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -36,7 +36,7 @@ public class JpaCriteriaParameter<T>
|
|||
|
||||
public JpaCriteriaParameter(
|
||||
String name,
|
||||
BindableType<T> type,
|
||||
BindableType<? super T> type,
|
||||
boolean allowsMultiValuedBinding,
|
||||
NodeBuilder nodeBuilder) {
|
||||
super( toSqmType( type, nodeBuilder ), nodeBuilder );
|
||||
|
|
|
@ -32,7 +32,7 @@ public class SqmAliasedNodeRef extends AbstractSqmExpression<Integer> {
|
|||
public SqmAliasedNodeRef(
|
||||
int position,
|
||||
NavigablePath navigablePath,
|
||||
SqmExpressible<? extends Integer> type,
|
||||
SqmExpressible<Integer> type,
|
||||
NodeBuilder criteriaBuilder) {
|
||||
super( type, criteriaBuilder );
|
||||
this.position = position;
|
||||
|
|
|
@ -25,21 +25,24 @@ import jakarta.persistence.criteria.Expression;
|
|||
public class SqmCaseSearched<R>
|
||||
extends AbstractSqmExpression<R>
|
||||
implements JpaSearchedCase<R> {
|
||||
private final List<WhenFragment<R>> whenFragments;
|
||||
private SqmExpression<R> otherwise;
|
||||
private final List<WhenFragment<? extends R>> whenFragments;
|
||||
private SqmExpression<? extends R> otherwise;
|
||||
|
||||
public SqmCaseSearched(NodeBuilder nodeBuilder) {
|
||||
this( null, nodeBuilder );
|
||||
}
|
||||
|
||||
public SqmCaseSearched(SqmExpressible<R> inherentType, NodeBuilder nodeBuilder) {
|
||||
super( inherentType, nodeBuilder );
|
||||
this.whenFragments = new ArrayList<>();
|
||||
this( inherentType, 10, nodeBuilder );
|
||||
}
|
||||
|
||||
public SqmCaseSearched(SqmExpressible<R> inherentType, int estimateWhenSize, NodeBuilder nodeBuilder) {
|
||||
public SqmCaseSearched(int estimatedWhenSize, NodeBuilder nodeBuilder) {
|
||||
this( null, estimatedWhenSize, nodeBuilder );
|
||||
}
|
||||
|
||||
private SqmCaseSearched(SqmExpressible<R> inherentType, int estimatedWhenSize, NodeBuilder nodeBuilder) {
|
||||
super( inherentType, nodeBuilder );
|
||||
this.whenFragments = new ArrayList<>( estimateWhenSize );
|
||||
this.whenFragments = new ArrayList<>( estimatedWhenSize );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -50,13 +53,9 @@ public class SqmCaseSearched<R>
|
|||
}
|
||||
final SqmCaseSearched<R> caseSearched = context.registerCopy(
|
||||
this,
|
||||
new SqmCaseSearched<>(
|
||||
getNodeType(),
|
||||
whenFragments.size(),
|
||||
nodeBuilder()
|
||||
)
|
||||
new SqmCaseSearched<>( getNodeType(), whenFragments.size(), nodeBuilder() )
|
||||
);
|
||||
for ( WhenFragment<R> whenFragment : whenFragments ) {
|
||||
for ( WhenFragment<? extends R> whenFragment : whenFragments ) {
|
||||
caseSearched.whenFragments.add(
|
||||
new WhenFragment<>(
|
||||
whenFragment.predicate.copy( context ),
|
||||
|
@ -71,36 +70,33 @@ public class SqmCaseSearched<R>
|
|||
return caseSearched;
|
||||
}
|
||||
|
||||
public List<WhenFragment<R>> getWhenFragments() {
|
||||
public List<WhenFragment<? extends R>> getWhenFragments() {
|
||||
return whenFragments;
|
||||
}
|
||||
|
||||
public SqmExpression<R> getOtherwise() {
|
||||
public SqmExpression<? extends R> getOtherwise() {
|
||||
return otherwise;
|
||||
}
|
||||
|
||||
public SqmCaseSearched<R> when(SqmPredicate predicate, SqmExpression<R> result) {
|
||||
public SqmCaseSearched<R> when(SqmPredicate predicate, SqmExpression<? extends R> result) {
|
||||
whenFragments.add( new WhenFragment<>( predicate, result ) );
|
||||
applyInferableResultType( result.getNodeType() );
|
||||
return this;
|
||||
}
|
||||
|
||||
public SqmCaseSearched<R> otherwise(SqmExpression<R> otherwiseExpression) {
|
||||
public SqmCaseSearched<R> otherwise(SqmExpression<? extends R> otherwiseExpression) {
|
||||
this.otherwise = otherwiseExpression;
|
||||
applyInferableResultType( otherwiseExpression.getNodeType() );
|
||||
return this;
|
||||
}
|
||||
|
||||
private void applyInferableResultType(SqmExpressible<?> type) {
|
||||
if ( type == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final SqmExpressible<?> oldType = getExpressible();
|
||||
|
||||
final SqmExpressible<?> newType = QueryHelper.highestPrecedenceType2( oldType, type );
|
||||
if ( newType != null && newType != oldType ) {
|
||||
internalApplyInferableType( newType );
|
||||
if ( type != null ) {
|
||||
final SqmExpressible<?> oldType = getExpressible();
|
||||
final SqmExpressible<?> newType = QueryHelper.highestPrecedenceType2( oldType, type );
|
||||
if ( newType != null && newType != oldType ) {
|
||||
internalApplyInferableType( newType );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,9 +109,7 @@ public class SqmCaseSearched<R>
|
|||
}
|
||||
|
||||
if ( whenFragments != null ) {
|
||||
whenFragments.forEach(
|
||||
whenFragment -> whenFragment.getResult().applyInferableType( newType )
|
||||
);
|
||||
whenFragments.forEach( whenFragment -> whenFragment.getResult().applyInferableType( newType ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,7 +144,7 @@ public class SqmCaseSearched<R>
|
|||
@Override
|
||||
public void appendHqlString(StringBuilder sb) {
|
||||
sb.append( "case" );
|
||||
for ( WhenFragment<R> whenFragment : whenFragments ) {
|
||||
for ( WhenFragment<? extends R> whenFragment : whenFragments ) {
|
||||
sb.append( " when " );
|
||||
whenFragment.predicate.appendHqlString( sb );
|
||||
sb.append( " then " );
|
||||
|
@ -176,8 +170,7 @@ public class SqmCaseSearched<R>
|
|||
|
||||
@Override
|
||||
public SqmCaseSearched<R> when(Expression<Boolean> condition, Expression<? extends R> result) {
|
||||
//noinspection unchecked
|
||||
when( nodeBuilder().wrap( condition ), (SqmExpression) result );
|
||||
when( nodeBuilder().wrap( condition ), (SqmExpression<? extends R>) result );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -189,8 +182,7 @@ public class SqmCaseSearched<R>
|
|||
|
||||
@Override
|
||||
public SqmExpression<R> otherwise(Expression<? extends R> result) {
|
||||
//noinspection unchecked
|
||||
otherwise( (SqmExpression) result );
|
||||
otherwise( (SqmExpression<? extends R>) result );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,22 +26,28 @@ public class SqmCaseSimple<T, R>
|
|||
extends AbstractSqmExpression<R>
|
||||
implements JpaSimpleCase<T, R> {
|
||||
private final SqmExpression<T> fixture;
|
||||
private final List<WhenFragment<T, R>> whenFragments;
|
||||
private SqmExpression<R> otherwise;
|
||||
private final List<WhenFragment<? extends T, ? extends R>> whenFragments;
|
||||
private SqmExpression<? extends R> otherwise;
|
||||
|
||||
public SqmCaseSimple(SqmExpression<T> fixture, NodeBuilder nodeBuilder) {
|
||||
this( fixture, null, nodeBuilder );
|
||||
this( fixture, null, 10, nodeBuilder );
|
||||
}
|
||||
|
||||
public SqmCaseSimple(SqmExpression<T> fixture, int estimatedWhenSize, NodeBuilder nodeBuilder) {
|
||||
this( fixture, null, estimatedWhenSize, nodeBuilder );
|
||||
}
|
||||
|
||||
public SqmCaseSimple(SqmExpression<T> fixture, SqmExpressible<R> inherentType, NodeBuilder nodeBuilder) {
|
||||
super( inherentType, nodeBuilder );
|
||||
this.whenFragments = new ArrayList<>( );
|
||||
this.fixture = fixture;
|
||||
this( fixture, inherentType, 10, nodeBuilder );
|
||||
}
|
||||
|
||||
public SqmCaseSimple(SqmExpression<T> fixture, SqmExpressible<R> inherentType, int estimateWhenSize, NodeBuilder nodeBuilder) {
|
||||
private SqmCaseSimple(
|
||||
SqmExpression<T> fixture,
|
||||
SqmExpressible<R> inherentType,
|
||||
int estimatedWhenSize,
|
||||
NodeBuilder nodeBuilder) {
|
||||
super( inherentType, nodeBuilder );
|
||||
this.whenFragments = new ArrayList<>( estimateWhenSize );
|
||||
this.whenFragments = new ArrayList<>( estimatedWhenSize );
|
||||
this.fixture = fixture;
|
||||
}
|
||||
|
||||
|
@ -53,14 +59,9 @@ public class SqmCaseSimple<T, R>
|
|||
}
|
||||
final SqmCaseSimple<T, R> caseSearched = context.registerCopy(
|
||||
this,
|
||||
new SqmCaseSimple<>(
|
||||
fixture.copy( context ),
|
||||
getNodeType(),
|
||||
whenFragments.size(),
|
||||
nodeBuilder()
|
||||
)
|
||||
new SqmCaseSimple<>( fixture.copy( context ), getNodeType(), whenFragments.size(), nodeBuilder() )
|
||||
);
|
||||
for ( SqmCaseSimple.WhenFragment<T, R> whenFragment : whenFragments ) {
|
||||
for ( WhenFragment<? extends T, ? extends R> whenFragment : whenFragments ) {
|
||||
caseSearched.whenFragments.add(
|
||||
new SqmCaseSimple.WhenFragment<>(
|
||||
whenFragment.checkValue.copy( context ),
|
||||
|
@ -79,41 +80,41 @@ public class SqmCaseSimple<T, R>
|
|||
return fixture;
|
||||
}
|
||||
|
||||
public List<WhenFragment<T,R>> getWhenFragments() {
|
||||
public List<WhenFragment<? extends T,? extends R>> getWhenFragments() {
|
||||
return whenFragments;
|
||||
}
|
||||
|
||||
public SqmExpression<R> getOtherwise() {
|
||||
public SqmExpression<? extends R> getOtherwise() {
|
||||
return otherwise;
|
||||
}
|
||||
|
||||
public void otherwise(SqmExpression<R> otherwiseExpression) {
|
||||
public void otherwise(SqmExpression<? extends R> otherwiseExpression) {
|
||||
this.otherwise = otherwiseExpression;
|
||||
|
||||
applyInferableResultType( otherwiseExpression.getNodeType() );
|
||||
}
|
||||
|
||||
public void when(SqmExpression<T> test, SqmExpression<R> result) {
|
||||
public void when(SqmExpression<? extends T> test, SqmExpression<? extends R> result) {
|
||||
whenFragments.add( new WhenFragment<>( test, result ) );
|
||||
|
||||
// TODO: currently does nothing, but it would be nice if it worked!
|
||||
test.applyInferableType( fixture.getNodeType() );
|
||||
|
||||
applyInferableResultType( result.getNodeType() );
|
||||
}
|
||||
|
||||
private void applyInferableResultType(SqmExpressible<?> type) {
|
||||
if ( type == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final SqmExpressible<?> oldType = getExpressible();
|
||||
|
||||
final SqmExpressible<?> newType = QueryHelper.highestPrecedenceType2( oldType, type );
|
||||
if ( newType != null && newType != oldType ) {
|
||||
internalApplyInferableType( newType );
|
||||
if ( type != null ) {
|
||||
final SqmExpressible<?> oldType = getExpressible();
|
||||
final SqmExpressible<?> newType = QueryHelper.highestPrecedenceType2( oldType, type );
|
||||
if ( newType != null && newType != oldType ) {
|
||||
internalApplyInferableType( newType );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void internalApplyInferableType(SqmExpressible newType) {
|
||||
protected void internalApplyInferableType(SqmExpressible<?> newType) {
|
||||
super.internalApplyInferableType( newType );
|
||||
|
||||
if ( otherwise != null ) {
|
||||
|
@ -121,9 +122,7 @@ public class SqmCaseSimple<T, R>
|
|||
}
|
||||
|
||||
if ( whenFragments != null ) {
|
||||
whenFragments.forEach(
|
||||
whenFragment -> whenFragment.getResult().applyInferableType( newType )
|
||||
);
|
||||
whenFragments.forEach( whenFragment -> whenFragment.getResult().applyInferableType( newType ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,11 +145,6 @@ public class SqmCaseSimple<T, R>
|
|||
this.result = result;
|
||||
}
|
||||
|
||||
private WhenFragment(WhenFragment<T, R> original, SqmCopyContext context) {
|
||||
this.checkValue = original.checkValue.copy( context );
|
||||
this.result = original.result.copy( context );
|
||||
}
|
||||
|
||||
public SqmExpression<T> getCheckValue() {
|
||||
return checkValue;
|
||||
}
|
||||
|
@ -164,7 +158,7 @@ public class SqmCaseSimple<T, R>
|
|||
public void appendHqlString(StringBuilder sb) {
|
||||
sb.append( "case " );
|
||||
fixture.appendHqlString( sb );
|
||||
for ( WhenFragment<T, R> whenFragment : whenFragments ) {
|
||||
for ( WhenFragment<? extends T, ? extends R> whenFragment : whenFragments ) {
|
||||
sb.append( " when " );
|
||||
whenFragment.checkValue.appendHqlString( sb );
|
||||
sb.append( " then " );
|
||||
|
@ -195,8 +189,7 @@ public class SqmCaseSimple<T, R>
|
|||
|
||||
@Override
|
||||
public JpaSimpleCase<T, R> when(T condition, Expression<? extends R> result) {
|
||||
//noinspection unchecked
|
||||
when( nodeBuilder().value( condition, fixture ), (SqmExpression<R>) result );
|
||||
when( nodeBuilder().value( condition, fixture ), (SqmExpression<? extends R>) result );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -208,8 +201,7 @@ public class SqmCaseSimple<T, R>
|
|||
|
||||
@Override
|
||||
public JpaSimpleCase<T, R> when(Expression<? extends T> condition, Expression<? extends R> result) {
|
||||
//noinspection unchecked
|
||||
when( (SqmExpression<T>) condition, (SqmExpression<R>) result );
|
||||
when( (SqmExpression<? extends T>) condition, (SqmExpression<? extends R>) result );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -221,8 +213,7 @@ public class SqmCaseSimple<T, R>
|
|||
|
||||
@Override
|
||||
public JpaSimpleCase<T, R> otherwise(Expression<? extends R> result) {
|
||||
//noinspection unchecked
|
||||
otherwise( (SqmExpression<R>) result );
|
||||
otherwise( (SqmExpression<? extends R>) result );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ import org.hibernate.type.descriptor.java.JavaType;
|
|||
public class SqmLiteral<T> extends AbstractSqmExpression<T> {
|
||||
private final T value;
|
||||
|
||||
public SqmLiteral(T value, SqmExpressible<? extends T> inherentType, NodeBuilder nodeBuilder) {
|
||||
public SqmLiteral(T value, SqmExpressible<? super T> inherentType, NodeBuilder nodeBuilder) {
|
||||
super( inherentType, nodeBuilder );
|
||||
assert value != null && ( inherentType == null || inherentType.getExpressibleJavaType().isInstance( value ) );
|
||||
this.value = value;
|
||||
|
|
|
@ -19,7 +19,7 @@ public class ValueBindJpaCriteriaParameter<T> extends JpaCriteriaParameter<T>{
|
|||
private final T value;
|
||||
|
||||
public ValueBindJpaCriteriaParameter(
|
||||
BindableType<T> type,
|
||||
BindableType<? super T> type,
|
||||
T value,
|
||||
NodeBuilder nodeBuilder) {
|
||||
super( null, type, false, nodeBuilder );
|
||||
|
|
|
@ -21,8 +21,8 @@ import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
|
|||
public abstract class AbstractJpaSelection<T>
|
||||
extends AbstractJpaTupleElement<T>
|
||||
implements SqmSelectableNode<T>, JpaSelection<T> {
|
||||
protected AbstractJpaSelection(SqmExpressible<? extends T> sqmExpressible, NodeBuilder criteriaBuilder) {
|
||||
super(sqmExpressible, criteriaBuilder );
|
||||
protected AbstractJpaSelection(SqmExpressible<? super T> sqmExpressible, NodeBuilder criteriaBuilder) {
|
||||
super( sqmExpressible, criteriaBuilder );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,10 +25,9 @@ public abstract class AbstractJpaTupleElement<T>
|
|||
private SqmExpressible<T> expressibleType;
|
||||
private String alias;
|
||||
|
||||
protected AbstractJpaTupleElement(SqmExpressible<? extends T> expressibleType, NodeBuilder criteriaBuilder) {
|
||||
protected AbstractJpaTupleElement(SqmExpressible<? super T> expressibleType, NodeBuilder criteriaBuilder) {
|
||||
super( criteriaBuilder );
|
||||
|
||||
setExpressibleType(expressibleType);
|
||||
setExpressibleType( expressibleType );
|
||||
}
|
||||
|
||||
protected void copyTo(AbstractJpaTupleElement<T> target, SqmCopyContext context) {
|
||||
|
|
|
@ -38,10 +38,9 @@ import org.hibernate.query.sqm.tree.predicate.SqmTruthnessPredicate;
|
|||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
|
||||
/**
|
||||
* todo (6.0) : how is this different from {@link org.hibernate.query.sqm.internal.ParameterCollector}?
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
// todo (6.0) : how is this different from org.hibernate.query.sqm.internal.ParameterCollector?
|
||||
public class ParameterCollector extends BaseSemanticQueryWalker {
|
||||
|
||||
public static Set<SqmParameter<?>> collectParameters(SqmStatement<?> statement) {
|
||||
|
@ -76,12 +75,11 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
|
|||
}
|
||||
|
||||
/**
|
||||
* This is called while performing an inflight parameter collection of parameters
|
||||
* for `CriteriaQuery#getParameters`. That method can be called multiple times and
|
||||
* the parameters may have changed in between each call - therefore the parameters
|
||||
* must be collected dynamically each time.
|
||||
*
|
||||
* This form simply returns the JpaCriteriaParameter
|
||||
* This is called while performing an in-flight parameter collection of parameters
|
||||
* for {@link jakarta.persistence.criteria.CriteriaQuery#getParameters}. That method
|
||||
* can be called multiple times and the parameters may have changed in between each
|
||||
* call - therefore the parameters must be collected dynamically each time.
|
||||
* This form simply returns the {@link JpaCriteriaParameter}.
|
||||
*
|
||||
* @see SqmSelectStatement#resolveParameters()
|
||||
*/
|
||||
|
@ -140,7 +138,7 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
|
|||
|
||||
private SqmExpressibleAccessor<?> inferenceBasis;
|
||||
|
||||
private void withTypeInference(SqmExpressibleAccessor<?> inferenceBasis, Runnable action) {
|
||||
private <T> void withTypeInference(SqmExpressibleAccessor<T> inferenceBasis, Runnable action) {
|
||||
SqmExpressibleAccessor<?> original = this.inferenceBasis;
|
||||
this.inferenceBasis = inferenceBasis;
|
||||
try {
|
||||
|
@ -159,21 +157,21 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
|
|||
for ( SqmCaseSimple.WhenFragment<?, ?> whenFragment : expression.getWhenFragments() ) {
|
||||
final SqmExpressible<?> resolved = whenFragment.getCheckValue().getExpressible();
|
||||
if ( resolved != null ) {
|
||||
return (SqmExpressible<Object>) resolved;
|
||||
return (SqmExpressible<?>) resolved;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
() -> expression.getFixture().accept( this )
|
||||
);
|
||||
SqmExpressibleAccessor<?> resolved = determineCurrentExpressible( expression );
|
||||
SqmExpressibleAccessor<?> resolved = toExpressibleAccessor( expression );
|
||||
for ( SqmCaseSimple.WhenFragment<?, ?> whenFragment : expression.getWhenFragments() ) {
|
||||
withTypeInference(
|
||||
expression.getFixture(),
|
||||
() -> whenFragment.getCheckValue().accept( this )
|
||||
);
|
||||
withTypeInference(
|
||||
resolved == null && inferenceSupplier != null ? inferenceSupplier : resolved,
|
||||
getInferenceBasis( inferenceSupplier, resolved ),
|
||||
() -> whenFragment.getResult().accept( this )
|
||||
);
|
||||
resolved = highestPrecedence( resolved, whenFragment.getResult() );
|
||||
|
@ -181,7 +179,7 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
|
|||
|
||||
if ( expression.getOtherwise() != null ) {
|
||||
withTypeInference(
|
||||
resolved == null && inferenceSupplier != null ? inferenceSupplier : resolved,
|
||||
getInferenceBasis( inferenceSupplier, resolved ),
|
||||
() -> expression.getOtherwise().accept( this )
|
||||
);
|
||||
}
|
||||
|
@ -192,7 +190,7 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
|
|||
@Override
|
||||
public Object visitSearchedCaseExpression(SqmCaseSearched<?> expression) {
|
||||
final SqmExpressibleAccessor<?> inferenceSupplier = this.inferenceBasis;
|
||||
SqmExpressibleAccessor<?> resolved = determineCurrentExpressible( expression );
|
||||
SqmExpressibleAccessor<?> resolved = toExpressibleAccessor( expression );
|
||||
|
||||
for ( SqmCaseSearched.WhenFragment<?> whenFragment : expression.getWhenFragments() ) {
|
||||
withTypeInference(
|
||||
|
@ -200,7 +198,7 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
|
|||
() -> whenFragment.getPredicate().accept( this )
|
||||
);
|
||||
withTypeInference(
|
||||
resolved == null && inferenceSupplier != null ? inferenceSupplier : resolved,
|
||||
getInferenceBasis( inferenceSupplier, resolved ),
|
||||
() -> whenFragment.getResult().accept( this )
|
||||
);
|
||||
resolved = highestPrecedence( resolved, whenFragment.getResult() );
|
||||
|
@ -208,7 +206,7 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
|
|||
|
||||
if ( expression.getOtherwise() != null ) {
|
||||
withTypeInference(
|
||||
resolved == null && inferenceSupplier != null ? inferenceSupplier : resolved,
|
||||
getInferenceBasis( inferenceSupplier, resolved ),
|
||||
() -> expression.getOtherwise().accept( this )
|
||||
);
|
||||
}
|
||||
|
@ -216,6 +214,12 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
|
|||
return expression;
|
||||
}
|
||||
|
||||
private static SqmExpressibleAccessor<?> getInferenceBasis(
|
||||
SqmExpressibleAccessor<?> inferenceSupplier, SqmExpressibleAccessor<?> resolved) {
|
||||
// return resolved == null && inferenceSupplier != null ? inferenceSupplier : resolved;
|
||||
return inferenceSupplier == null ? resolved : inferenceSupplier;
|
||||
}
|
||||
|
||||
private SqmExpressibleAccessor<?> highestPrecedence(SqmExpressibleAccessor<?> type1, SqmExpressibleAccessor<?> type2) {
|
||||
if ( type1 == null ) {
|
||||
return type2;
|
||||
|
@ -235,11 +239,9 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
|
|||
return type1;
|
||||
}
|
||||
|
||||
private SqmExpressibleAccessor<?> determineCurrentExpressible(SqmExpression<?> expression) {
|
||||
if ( expression.getExpressible() != null ) {
|
||||
return () -> (SqmExpressible<Object>) expression.getExpressible();
|
||||
}
|
||||
return null;
|
||||
private <T> SqmExpressibleAccessor<T> toExpressibleAccessor(SqmExpression<T> expression) {
|
||||
final SqmExpressible<T> expressible = expression.getExpressible();
|
||||
return expressible == null ? null : () -> expressible;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -29,6 +29,8 @@ import jakarta.persistence.criteria.Path;
|
|||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.metamodel.SingularAttribute;
|
||||
|
||||
import static org.hibernate.query.sqm.internal.TypecheckUtil.assertAssignable;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -124,11 +126,18 @@ public class SqmUpdateStatement<T>
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override @SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public SqmUpdateStatement<T> set(String attributeName, Object value) {
|
||||
//noinspection unchecked
|
||||
final SqmPath<Object> sqmPath = (SqmPath<Object>) getTarget().get( attributeName );
|
||||
applyAssignment( sqmPath, (SqmExpression<?>) nodeBuilder().value( value ) );
|
||||
final SqmPath sqmPath = getTarget().get(attributeName);
|
||||
final SqmExpression expression;
|
||||
if ( value instanceof SqmExpression ) {
|
||||
expression = (SqmExpression) value;
|
||||
}
|
||||
else {
|
||||
expression = (SqmExpression) nodeBuilder().value( value );
|
||||
}
|
||||
assertAssignable( null, sqmPath, expression, nodeBuilder().getSessionFactory() );
|
||||
applyAssignment( sqmPath, expression );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,13 +67,7 @@ public abstract class AbstractJdbcParameter
|
|||
// - anything that is the same for each row always - parameter, literal, etc;
|
||||
// the idea would be to write the value directly into the JdbcValues array
|
||||
// and not generating a SQL selection in the query sent to DB
|
||||
return new SqlSelectionImpl(
|
||||
jdbcPosition,
|
||||
valuesArrayPosition,
|
||||
javaType,
|
||||
this,
|
||||
false
|
||||
);
|
||||
return new SqlSelectionImpl( jdbcPosition, valuesArrayPosition, javaType, this, false );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -93,7 +87,11 @@ public abstract class AbstractJdbcParameter
|
|||
throw new ExecutionException( "JDBC parameter value not bound - " + this );
|
||||
}
|
||||
|
||||
final Object bindValue = binding.getBindValue();
|
||||
final JdbcMapping jdbcMapping = jdbcMapping( executionContext, binding );
|
||||
bindParameterValue( jdbcMapping, statement, binding.getBindValue(), startPosition, executionContext );
|
||||
}
|
||||
|
||||
private JdbcMapping jdbcMapping(ExecutionContext executionContext, JdbcParameterBinding binding) {
|
||||
JdbcMapping jdbcMapping = binding.getBindType();
|
||||
|
||||
if ( jdbcMapping == null ) {
|
||||
|
@ -102,10 +100,14 @@ public abstract class AbstractJdbcParameter
|
|||
|
||||
// If the parameter type is not known from the context i.e. null or Object, infer it from the bind value
|
||||
if ( jdbcMapping == null || jdbcMapping.getMappedJavaType().getJavaTypeClass() == Object.class ) {
|
||||
jdbcMapping = guessBindType( executionContext, bindValue, jdbcMapping );
|
||||
jdbcMapping = guessBindType( executionContext, binding.getBindValue(), jdbcMapping );
|
||||
}
|
||||
|
||||
bindParameterValue( jdbcMapping, statement, bindValue, startPosition, executionContext );
|
||||
if ( jdbcMapping == null ) {
|
||||
throw new ExecutionException( "No JDBC mapping could be inferred for parameter - " + this );
|
||||
}
|
||||
|
||||
return jdbcMapping;
|
||||
}
|
||||
|
||||
protected void bindParameterValue(
|
||||
|
@ -127,14 +129,12 @@ public abstract class AbstractJdbcParameter
|
|||
if ( bindValue == null && jdbcMapping != null ) {
|
||||
return jdbcMapping;
|
||||
}
|
||||
|
||||
final BindableType<?> parameterType =
|
||||
executionContext.getSession().getFactory().getMappingMetamodel()
|
||||
.resolveParameterBindType( bindValue );
|
||||
if ( parameterType instanceof JdbcMapping ) {
|
||||
return (JdbcMapping) parameterType;
|
||||
else {
|
||||
final BindableType<?> parameterType =
|
||||
executionContext.getSession().getFactory().getMappingMetamodel()
|
||||
.resolveParameterBindType( bindValue );
|
||||
return parameterType instanceof JdbcMapping ? (JdbcMapping) parameterType : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,7 +8,6 @@ package org.hibernate.sql.exec.spi;
|
|||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
|
@ -94,11 +93,7 @@ public interface JdbcParameterBindings {
|
|||
addBinding(
|
||||
params.get( selectionIndex ),
|
||||
new JdbcParameterBindingImpl(
|
||||
BindingTypeHelper.INSTANCE.resolveBindType(
|
||||
jdbcValue,
|
||||
type,
|
||||
typeConfiguration
|
||||
),
|
||||
BindingTypeHelper.INSTANCE.resolveBindType( jdbcValue, type, typeConfiguration ),
|
||||
jdbcValue
|
||||
)
|
||||
);
|
||||
|
|
|
@ -2031,6 +2031,17 @@ public class FunctionTests {
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnumIsNull(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createSelectionQuery("from EntityOfBasics where gender is null").getResultList();
|
||||
session.createSelectionQuery("from EntityOfBasics e where e.gender is null").getResultList();
|
||||
// session.createSelectionQuery("from EntityOfBasics where :gender is null").setParameter("gender", EntityOfBasics.Gender.MALE).getResultList();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
static class Pair {
|
||||
int integer; double floating;
|
||||
Pair(int integer, double floating) {
|
||||
|
|
Loading…
Reference in New Issue