HHH-16768 - Move type compatibility validation to the comparison/between node constructors

Signed-off-by: Jan Schatteman <jschatte@redhat.com>
This commit is contained in:
Jan Schatteman 2023-09-04 17:14:14 +02:00 committed by Jan Schatteman
parent dd9a51a53a
commit 935ac494dd
9 changed files with 83 additions and 47 deletions

View File

@ -256,7 +256,6 @@ import static org.hibernate.query.sqm.TemporalUnit.TIMEZONE_HOUR;
import static org.hibernate.query.sqm.TemporalUnit.TIMEZONE_MINUTE;
import static org.hibernate.query.sqm.TemporalUnit.WEEK_OF_MONTH;
import static org.hibernate.query.sqm.TemporalUnit.WEEK_OF_YEAR;
import static org.hibernate.query.sqm.internal.TypecheckUtil.assertComparable;
import static org.hibernate.type.descriptor.DateTimeUtils.DATE_TIME;
import static org.hibernate.type.spi.TypeConfiguration.isJdbcTemporalType;
@ -2441,7 +2440,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
right = r;
}
}
assertComparable( left, right, creationContext.getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
left,
comparisonOperator,
@ -2556,10 +2554,10 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
public SqmPredicate visitMemberOfPredicate(HqlParser.MemberOfPredicateContext ctx) {
final boolean negated = ctx.NOT() != null;
final SqmPath<?> sqmPluralPath = consumeDomainPath( ctx.path() );
if ( sqmPluralPath.getReferencedPathSource() instanceof PluralPersistentAttribute ) {
if ( sqmPluralPath instanceof SqmPluralValuedSimplePath ) {
return new SqmMemberOfPredicate(
(SqmExpression<?>) ctx.expression().accept( this ),
sqmPluralPath,
(SqmPluralValuedSimplePath<?>) sqmPluralPath,
negated,
creationContext.getNodeBuilder()
);
@ -2636,7 +2634,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
else if ( inListContext instanceof HqlParser.SubqueryInListContext ) {
final HqlParser.SubqueryInListContext subQueryOrParamInListContext = (HqlParser.SubqueryInListContext) inListContext;
final SqmSubQuery<?> subquery = visitSubquery( subQueryOrParamInListContext.subquery() );
assertComparable( testExpression, subquery, creationContext.getNodeBuilder().getSessionFactory() );
return new SqmInSubQueryPredicate(
testExpression,
subquery,

View File

@ -43,12 +43,14 @@ import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.model.domain.BasicDomainType;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.JpaMetamodel;
import org.hibernate.metamodel.model.domain.SimpleDomainType;
import org.hibernate.metamodel.model.domain.internal.BasicTypeImpl;
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.query.BindableType;
import org.hibernate.query.NullPrecedence;
import org.hibernate.query.ReturnableType;
import org.hibernate.query.SemanticException;
import org.hibernate.query.SortDirection;
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
import org.hibernate.query.criteria.JpaCoalesce;
@ -2040,8 +2042,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public <Y extends Comparable<? super Y>> SqmPredicate between(Expression<? extends Y> value, Expression<? extends Y> lower, Expression<? extends Y> upper) {
assertComparable( value, lower, getNodeBuilder().getSessionFactory() );
assertComparable( value, upper, getNodeBuilder().getSessionFactory() );
return new SqmBetweenPredicate(
(SqmExpression<? extends Y>) value,
(SqmExpression<? extends Y>) lower,
@ -2056,8 +2056,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
final SqmExpression<? extends Y> valueExpression = (SqmExpression<? extends Y>) value;
final SqmExpression<?> lowerExpr = value( lower, valueExpression );
final SqmExpression<?> upperExpr = value( upper, valueExpression );
assertComparable( valueExpression, lowerExpr, getNodeBuilder().getSessionFactory() );
assertComparable( valueExpression, upperExpr, getNodeBuilder().getSessionFactory() );
return new SqmBetweenPredicate(
valueExpression,
lowerExpr,
@ -2069,7 +2067,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public SqmPredicate equal(Expression<?> x, Expression<?> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.EQUAL,
@ -2081,7 +2078,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public SqmPredicate equal(Expression<?> x, Object y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.EQUAL,
@ -2092,7 +2088,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public SqmPredicate notEqual(Expression<?> x, Expression<?> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.NOT_EQUAL,
@ -2104,7 +2099,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public SqmPredicate notEqual(Expression<?> x, Object y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.NOT_EQUAL,
@ -2115,7 +2109,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public SqmPredicate distinctFrom(Expression<?> x, Expression<?> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.DISTINCT_FROM,
@ -2127,7 +2120,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public SqmPredicate distinctFrom(Expression<?> x, Object y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.DISTINCT_FROM,
@ -2138,7 +2130,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public SqmPredicate notDistinctFrom(Expression<?> x, Expression<?> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.NOT_DISTINCT_FROM,
@ -2150,7 +2141,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public SqmPredicate notDistinctFrom(Expression<?> x, Object y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.NOT_DISTINCT_FROM,
@ -2161,7 +2151,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public <Y extends Comparable<? super Y>> SqmPredicate greaterThan(Expression<? extends Y> x, Expression<? extends Y> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN,
@ -2173,7 +2162,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public <Y extends Comparable<? super Y>> SqmPredicate greaterThan(Expression<? extends Y> x, Y y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN,
@ -2184,7 +2172,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public <Y extends Comparable<? super Y>> SqmPredicate greaterThanOrEqualTo(Expression<? extends Y> x, Expression<? extends Y> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN_OR_EQUAL,
@ -2196,7 +2183,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public <Y extends Comparable<? super Y>> SqmPredicate greaterThanOrEqualTo(Expression<? extends Y> x, Y y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN_OR_EQUAL,
@ -2207,7 +2193,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public <Y extends Comparable<? super Y>> SqmPredicate lessThan(Expression<? extends Y> x, Expression<? extends Y> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.LESS_THAN,
@ -2219,7 +2204,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public <Y extends Comparable<? super Y>> SqmPredicate lessThan(Expression<? extends Y> x, Y y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.LESS_THAN,
@ -2241,7 +2225,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public <Y extends Comparable<? super Y>> SqmPredicate lessThanOrEqualTo(Expression<? extends Y> x, Y y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.LESS_THAN_OR_EQUAL,
@ -2252,7 +2235,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public SqmPredicate gt(Expression<? extends Number> x, Expression<? extends Number> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN,
@ -2264,7 +2246,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public SqmPredicate gt(Expression<? extends Number> x, Number y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN,
@ -2275,7 +2256,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public SqmPredicate ge(Expression<? extends Number> x, Expression<? extends Number> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN_OR_EQUAL,
@ -2287,7 +2267,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public SqmPredicate ge(Expression<? extends Number> x, Number y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN_OR_EQUAL,
@ -2298,7 +2277,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public SqmPredicate lt(Expression<? extends Number> x, Expression<? extends Number> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.LESS_THAN,
@ -2310,7 +2288,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public SqmPredicate lt(Expression<? extends Number> x, Number y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.LESS_THAN,
@ -2321,7 +2298,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public SqmPredicate le(Expression<? extends Number> x, Expression<? extends Number> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.LESS_THAN_OR_EQUAL,
@ -2333,7 +2309,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public SqmPredicate le(Expression<? extends Number> x, Number y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.LESS_THAN_OR_EQUAL,
@ -2354,22 +2329,31 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public <E, C extends Collection<E>> SqmPredicate isMember(Expression<E> elem, Expression<C> collection) {
return new SqmMemberOfPredicate( (SqmExpression<?>) elem, (SqmPath<?>) collection, false, this );
return createSqmMemberOfPredicate( (SqmExpression<?>) elem, (SqmPath<?>) collection, false, this );
}
@Override
public <E, C extends Collection<E>> SqmPredicate isMember(E elem, Expression<C> collection) {
return new SqmMemberOfPredicate( value( elem ), (SqmPath<?>) collection, false, this );
return createSqmMemberOfPredicate( value( elem ), (SqmPath<?>) collection, false, this );
}
@Override
public <E, C extends Collection<E>> SqmPredicate isNotMember(Expression<E> elem, Expression<C> collection) {
return new SqmMemberOfPredicate( (SqmExpression<?>) elem, (SqmPath<?>) collection, true, this );
return createSqmMemberOfPredicate( (SqmExpression<?>) elem, (SqmPath<?>) collection, true, this );
}
@Override
public <E, C extends Collection<E>> SqmPredicate isNotMember(E elem, Expression<C> collection) {
return new SqmMemberOfPredicate( value( elem ), (SqmPath<?>) collection, true, this );
return createSqmMemberOfPredicate( value( elem ), (SqmPath<?>) collection, true, this );
}
private SqmMemberOfPredicate createSqmMemberOfPredicate(SqmExpression<?> elem, SqmPath<?> collection, boolean negated, NodeBuilder nodeBuilder) {
if ( collection instanceof SqmPluralValuedSimplePath ) {
return new SqmMemberOfPredicate( elem, (SqmPluralValuedSimplePath) collection, negated, this );
}
else {
throw new SemanticException( "Operand of 'member of' operator must be a plural path" );
}
}
@Override

View File

@ -22,6 +22,7 @@ import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.UnaryArithmeticOperator;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmLiteralNull;
import org.hibernate.type.BasicType;
@ -89,7 +90,7 @@ public class TypecheckUtil {
* be done within the framework laid out below, not by adding ad-hoc special
* rules and holes which undermine the type system. It's much more important
* that HQL has simple, predictable, and understandable rules than it is that
* every single user be able to do every single little wierd thing that used
* every single user be able to do every single little weird thing that used
* to work in Hibernate 5.
*
* @param lhsType the type of the expression on the LHS of the comparison operator
@ -97,7 +98,7 @@ public class TypecheckUtil {
*
* @see #isTypeAssignable(SqmPathSource, SqmExpressible, SessionFactoryImplementor)
*/
private static boolean areTypesComparable(
public static boolean areTypesComparable(
SqmExpressible<?> lhsType, SqmExpressible<?> rhsType,
SessionFactoryImplementor factory) {
@ -321,6 +322,13 @@ public class TypecheckUtil {
&& left.getTupleLength().intValue() != right.getTupleLength().intValue() ) {
throw new SemanticException( "Cannot compare tuples of different lengths" );
}
// SqmMemerOfPredicate is the only one allowing multi-valued paths, its comparability is now evaluated in areTypesComparable
// i.e. without calling this method, so we can check this here for other Predicates that do call this
if ( left instanceof SqmPluralValuedSimplePath || right instanceof SqmPluralValuedSimplePath ) {
throw new SemanticException( "Multi valued paths are only allowed for the member of operator" );
}
// allow comparing literal null to things
if ( !(left instanceof SqmLiteralNull) && !(right instanceof SqmLiteralNull) ) {
final SqmExpressible<?> leftType = left.getNodeType();
@ -448,6 +456,17 @@ public class TypecheckUtil {
}
}
public static void assertString(SqmExpression<?> expression) {
final SqmExpressible<?> nodeType = expression.getNodeType();
if ( nodeType != null ) {
final Class<?> javaType = nodeType.getExpressibleJavaType().getJavaTypeClass();
if ( javaType != String.class && javaType != char[].class ) {
throw new SemanticException( "Operand of 'like' is of type '" + nodeType.getTypeName() + "' which is not a string"
+ " (it is not an instance of 'java.lang.String' or 'char[]')" );
}
}
}
// public static void assertNumeric(SqmExpression<?> expression, BinaryArithmeticOperator op) {
// final SqmExpressible<?> nodeType = expression.getNodeType();
// if ( nodeType != null ) {

View File

@ -13,6 +13,8 @@ import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import static org.hibernate.query.sqm.internal.TypecheckUtil.assertComparable;
/**
* @author Steve Ebersole
*/
@ -32,6 +34,9 @@ public class SqmBetweenPredicate extends AbstractNegatableSqmPredicate {
this.lowerBound = lowerBound;
this.upperBound = upperBound;
assertComparable( expression, lowerBound, nodeBuilder.getSessionFactory() );
assertComparable( expression, upperBound, nodeBuilder.getSessionFactory() );
final SqmExpressible<?> expressibleType = QueryHelper.highestPrecedenceType(
expression.getExpressible(),
lowerBound.getExpressible(),

View File

@ -6,14 +6,18 @@
*/
package org.hibernate.query.sqm.tree.predicate;
import org.hibernate.query.SemanticException;
import org.hibernate.query.sqm.ComparisonOperator;
import org.hibernate.query.internal.QueryHelper;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import static org.hibernate.query.sqm.internal.TypecheckUtil.assertComparable;
/**
* @author Steve Ebersole
*/
@ -41,6 +45,8 @@ public class SqmComparisonPredicate extends AbstractNegatableSqmPredicate {
this.rightHandExpression = rightHandExpression;
this.operator = operator;
assertComparable( leftHandExpression, rightHandExpression, nodeBuilder.getSessionFactory() );
final SqmExpressible<?> expressibleType = QueryHelper.highestPrecedenceType(
leftHandExpression.getExpressible(),
rightHandExpression.getExpressible()
@ -55,6 +61,7 @@ public class SqmComparisonPredicate extends AbstractNegatableSqmPredicate {
this.leftHandExpression = affirmativeForm.leftHandExpression;
this.rightHandExpression = affirmativeForm.rightHandExpression;
this.operator = affirmativeForm.operator;
assertComparable( leftHandExpression, rightHandExpression, nodeBuilder().getSessionFactory() );
}
@Override

View File

@ -17,6 +17,8 @@ import org.hibernate.query.sqm.tree.select.SqmSubQuery;
import jakarta.persistence.criteria.Expression;
import static org.hibernate.query.sqm.internal.TypecheckUtil.assertComparable;
/**
* @author Steve Ebersole
*/
@ -40,6 +42,8 @@ public class SqmInSubQueryPredicate<T> extends AbstractNegatableSqmPredicate imp
this.testExpression = testExpression;
this.subQueryExpression = subQueryExpression;
assertComparable( testExpression, subQueryExpression, nodeBuilder.getSessionFactory() );
final SqmExpressible<?> expressibleType = QueryHelper.highestPrecedenceType2(
testExpression.getExpressible(),
subQueryExpression.getExpressible()

View File

@ -13,6 +13,8 @@ import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import static org.hibernate.query.sqm.internal.TypecheckUtil.assertString;
/**
* @author Steve Ebersole
*/
@ -55,8 +57,13 @@ public class SqmLikePredicate extends AbstractNegatableSqmPredicate {
matchExpression.getExpressible(),
pattern.getExpressible()
);
assertString( matchExpression );
assertString( pattern );
matchExpression.applyInferableType( expressibleType );
pattern.applyInferableType( expressibleType );
if ( escapeCharacter != null ) {
escapeCharacter.applyInferableType( nodeBuilder.getCharacterType() );
}

View File

@ -6,27 +6,30 @@
*/
package org.hibernate.query.sqm.tree.predicate;
import org.hibernate.metamodel.model.domain.SimpleDomainType;
import org.hibernate.query.SemanticException;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import static org.hibernate.query.sqm.internal.TypecheckUtil.areTypesComparable;
/**
* @author Steve Ebersole
*/
public class SqmMemberOfPredicate extends AbstractNegatableSqmPredicate {
private final SqmExpression<?> leftHandExpression;
private final SqmPath<?> pluralPath;
private final SqmPluralValuedSimplePath<?> pluralPath;
public SqmMemberOfPredicate(SqmExpression<?> leftHandExpression, SqmPath<?> pluralPath, NodeBuilder nodeBuilder) {
public SqmMemberOfPredicate(SqmExpression<?> leftHandExpression, SqmPluralValuedSimplePath<?> pluralPath, NodeBuilder nodeBuilder) {
this( leftHandExpression, pluralPath, false, nodeBuilder );
}
public SqmMemberOfPredicate(
SqmExpression<?> leftHandExpression,
SqmPath<?> pluralPath,
SqmPluralValuedSimplePath<?> pluralPath,
boolean negated,
NodeBuilder nodeBuilder) {
super( negated, nodeBuilder );
@ -34,11 +37,21 @@ public class SqmMemberOfPredicate extends AbstractNegatableSqmPredicate {
this.pluralPath = pluralPath;
this.leftHandExpression = leftHandExpression;
leftHandExpression.applyInferableType(
( (SqmPluralValuedSimplePath<?>) pluralPath ).getReferencedPathSource().getElementType()
final SimpleDomainType<?> simpleDomainType = pluralPath.getReferencedPathSource().getElementType();
if ( !areTypesComparable(leftHandExpression.getNodeType(), simpleDomainType, nodeBuilder.getSessionFactory()) ) {
throw new SemanticException(
String.format(
"Cannot compare left expression of type '%s' with right expression of type '%s'",
leftHandExpression.getNodeType().getTypeName(),
pluralPath.getNodeType().getTypeName()
)
);
}
leftHandExpression.applyInferableType( simpleDomainType );
}
@Override
public SqmMemberOfPredicate copy(SqmCopyContext context) {
final SqmMemberOfPredicate existing = context.getCopy( this );
@ -62,7 +75,7 @@ public class SqmMemberOfPredicate extends AbstractNegatableSqmPredicate {
return leftHandExpression;
}
public SqmPath<?> getPluralPath() {
public SqmPluralValuedSimplePath<?> getPluralPath() {
return pluralPath;
}

View File

@ -2646,7 +2646,7 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase {
List<Person> persons = entityManager.createQuery(
"select p " +
"from Person p " +
"where p.createdOn between '1999-01-01' and '2001-01-02'",
"where p.createdOn between date 1999-01-01 and date 2001-01-02",
Person.class)
.getResultList();
//end::hql-between-predicate-example[]