fixed SqmParameter type inference from an SqmPath during translation to SQL AST
This commit is contained in:
parent
b9f4562680
commit
e572202cd1
|
@ -8,7 +8,7 @@
|
|||
apply plugin: 'base'
|
||||
|
||||
ext {
|
||||
ormVersion = new HibernateVersion( '6.0.0-SNAPSHOT', project )
|
||||
ormVersion = new HibernateVersion( '6.0.0.BENCHMARK', project )
|
||||
baselineJavaVersion = '1.8'
|
||||
jpaVersion = new JpaVersion('2.2')
|
||||
}
|
||||
|
|
|
@ -110,12 +110,15 @@ DOUBLE_PIPE : '||';
|
|||
QUESTION_MARK : '?';
|
||||
ARROW : '->';
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Keywords
|
||||
|
||||
ABS : [aA] [bB] [sS];
|
||||
AS : [aA] [sS];
|
||||
ALL : [aA] [lL] [lL];
|
||||
AND : [aA] [nN] [dD];
|
||||
ANY : [aA] [nN] [yY];
|
||||
AS : [aA] [sS];
|
||||
ASC : [aA] [sS] [cC];
|
||||
AVG : [aA] [vV] [gG];
|
||||
BY : [bB] [yY];
|
||||
|
@ -129,11 +132,11 @@ COALESCE : [cC] [oO] [aA] [lL] [eE] [sS] [cC] [eE];
|
|||
COLLATE : [cC] [oO] [lL] [lL] [aA] [tT] [eE];
|
||||
CONCAT : [cC] [oO] [nN] [cC] [aA] [tT];
|
||||
COUNT : [cC] [oO] [uU] [nN] [tT];
|
||||
CROSS : [cC] [rR] [oO] [sS] [sS];
|
||||
CURRENT_DATE : [cC] [uU] [rR] [rR] [eE] [nN] [tT] '_' [dD] [aA] [tT] [eE];
|
||||
CURRENT_INSTANT : [cC] [uU] [rR] [rR] [eE] [nN] [tT] '_' [iI] [nN] [sS] [tT] [aA] [nN] [tT];
|
||||
CURRENT_TIME : [cC] [uU] [rR] [rR] [eE] [nN] [tT] '_' [tT] [iI] [mM] [eE];
|
||||
CURRENT_TIMESTAMP : [cC] [uU] [rR] [rR] [eE] [nN] [tT] '_' [tT] [iI] [mM] [eE] [sS] [tT] [aA] [mM] [pP];
|
||||
CROSS : [cC] [rR] [oO] [sS] [sS];
|
||||
DAY : [dD] [aA] [yY];
|
||||
DELETE : [dD] [eE] [lL] [eE] [tT] [eE];
|
||||
DESC : [dD] [eE] [sS] [cC];
|
||||
|
@ -170,8 +173,8 @@ LEADING : [lL] [eE] [aA] [dD] [iI] [nN] [gG];
|
|||
LEAST : [lL] [eE] [aA] [sS] [tT];
|
||||
LEFT : [lL] [eE] [fF] [tT];
|
||||
LENGTH : [lL] [eE] [nN] [gG] [tT] [hH];
|
||||
LIMIT : [lL] [iI] [mM] [iI] [tT];
|
||||
LIKE : [lL] [iI] [kK] [eE];
|
||||
LIMIT : [lL] [iI] [mM] [iI] [tT];
|
||||
LIST : [lL] [iI] [sS] [tT];
|
||||
LN : [lL] [nN];
|
||||
LOCATE : [lL] [oO] [cC] [aA] [tT] [eE];
|
||||
|
@ -230,12 +233,12 @@ WHERE : [wW] [hH] [eE] [rR] [eE];
|
|||
WITH : [wW] [iI] [tT] [hH];
|
||||
YEAR : [yY] [eE] [aA] [rR];
|
||||
|
||||
ACOS : [aA] [cC] [oO] [sH];
|
||||
ASIN : [aA] [sS] [iI] [nN];
|
||||
ATAN : [aA] [cC] [oO] [sH];
|
||||
ATAN : [aA] [tT] [aA] [nN];
|
||||
ATAN2 : [aA] [tT] [aA] [nN] '2';
|
||||
ACOS : [aA] [tT] [aA] [nN];
|
||||
SIN : [sS] [iI] [nN];
|
||||
COS : [cC] [oO] [sH];
|
||||
SIN : [sS] [iI] [nN];
|
||||
TAN : [tT] [aA] [nN];
|
||||
|
||||
// case-insensitive true, false and null recognition (split vote :)
|
||||
|
|
|
@ -761,7 +761,13 @@ trigFunction
|
|||
;
|
||||
|
||||
trigFunctionName
|
||||
: SIN | COS | TAN | ASIN | ACOS | ATAN
|
||||
: COS
|
||||
| SIN
|
||||
| TAN
|
||||
| ACOS
|
||||
| ASIN
|
||||
| ATAN
|
||||
| ATAN2
|
||||
;
|
||||
|
||||
atan2Function
|
||||
|
@ -845,30 +851,43 @@ positionFunctionStringArgument
|
|||
identifier
|
||||
: IDENTIFIER
|
||||
| (ABS
|
||||
| AS
|
||||
| ALL
|
||||
| AND
|
||||
| ANY
|
||||
| AS
|
||||
| ASC
|
||||
| ATAN2
|
||||
| AVG
|
||||
| BY
|
||||
| BETWEEN
|
||||
| BOTH
|
||||
| CASE
|
||||
| CAST
|
||||
| CEILING
|
||||
| CLASS
|
||||
| COALESCE
|
||||
| COLLATE
|
||||
| CONCAT
|
||||
| COUNT
|
||||
| CROSS
|
||||
| CURRENT_DATE
|
||||
| CURRENT_INSTANT
|
||||
| CURRENT_TIME
|
||||
| CURRENT_TIMESTAMP
|
||||
| DAY
|
||||
| DELETE
|
||||
| DESC
|
||||
| DISTINCT
|
||||
| ELEMENTS
|
||||
| ELSE
|
||||
| EMPTY
|
||||
| END
|
||||
| ENTRY
|
||||
| ESCAPE
|
||||
| EXISTS
|
||||
| EXP
|
||||
| EXTRACT
|
||||
| FETCH
|
||||
| FLOOR
|
||||
| FROM
|
||||
| FOR
|
||||
|
@ -882,6 +901,8 @@ identifier
|
|||
| INDEX
|
||||
| INNER
|
||||
| INSERT
|
||||
| INTO
|
||||
| IS
|
||||
| JOIN
|
||||
| KEY
|
||||
| LEADING
|
||||
|
@ -892,38 +913,53 @@ identifier
|
|||
| LIMIT
|
||||
| LIST
|
||||
| LN
|
||||
| LOCATE
|
||||
| LOWER
|
||||
| MAP
|
||||
| MAX
|
||||
| MAXELEMENT
|
||||
| MAXINDEX
|
||||
| MEMBER
|
||||
| MICROSECOND
|
||||
| MILLISECOND
|
||||
| MIN
|
||||
| MINELEMENT
|
||||
| MININDEX
|
||||
| MINUTE
|
||||
| MEMBER
|
||||
| MOD
|
||||
| MONTH
|
||||
| NEW
|
||||
| NOT
|
||||
| NULLIF
|
||||
| OBJECT
|
||||
| OF
|
||||
| OFFSET
|
||||
| ON
|
||||
| OR
|
||||
| ORDER
|
||||
| OUTER
|
||||
| POSITION
|
||||
| QUARTER
|
||||
| POWER
|
||||
| QUARTER
|
||||
| REPLACE
|
||||
| ROUND
|
||||
| RIGHT
|
||||
| SELECT
|
||||
| ROUND
|
||||
| SECOND
|
||||
| SELECT
|
||||
| SET
|
||||
| SIGN
|
||||
| SIZE
|
||||
| SQRT
|
||||
| STR
|
||||
| SUBSTRING
|
||||
| SUM
|
||||
| THEN
|
||||
| TIMEZONE_HOUR
|
||||
| TIMEZONE_MINUTE
|
||||
| TRAILING
|
||||
| TREAT
|
||||
| TRIM
|
||||
| TYPE
|
||||
| UPDATE
|
||||
| UPPER
|
||||
| VALUE
|
||||
|
|
|
@ -61,4 +61,11 @@ public class BasicSqmPathSource<J>
|
|||
public Class<J> getJavaType() {
|
||||
return getExpressableJavaTypeDescriptor().getJavaType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BasicSqmPathSource(" +
|
||||
getPathName() + " : " + getJavaType().getSimpleName() +
|
||||
")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ import org.hibernate.internal.util.collections.ArrayHelper;
|
|||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.metamodel.internal.JpaStaticMetaModelPopulationSetting;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
|
||||
|
@ -59,8 +58,6 @@ import org.hibernate.persister.collection.CollectionPersister;
|
|||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.Queryable;
|
||||
import org.hibernate.persister.spi.PersisterFactory;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.PathException;
|
||||
import org.hibernate.query.sqm.SqmExpressable;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.Type;
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.query.hql.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
|
|
|
@ -192,6 +192,8 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
executionContext.getDomainParameterBindingContext().getQueryParameterBindings(),
|
||||
domainParameterXref,
|
||||
jdbcParamsXref,
|
||||
// todo (6.0) : ugh. this one is important
|
||||
null,
|
||||
session
|
||||
);
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.mapping.Bindable;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
|
@ -25,13 +26,13 @@ import org.hibernate.query.spi.QueryParameterBinding;
|
|||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||
import org.hibernate.query.sqm.spi.JdbcParameterBySqmParameterAccess;
|
||||
import org.hibernate.query.sqm.sql.SqlAstCreationState;
|
||||
import org.hibernate.query.sqm.tree.SqmDmlStatement;
|
||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameter;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBinding;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
|
@ -107,50 +108,52 @@ public class SqmUtil {
|
|||
|
||||
return result;
|
||||
}
|
||||
public static JdbcParameterBindings buildJdbcParameterBindings(
|
||||
SqmStatement sqmStatement,
|
||||
JdbcParameterBySqmParameterAccess sqmInterpretation,
|
||||
ExecutionContext executionContext) {
|
||||
final DomainParameterXref domainParameterXref = DomainParameterXref.from( sqmStatement );
|
||||
final Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamsXref =
|
||||
generateJdbcParamsXref( domainParameterXref, sqmInterpretation );
|
||||
return createJdbcParameterBindings(
|
||||
executionContext.getDomainParameterBindingContext().getQueryParameterBindings(),
|
||||
domainParameterXref,
|
||||
jdbcParamsXref,
|
||||
executionContext.getSession()
|
||||
);
|
||||
}
|
||||
|
||||
public static JdbcParameterBindings buildJdbcParameterBindings(
|
||||
SqmStatement sqmStatement,
|
||||
Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamsXref,
|
||||
ExecutionContext executionContext) {
|
||||
final DomainParameterXref domainParameterXref = DomainParameterXref.from( sqmStatement );
|
||||
return createJdbcParameterBindings(
|
||||
executionContext.getDomainParameterBindingContext().getQueryParameterBindings(),
|
||||
domainParameterXref,
|
||||
jdbcParamsXref,
|
||||
executionContext.getSession()
|
||||
);
|
||||
}
|
||||
// public static JdbcParameterBindings buildJdbcParameterBindings(
|
||||
// SqmStatement sqmStatement,
|
||||
// JdbcParameterBySqmParameterAccess sqmInterpretation,
|
||||
// ExecutionContext executionContext) {
|
||||
// final DomainParameterXref domainParameterXref = DomainParameterXref.from( sqmStatement );
|
||||
// final Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamsXref =
|
||||
// generateJdbcParamsXref( domainParameterXref, sqmInterpretation );
|
||||
// return createJdbcParameterBindings(
|
||||
// executionContext.getDomainParameterBindingContext().getQueryParameterBindings(),
|
||||
// domainParameterXref,
|
||||
// jdbcParamsXref,
|
||||
// executionContext.getSession()
|
||||
// );
|
||||
// }
|
||||
|
||||
public static JdbcParameterBindings buildJdbcParameterBindings(
|
||||
DomainParameterXref domainParameterXref,
|
||||
Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamsXref,
|
||||
ExecutionContext executionContext) {
|
||||
return createJdbcParameterBindings(
|
||||
executionContext.getDomainParameterBindingContext().getQueryParameterBindings(),
|
||||
domainParameterXref,
|
||||
jdbcParamsXref,
|
||||
executionContext.getSession()
|
||||
);
|
||||
}
|
||||
// public static JdbcParameterBindings buildJdbcParameterBindings(
|
||||
// SqmStatement sqmStatement,
|
||||
// Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamsXref,
|
||||
// ExecutionContext executionContext) {
|
||||
// final DomainParameterXref domainParameterXref = DomainParameterXref.from( sqmStatement );
|
||||
// return createJdbcParameterBindings(
|
||||
// executionContext.getDomainParameterBindingContext().getQueryParameterBindings(),
|
||||
// domainParameterXref,
|
||||
// jdbcParamsXref,
|
||||
// executionContext.getSession()
|
||||
// );
|
||||
// }
|
||||
|
||||
// public static JdbcParameterBindings buildJdbcParameterBindings(
|
||||
// DomainParameterXref domainParameterXref,
|
||||
// Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamsXref,
|
||||
// ExecutionContext executionContext) {
|
||||
// return createJdbcParameterBindings(
|
||||
// executionContext.getDomainParameterBindingContext().getQueryParameterBindings(),
|
||||
// domainParameterXref,
|
||||
// jdbcParamsXref,
|
||||
// executionContext.getSession()
|
||||
// );
|
||||
// }
|
||||
|
||||
public static JdbcParameterBindings createJdbcParameterBindings(
|
||||
QueryParameterBindings domainParamBindings,
|
||||
DomainParameterXref domainParameterXref,
|
||||
Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamXref,
|
||||
SqlAstCreationState sqlAstCreationState,
|
||||
SharedSessionContractImplementor session) {
|
||||
final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl();
|
||||
|
||||
|
@ -160,16 +163,18 @@ public class SqmUtil {
|
|||
final List<SqmParameter> sqmParameters = entry.getValue();
|
||||
|
||||
final QueryParameterBinding<?> domainParamBinding = domainParamBindings.getBinding( queryParam );
|
||||
final AllowableParameterType<?> parameterType = determineParameterType( domainParamBinding, queryParam, session );
|
||||
final AllowableParameterType<?> parameterType = determineParameterType(
|
||||
domainParamBinding,
|
||||
queryParam,
|
||||
session.getFactory()
|
||||
);
|
||||
|
||||
final Map<SqmParameter, List<JdbcParameter>> jdbcParamMap = jdbcParamXref.get( queryParam );
|
||||
for ( SqmParameter sqmParameter : sqmParameters ) {
|
||||
final List<JdbcParameter> jdbcParams = jdbcParamMap.get( sqmParameter );
|
||||
|
||||
if ( ! domainParamBinding.isBound() ) {
|
||||
final MappingModelExpressable mappingExpressable = session.getFactory()
|
||||
.getDomainModel()
|
||||
.resolveMappingExpressable( parameterType );
|
||||
final MappingModelExpressable mappingExpressable = SqmMappingModelHelper.resolveMappingModelExpressable( sqmParameter, sqlAstCreationState );
|
||||
mappingExpressable.visitJdbcTypes(
|
||||
new Consumer<JdbcMapping>() {
|
||||
int position = 0;
|
||||
|
@ -264,10 +269,10 @@ public class SqmUtil {
|
|||
);
|
||||
}
|
||||
|
||||
private static AllowableParameterType determineParameterType(
|
||||
public static AllowableParameterType determineParameterType(
|
||||
QueryParameterBinding<?> binding,
|
||||
QueryParameterImplementor<?> parameter,
|
||||
SharedSessionContractImplementor session) {
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
if ( binding.getBindType() != null ) {
|
||||
return binding.getBindType();
|
||||
}
|
||||
|
@ -276,7 +281,7 @@ public class SqmUtil {
|
|||
return parameter.getHibernateType();
|
||||
}
|
||||
|
||||
final TypeConfiguration typeConfiguration = session.getFactory().getTypeConfiguration();
|
||||
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
|
||||
|
||||
// assume we have (or can create) a mapping for the parameter's Java type
|
||||
return typeConfiguration.standardBasicTypeForJavaType( parameter.getParameterType() );
|
||||
|
|
|
@ -24,7 +24,10 @@ import org.hibernate.metamodel.mapping.AttributeMapping;
|
|||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.model.domain.AllowableParameterType;
|
||||
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.metamodel.model.domain.internal.EmbeddedSqmPathSource;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.BinaryArithmeticOperator;
|
||||
import org.hibernate.query.UnaryArithmeticOperator;
|
||||
|
@ -740,35 +743,72 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
}
|
||||
|
||||
protected MappingModelExpressable<?> determineValueMapping(SqmExpression<?> sqmExpression) {
|
||||
SqmExpressable<?> nodeType = sqmExpression.getNodeType();
|
||||
|
||||
if ( nodeType == null ) {
|
||||
if ( sqmExpression instanceof SqmParameter ) {
|
||||
final SqmParameter sqmParameter = (SqmParameter) sqmExpression;
|
||||
final QueryParameterBinding<?> binding = domainParameterBindings.getBinding( domainParameterXref.getQueryParameter( sqmParameter ) );
|
||||
assert binding != null;
|
||||
|
||||
nodeType = binding.getBindType();
|
||||
}
|
||||
return determineValueMapping( (SqmParameter) sqmExpression );
|
||||
}
|
||||
|
||||
MappingModelExpressable valueMapping = getCreationContext().getDomainModel().resolveMappingExpressable( nodeType );
|
||||
if ( sqmExpression instanceof SqmPath ) {
|
||||
log.debugf( "Determining mapping-model type for SqmPath : " + sqmExpression );
|
||||
return SqmMappingModelHelper.resolveMappingModelExpressable( sqmExpression, this );
|
||||
}
|
||||
|
||||
|
||||
log.debugf( "Determining mapping-model type for generalized SqmExpression : " + sqmExpression );
|
||||
final SqmExpressable<?> nodeType = sqmExpression.getNodeType();
|
||||
final MappingModelExpressable valueMapping = getCreationContext().getDomainModel().resolveMappingExpressable( nodeType );
|
||||
|
||||
if ( valueMapping == null ) {
|
||||
final Supplier<MappingModelExpressable> currentExpressableSupplier = inferableTypeAccessStack.getCurrent();
|
||||
if ( currentExpressableSupplier != null ) {
|
||||
valueMapping = currentExpressableSupplier.get();
|
||||
return currentExpressableSupplier.get();
|
||||
}
|
||||
}
|
||||
|
||||
if ( valueMapping == null ) {
|
||||
throw new ConversionException( "Could not determine ValueMapping for SqmParameter: " + sqmExpression );
|
||||
throw new ConversionException( "Could not determine ValueMapping for SqmExpression: " + sqmExpression );
|
||||
}
|
||||
|
||||
return valueMapping;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected MappingModelExpressable<?> determineValueMapping(SqmParameter<?> sqmParameter) {
|
||||
log.debugf( "Determining mapping-model type for SqmParameter : " + sqmParameter );
|
||||
|
||||
final QueryParameterImplementor<?> queryParameter = domainParameterXref.getQueryParameter( sqmParameter );
|
||||
final QueryParameterBinding<?> binding = domainParameterBindings.getBinding( queryParameter );
|
||||
|
||||
if ( sqmParameter.getAnticipatedType() == null ) {
|
||||
// this should indicate the condition that the user query did not define an
|
||||
// explicit type in regard to this parameter. Here we should prefer the
|
||||
// inferable type and fallback to the binding type
|
||||
final Supplier<MappingModelExpressable> currentExpressableSupplier = inferableTypeAccessStack.getCurrent();
|
||||
if ( currentExpressableSupplier != null ) {
|
||||
final MappingModelExpressable inferredMapping = currentExpressableSupplier.get();
|
||||
if ( inferredMapping != null ) {
|
||||
return inferredMapping;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AllowableParameterType<?> parameterSqmType = binding.getBindType();
|
||||
if ( parameterSqmType == null ) {
|
||||
parameterSqmType = queryParameter.getHibernateType();
|
||||
if ( parameterSqmType == null ) {
|
||||
parameterSqmType = sqmParameter.getAnticipatedType();
|
||||
}
|
||||
}
|
||||
|
||||
assert parameterSqmType != null;
|
||||
|
||||
if ( parameterSqmType instanceof BasicValuedMapping ) {
|
||||
return (BasicValuedMapping) parameterSqmType;
|
||||
}
|
||||
|
||||
throw new ConversionException( "Could not determine ValueMapping for SqmParameter: " + sqmParameter );
|
||||
}
|
||||
|
||||
private final Stack<Supplier<MappingModelExpressable>> inferableTypeAccessStack = new StandardStack<>(
|
||||
() -> null
|
||||
);
|
||||
|
|
|
@ -33,16 +33,16 @@ public abstract class AbstractSqmExpression<T> extends AbstractJpaSelection<T> i
|
|||
|
||||
@Override
|
||||
public final void applyInferableType(SqmExpressable<?> type) {
|
||||
if ( type == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final SqmExpressable<?> oldType = getNodeType();
|
||||
|
||||
final SqmExpressable<?> newType = highestPrecedenceType( oldType, type );
|
||||
if ( newType != null && newType != oldType ) {
|
||||
internalApplyInferableType( newType );
|
||||
}
|
||||
// if ( type == null ) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// final SqmExpressable<?> oldType = getNodeType();
|
||||
//
|
||||
// final SqmExpressable<?> newType = highestPrecedenceType( oldType, type );
|
||||
// if ( newType != null && newType != oldType ) {
|
||||
// internalApplyInferableType( newType );
|
||||
// }
|
||||
}
|
||||
|
||||
protected void internalApplyInferableType(SqmExpressable<?> newType) {
|
||||
|
|
|
@ -107,7 +107,7 @@ public class SqmEnumLiteral implements SqmExpression<Enum>, SqmExpressable<Enum>
|
|||
@Override
|
||||
public void applyInferableType(SqmExpressable<?> type) {
|
||||
//noinspection unchecked
|
||||
this.expressable = (SqmExpressable) type;
|
||||
// this.expressable = (SqmExpressable) type;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Collection;
|
|||
import java.util.function.Consumer;
|
||||
import javax.persistence.criteria.Expression;
|
||||
|
||||
import org.hibernate.annotations.Remove;
|
||||
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
|
||||
import org.hibernate.metamodel.model.domain.DomainType;
|
||||
import org.hibernate.query.criteria.JpaExpression;
|
||||
|
@ -44,7 +45,11 @@ public interface SqmExpression<T> extends SqmSelectableNode<T>, JpaExpression<T>
|
|||
* @apiNote The SqmExpressable type parameter is dropped here because
|
||||
* the inference could technically cause a change in Java type (i.e.
|
||||
* an implicit cast)
|
||||
*
|
||||
* @deprecated - type inference is now handled during the SQM -> SQL AST transformation
|
||||
*/
|
||||
@Remove
|
||||
@Deprecated
|
||||
void applyInferableType(SqmExpressable<?> type);
|
||||
|
||||
@Override
|
||||
|
|
|
@ -97,7 +97,7 @@ public class SqmFieldLiteral<T> implements SqmExpression<T>, SqmExpressable<T>,
|
|||
@Override
|
||||
public void applyInferableType(SqmExpressable<?> type) {
|
||||
//noinspection unchecked
|
||||
this.expressable = (SqmExpressable) type;
|
||||
// this.expressable = (SqmExpressable) type;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -41,6 +41,11 @@ public class SqmNamedParameter<T> extends AbstractSqmParameter<T> {
|
|||
return ":" + getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SqmNamedParameter(" + getName() + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
|
|
|
@ -49,6 +49,11 @@ public class SqmPositionalParameter<T> extends AbstractSqmParameter<T> {
|
|||
return walker.visitPositionalParameterExpression( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SqmPositionalParameter(" + getPosition() + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asLoggableText() {
|
||||
return "?" + getPosition();
|
||||
|
|
|
@ -232,8 +232,8 @@ public class SqmSubQuery<T> extends AbstractSqmSelectQuery<T> implements SqmSele
|
|||
@Override
|
||||
public void applyInferableType(SqmExpressable<?> type) {
|
||||
//noinspection unchecked
|
||||
this.expressableType = (SqmExpressable) type;
|
||||
setResultType( type == null ? null : type.getExpressableJavaTypeDescriptor().getJavaType() );
|
||||
// this.expressableType = (SqmExpressable) type;
|
||||
// setResultType( type == null ? null : type.getExpressableJavaTypeDescriptor().getJavaType() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.query.hql;
|
||||
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.jpa.spi.JpaCompliance;
|
||||
|
||||
import org.hibernate.testing.junit5.SessionFactoryBasedFunctionalTest;
|
||||
import org.hibernate.testing.orm.domain.helpdesk.HelpDeskDomainModel;
|
||||
import org.hibernate.testing.orm.domain.retail.RetailDomainModel;
|
||||
|
||||
/**
|
||||
* Tests for type inference outside of what JPA says should be supported.
|
||||
*
|
||||
* NOTE : Distinguishing this from {@link JpaStandardSqmInferenceTests} allows
|
||||
* applying {@link JpaCompliance#isJpaQueryComplianceEnabled()} testing for just
|
||||
* these extensions
|
||||
*
|
||||
* @see JpaStandardSqmInferenceTests
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ExtensionSqmInferenceTests extends SessionFactoryBasedFunctionalTest {
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources metadataSources) {
|
||||
super.applyMetadataSources( metadataSources );
|
||||
|
||||
HelpDeskDomainModel.INSTANCE.applyDomainModel( metadataSources );
|
||||
RetailDomainModel.INSTANCE.applyDomainModel( metadataSources );
|
||||
}
|
||||
|
||||
// todo (6.0) : add the checks ;)
|
||||
}
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.query.hql;
|
||||
|
||||
import javax.money.MonetaryAmount;
|
||||
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
|
||||
import org.hibernate.testing.junit5.SessionFactoryBasedFunctionalTest;
|
||||
import org.hibernate.testing.orm.domain.helpdesk.HelpDeskDomainModel;
|
||||
import org.hibernate.testing.orm.domain.helpdesk.Status;
|
||||
import org.hibernate.testing.orm.domain.retail.RetailDomainModel;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests for "type inference specifically limited to the cases JPA
|
||||
* says should be supported.
|
||||
*
|
||||
* @see ExtensionSqmInferenceTests
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class JpaStandardSqmInferenceTests extends SessionFactoryBasedFunctionalTest {
|
||||
protected void applyMetadataSources(MetadataSources metadataSources) {
|
||||
super.applyMetadataSources( metadataSources );
|
||||
|
||||
HelpDeskDomainModel.INSTANCE.applyDomainModel( metadataSources );
|
||||
RetailDomainModel.INSTANCE.applyDomainModel( metadataSources );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnumInference() {
|
||||
checkParameters(
|
||||
"from Account a where a.loginStatus = :status",
|
||||
Status.class
|
||||
);
|
||||
|
||||
checkParameters(
|
||||
"from Account a where a.loginStatus <> :status",
|
||||
Status.class
|
||||
);
|
||||
|
||||
checkParameters(
|
||||
"from Account a where a.loginStatus != :status",
|
||||
Status.class
|
||||
);
|
||||
|
||||
checkParameters(
|
||||
"from Account a where a.loginStatus > :status",
|
||||
Status.class
|
||||
);
|
||||
|
||||
checkParameters(
|
||||
"from Account a where a.loginStatus >= :status",
|
||||
Status.class
|
||||
);
|
||||
|
||||
checkParameters(
|
||||
"from Account a where a.loginStatus < :status",
|
||||
Status.class
|
||||
);
|
||||
|
||||
checkParameters(
|
||||
"from Account a where a.loginStatus <= :status",
|
||||
Status.class
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertedInference() {
|
||||
checkParameters(
|
||||
"select l from LineItem l where l.subTotal = :limit",
|
||||
MonetaryAmount.class
|
||||
);
|
||||
|
||||
checkParameters(
|
||||
"select l from LineItem l where l.subTotal <> :limit",
|
||||
MonetaryAmount.class
|
||||
);
|
||||
|
||||
checkParameters(
|
||||
"select l from LineItem l where l.subTotal != :limit",
|
||||
MonetaryAmount.class
|
||||
);
|
||||
|
||||
checkParameters(
|
||||
"select l from LineItem l where l.subTotal > :limit",
|
||||
MonetaryAmount.class
|
||||
);
|
||||
|
||||
checkParameters(
|
||||
"select l from LineItem l where l.subTotal >= :limit",
|
||||
MonetaryAmount.class
|
||||
);
|
||||
|
||||
checkParameters(
|
||||
"select l from LineItem l where l.subTotal < :limit",
|
||||
MonetaryAmount.class
|
||||
);
|
||||
|
||||
checkParameters(
|
||||
"select l from LineItem l where l.subTotal <= :limit",
|
||||
MonetaryAmount.class
|
||||
);
|
||||
}
|
||||
|
||||
private void checkParameters(String query, Class<?>... expecteds) {
|
||||
final SqmStatement sqmStatement = sessionFactory().getQueryEngine().getHqlTranslator().interpret( query );
|
||||
|
||||
checkParameterTypes( sqmStatement, expecteds );
|
||||
}
|
||||
|
||||
private void checkParameterTypes(SqmStatement<?> sqmStatement, Class<?>[] expectedParameterTypes) {
|
||||
assertEquals( expectedParameterTypes.length, sqmStatement.getSqmParameters().size() );
|
||||
|
||||
int count = 0;
|
||||
for ( SqmParameter<?> queryParameter : sqmStatement.getSqmParameters() ) {
|
||||
assertEquals(
|
||||
"Anticipated type for query parameter [" + queryParameter + "]",
|
||||
expectedParameterTypes[count++],
|
||||
queryParameter.getAnticipatedType().getExpressableJavaTypeDescriptor().getJavaType()
|
||||
);
|
||||
|
||||
// assertThat(
|
||||
// queryParameter.getAnticipatedType().getJavaType(),
|
||||
// AssignableMatcher.assignableTo( expectedParameterTypes[count++] )
|
||||
// );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -74,13 +74,13 @@ public class ParameterTests extends BaseSqmUnitTest {
|
|||
assertThat( sqm.getSqmParameters(), hasSize( 1 ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnticipatedTypeHandling() {
|
||||
final SqmSelectStatement<?> sqm = interpretSelect( "select a.nickName from Person a where a.numberOfToes = ?1" );
|
||||
final SqmParameter parameter = sqm.getSqmParameters().iterator().next();
|
||||
assertThat( parameter.getAnticipatedType(), is( instanceOf( BasicSqmPathSource.class ) ) );
|
||||
assertThat( parameter.allowMultiValuedBinding(), is( false ) );
|
||||
}
|
||||
// @Test
|
||||
// public void testAnticipatedTypeHandling() {
|
||||
// final SqmSelectStatement<?> sqm = interpretSelect( "select a.nickName from Person a where a.numberOfToes = ?1" );
|
||||
// final SqmParameter parameter = sqm.getSqmParameters().iterator().next();
|
||||
// assertThat( parameter.getAnticipatedType(), is( instanceOf( BasicSqmPathSource.class ) ) );
|
||||
// assertThat( parameter.allowMultiValuedBinding(), is( false ) );
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void testAllowMultiValuedBinding() {
|
||||
|
@ -132,14 +132,14 @@ public class ParameterTests extends BaseSqmUnitTest {
|
|||
final SqmSelectStatement<?> sqm = interpretSelect( "select p.id from Person p where p.name.first = :fname" );
|
||||
assertThat( sqm.getSqmParameters().size(), equalTo( 1 ) );
|
||||
final SqmParameter<?> parameter = sqm.getSqmParameters().iterator().next();
|
||||
assertThat( parameter.getAnticipatedType(), instanceOf( BasicSqmPathSource.class ) );
|
||||
// assertThat( parameter.getAnticipatedType(), instanceOf( BasicSqmPathSource.class ) );
|
||||
}
|
||||
|
||||
{
|
||||
final SqmSelectStatement<?> sqm = interpretSelect( "select p.id from Person p where p.name = :name" );
|
||||
assertThat( sqm.getSqmParameters().size(), equalTo( 1 ) );
|
||||
final SqmParameter<?> parameter = sqm.getSqmParameters().iterator().next();
|
||||
assertThat( parameter.getAnticipatedType(), instanceOf( EmbeddedSqmPathSource.class ) );
|
||||
// assertThat( parameter.getAnticipatedType(), instanceOf( EmbeddedSqmPathSource.class ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -182,6 +182,22 @@ public class SmokeTests {
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHqlBasicParameterUsage(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final QueryImplementor<Component> query = session.createQuery(
|
||||
"select e.component from SimpleEntity e where e.component.attribute1 = :param",
|
||||
Component.class
|
||||
);
|
||||
final Component component = query.setParameter( "param", "a1" ).uniqueResult();
|
||||
assertThat( component, notNullValue() );
|
||||
assertThat( component.getAttribute1(), is( "a1" ) );
|
||||
assertThat( component.getAttribute2(), is( "a2" ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Dynamic instantiations
|
||||
|
|
Loading…
Reference in New Issue