diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java index 71557754e2..1ba7bc0b3b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java @@ -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 extends HqlParserBaseVisitor implem right = r; } } - assertComparable( left, right, creationContext.getNodeBuilder().getSessionFactory() ); return new SqmComparisonPredicate( left, comparisonOperator, @@ -2556,10 +2554,10 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor 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 extends HqlParserBaseVisitor 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, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java index 3a84be46ff..26b3768cd6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java @@ -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 > SqmPredicate between(Expression value, Expression lower, Expression upper) { - assertComparable( value, lower, getNodeBuilder().getSessionFactory() ); - assertComparable( value, upper, getNodeBuilder().getSessionFactory() ); return new SqmBetweenPredicate( (SqmExpression) value, (SqmExpression) lower, @@ -2056,8 +2056,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, final SqmExpression valueExpression = (SqmExpression) 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 > SqmPredicate greaterThan(Expression x, Expression 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 > SqmPredicate greaterThan(Expression 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 > SqmPredicate greaterThanOrEqualTo(Expression x, Expression 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 > SqmPredicate greaterThanOrEqualTo(Expression 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 > SqmPredicate lessThan(Expression x, Expression 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 > SqmPredicate lessThan(Expression 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 > SqmPredicate lessThanOrEqualTo(Expression 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 x, Expression 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 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 x, Expression 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 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 x, Expression 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 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 x, Expression 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 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 > SqmPredicate isMember(Expression elem, Expression collection) { - return new SqmMemberOfPredicate( (SqmExpression) elem, (SqmPath) collection, false, this ); + return createSqmMemberOfPredicate( (SqmExpression) elem, (SqmPath) collection, false, this ); } @Override public > SqmPredicate isMember(E elem, Expression collection) { - return new SqmMemberOfPredicate( value( elem ), (SqmPath) collection, false, this ); + return createSqmMemberOfPredicate( value( elem ), (SqmPath) collection, false, this ); } @Override public > SqmPredicate isNotMember(Expression elem, Expression collection) { - return new SqmMemberOfPredicate( (SqmExpression) elem, (SqmPath) collection, true, this ); + return createSqmMemberOfPredicate( (SqmExpression) elem, (SqmPath) collection, true, this ); } @Override public > SqmPredicate isNotMember(E elem, Expression 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 diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/TypecheckUtil.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/TypecheckUtil.java index 573efc4c7c..7d270bbe0d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/TypecheckUtil.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/TypecheckUtil.java @@ -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 ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBetweenPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBetweenPredicate.java index 5d1143878d..f015c12a09 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBetweenPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBetweenPredicate.java @@ -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(), diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java index 7496f4ad9f..831a824c3e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java @@ -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 diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInSubQueryPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInSubQueryPredicate.java index 36adafd256..d44532c2df 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInSubQueryPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInSubQueryPredicate.java @@ -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 extends AbstractNegatableSqmPredicate imp this.testExpression = testExpression; this.subQueryExpression = subQueryExpression; + assertComparable( testExpression, subQueryExpression, nodeBuilder.getSessionFactory() ); + final SqmExpressible expressibleType = QueryHelper.highestPrecedenceType2( testExpression.getExpressible(), subQueryExpression.getExpressible() diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmLikePredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmLikePredicate.java index 2bf30950ec..9c6249e942 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmLikePredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmLikePredicate.java @@ -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() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmMemberOfPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmMemberOfPredicate.java index 3c937871db..8276908064 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmMemberOfPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmMemberOfPredicate.java @@ -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,9 +37,19 @@ 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 @@ -62,7 +75,7 @@ public class SqmMemberOfPredicate extends AbstractNegatableSqmPredicate { return leftHandExpression; } - public SqmPath getPluralPath() { + public SqmPluralValuedSimplePath getPluralPath() { return pluralPath; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/HQLTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/HQLTest.java index 4009772d97..aa71355e86 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/HQLTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/HQLTest.java @@ -2646,7 +2646,7 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase { List 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[]