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.TIMEZONE_MINUTE;
import static org.hibernate.query.sqm.TemporalUnit.WEEK_OF_MONTH; 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.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.descriptor.DateTimeUtils.DATE_TIME;
import static org.hibernate.type.spi.TypeConfiguration.isJdbcTemporalType; import static org.hibernate.type.spi.TypeConfiguration.isJdbcTemporalType;
@ -2441,7 +2440,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
right = r; right = r;
} }
} }
assertComparable( left, right, creationContext.getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
left, left,
comparisonOperator, comparisonOperator,
@ -2556,10 +2554,10 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
public SqmPredicate visitMemberOfPredicate(HqlParser.MemberOfPredicateContext ctx) { public SqmPredicate visitMemberOfPredicate(HqlParser.MemberOfPredicateContext ctx) {
final boolean negated = ctx.NOT() != null; final boolean negated = ctx.NOT() != null;
final SqmPath<?> sqmPluralPath = consumeDomainPath( ctx.path() ); final SqmPath<?> sqmPluralPath = consumeDomainPath( ctx.path() );
if ( sqmPluralPath.getReferencedPathSource() instanceof PluralPersistentAttribute ) { if ( sqmPluralPath instanceof SqmPluralValuedSimplePath ) {
return new SqmMemberOfPredicate( return new SqmMemberOfPredicate(
(SqmExpression<?>) ctx.expression().accept( this ), (SqmExpression<?>) ctx.expression().accept( this ),
sqmPluralPath, (SqmPluralValuedSimplePath<?>) sqmPluralPath,
negated, negated,
creationContext.getNodeBuilder() creationContext.getNodeBuilder()
); );
@ -2636,7 +2634,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
else if ( inListContext instanceof HqlParser.SubqueryInListContext ) { else if ( inListContext instanceof HqlParser.SubqueryInListContext ) {
final HqlParser.SubqueryInListContext subQueryOrParamInListContext = (HqlParser.SubqueryInListContext) inListContext; final HqlParser.SubqueryInListContext subQueryOrParamInListContext = (HqlParser.SubqueryInListContext) inListContext;
final SqmSubQuery<?> subquery = visitSubquery( subQueryOrParamInListContext.subquery() ); final SqmSubQuery<?> subquery = visitSubquery( subQueryOrParamInListContext.subquery() );
assertComparable( testExpression, subquery, creationContext.getNodeBuilder().getSessionFactory() );
return new SqmInSubQueryPredicate( return new SqmInSubQueryPredicate(
testExpression, testExpression,
subquery, 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.BasicDomainType;
import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.JpaMetamodel; 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.internal.BasicTypeImpl;
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor; import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor; import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.query.BindableType; import org.hibernate.query.BindableType;
import org.hibernate.query.NullPrecedence; import org.hibernate.query.NullPrecedence;
import org.hibernate.query.ReturnableType; import org.hibernate.query.ReturnableType;
import org.hibernate.query.SemanticException;
import org.hibernate.query.SortDirection; import org.hibernate.query.SortDirection;
import org.hibernate.query.criteria.HibernateCriteriaBuilder; import org.hibernate.query.criteria.HibernateCriteriaBuilder;
import org.hibernate.query.criteria.JpaCoalesce; import org.hibernate.query.criteria.JpaCoalesce;
@ -2040,8 +2042,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public <Y extends Comparable<? super Y>> SqmPredicate between(Expression<? extends Y> value, Expression<? extends Y> lower, Expression<? extends Y> upper) { 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( return new SqmBetweenPredicate(
(SqmExpression<? extends Y>) value, (SqmExpression<? extends Y>) value,
(SqmExpression<? extends Y>) lower, (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<? extends Y> valueExpression = (SqmExpression<? extends Y>) value;
final SqmExpression<?> lowerExpr = value( lower, valueExpression ); final SqmExpression<?> lowerExpr = value( lower, valueExpression );
final SqmExpression<?> upperExpr = value( upper, valueExpression ); final SqmExpression<?> upperExpr = value( upper, valueExpression );
assertComparable( valueExpression, lowerExpr, getNodeBuilder().getSessionFactory() );
assertComparable( valueExpression, upperExpr, getNodeBuilder().getSessionFactory() );
return new SqmBetweenPredicate( return new SqmBetweenPredicate(
valueExpression, valueExpression,
lowerExpr, lowerExpr,
@ -2069,7 +2067,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public SqmPredicate equal(Expression<?> x, Expression<?> y) { public SqmPredicate equal(Expression<?> x, Expression<?> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.EQUAL, ComparisonOperator.EQUAL,
@ -2081,7 +2078,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public SqmPredicate equal(Expression<?> x, Object y) { public SqmPredicate equal(Expression<?> x, Object y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x ); final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.EQUAL, ComparisonOperator.EQUAL,
@ -2092,7 +2088,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public SqmPredicate notEqual(Expression<?> x, Expression<?> y) { public SqmPredicate notEqual(Expression<?> x, Expression<?> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.NOT_EQUAL, ComparisonOperator.NOT_EQUAL,
@ -2104,7 +2099,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public SqmPredicate notEqual(Expression<?> x, Object y) { public SqmPredicate notEqual(Expression<?> x, Object y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x ); final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.NOT_EQUAL, ComparisonOperator.NOT_EQUAL,
@ -2115,7 +2109,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public SqmPredicate distinctFrom(Expression<?> x, Expression<?> y) { public SqmPredicate distinctFrom(Expression<?> x, Expression<?> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.DISTINCT_FROM, ComparisonOperator.DISTINCT_FROM,
@ -2127,7 +2120,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public SqmPredicate distinctFrom(Expression<?> x, Object y) { public SqmPredicate distinctFrom(Expression<?> x, Object y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x ); final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.DISTINCT_FROM, ComparisonOperator.DISTINCT_FROM,
@ -2138,7 +2130,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public SqmPredicate notDistinctFrom(Expression<?> x, Expression<?> y) { public SqmPredicate notDistinctFrom(Expression<?> x, Expression<?> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.NOT_DISTINCT_FROM, ComparisonOperator.NOT_DISTINCT_FROM,
@ -2150,7 +2141,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public SqmPredicate notDistinctFrom(Expression<?> x, Object y) { public SqmPredicate notDistinctFrom(Expression<?> x, Object y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x ); final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.NOT_DISTINCT_FROM, ComparisonOperator.NOT_DISTINCT_FROM,
@ -2161,7 +2151,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public <Y extends Comparable<? super Y>> SqmPredicate greaterThan(Expression<? extends Y> x, Expression<? extends Y> y) { public <Y extends Comparable<? super Y>> SqmPredicate greaterThan(Expression<? extends Y> x, Expression<? extends Y> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN, ComparisonOperator.GREATER_THAN,
@ -2173,7 +2162,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public <Y extends Comparable<? super Y>> SqmPredicate greaterThan(Expression<? extends Y> x, Y y) { public <Y extends Comparable<? super Y>> SqmPredicate greaterThan(Expression<? extends Y> x, Y y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x ); final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN, ComparisonOperator.GREATER_THAN,
@ -2184,7 +2172,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public <Y extends Comparable<? super Y>> SqmPredicate greaterThanOrEqualTo(Expression<? extends Y> x, Expression<? extends Y> y) { public <Y extends Comparable<? super Y>> SqmPredicate greaterThanOrEqualTo(Expression<? extends Y> x, Expression<? extends Y> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN_OR_EQUAL, ComparisonOperator.GREATER_THAN_OR_EQUAL,
@ -2196,7 +2183,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public <Y extends Comparable<? super Y>> SqmPredicate greaterThanOrEqualTo(Expression<? extends Y> x, Y y) { public <Y extends Comparable<? super Y>> SqmPredicate greaterThanOrEqualTo(Expression<? extends Y> x, Y y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x ); final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN_OR_EQUAL, ComparisonOperator.GREATER_THAN_OR_EQUAL,
@ -2207,7 +2193,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public <Y extends Comparable<? super Y>> SqmPredicate lessThan(Expression<? extends Y> x, Expression<? extends Y> y) { public <Y extends Comparable<? super Y>> SqmPredicate lessThan(Expression<? extends Y> x, Expression<? extends Y> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.LESS_THAN, ComparisonOperator.LESS_THAN,
@ -2219,7 +2204,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public <Y extends Comparable<? super Y>> SqmPredicate lessThan(Expression<? extends Y> x, Y y) { public <Y extends Comparable<? super Y>> SqmPredicate lessThan(Expression<? extends Y> x, Y y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x ); final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.LESS_THAN, ComparisonOperator.LESS_THAN,
@ -2241,7 +2225,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public <Y extends Comparable<? super Y>> SqmPredicate lessThanOrEqualTo(Expression<? extends Y> x, Y y) { public <Y extends Comparable<? super Y>> SqmPredicate lessThanOrEqualTo(Expression<? extends Y> x, Y y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x ); final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.LESS_THAN_OR_EQUAL, ComparisonOperator.LESS_THAN_OR_EQUAL,
@ -2252,7 +2235,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public SqmPredicate gt(Expression<? extends Number> x, Expression<? extends Number> y) { public SqmPredicate gt(Expression<? extends Number> x, Expression<? extends Number> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN, ComparisonOperator.GREATER_THAN,
@ -2264,7 +2246,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public SqmPredicate gt(Expression<? extends Number> x, Number y) { public SqmPredicate gt(Expression<? extends Number> x, Number y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x ); final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN, ComparisonOperator.GREATER_THAN,
@ -2275,7 +2256,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public SqmPredicate ge(Expression<? extends Number> x, Expression<? extends Number> y) { public SqmPredicate ge(Expression<? extends Number> x, Expression<? extends Number> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN_OR_EQUAL, ComparisonOperator.GREATER_THAN_OR_EQUAL,
@ -2287,7 +2267,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public SqmPredicate ge(Expression<? extends Number> x, Number y) { public SqmPredicate ge(Expression<? extends Number> x, Number y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x ); final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN_OR_EQUAL, ComparisonOperator.GREATER_THAN_OR_EQUAL,
@ -2298,7 +2277,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public SqmPredicate lt(Expression<? extends Number> x, Expression<? extends Number> y) { public SqmPredicate lt(Expression<? extends Number> x, Expression<? extends Number> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.LESS_THAN, ComparisonOperator.LESS_THAN,
@ -2310,7 +2288,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public SqmPredicate lt(Expression<? extends Number> x, Number y) { public SqmPredicate lt(Expression<? extends Number> x, Number y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x ); final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.LESS_THAN, ComparisonOperator.LESS_THAN,
@ -2321,7 +2298,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public SqmPredicate le(Expression<? extends Number> x, Expression<? extends Number> y) { public SqmPredicate le(Expression<? extends Number> x, Expression<? extends Number> y) {
assertComparable( x, y, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.LESS_THAN_OR_EQUAL, ComparisonOperator.LESS_THAN_OR_EQUAL,
@ -2333,7 +2309,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public SqmPredicate le(Expression<? extends Number> x, Number y) { public SqmPredicate le(Expression<? extends Number> x, Number y) {
final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x ); final SqmExpression<?> yExpr = value( y, (SqmExpression<?>) x );
assertComparable( x, yExpr, getNodeBuilder().getSessionFactory() );
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.LESS_THAN_OR_EQUAL, ComparisonOperator.LESS_THAN_OR_EQUAL,
@ -2354,22 +2329,31 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override @Override
public <E, C extends Collection<E>> SqmPredicate isMember(Expression<E> elem, Expression<C> collection) { 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 @Override
public <E, C extends Collection<E>> SqmPredicate isMember(E elem, Expression<C> collection) { 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 @Override
public <E, C extends Collection<E>> SqmPredicate isNotMember(Expression<E> elem, Expression<C> collection) { 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 @Override
public <E, C extends Collection<E>> SqmPredicate isNotMember(E elem, Expression<C> collection) { 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 @Override

View File

@ -22,6 +22,7 @@ import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.UnaryArithmeticOperator; import org.hibernate.query.sqm.UnaryArithmeticOperator;
import org.hibernate.query.sqm.tree.SqmTypedNode; import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.domain.SqmPath; 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.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmLiteralNull; import org.hibernate.query.sqm.tree.expression.SqmLiteralNull;
import org.hibernate.type.BasicType; 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 * 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 * 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 * 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. * to work in Hibernate 5.
* *
* @param lhsType the type of the expression on the LHS of the comparison operator * @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) * @see #isTypeAssignable(SqmPathSource, SqmExpressible, SessionFactoryImplementor)
*/ */
private static boolean areTypesComparable( public static boolean areTypesComparable(
SqmExpressible<?> lhsType, SqmExpressible<?> rhsType, SqmExpressible<?> lhsType, SqmExpressible<?> rhsType,
SessionFactoryImplementor factory) { SessionFactoryImplementor factory) {
@ -321,6 +322,13 @@ public class TypecheckUtil {
&& left.getTupleLength().intValue() != right.getTupleLength().intValue() ) { && left.getTupleLength().intValue() != right.getTupleLength().intValue() ) {
throw new SemanticException( "Cannot compare tuples of different lengths" ); 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 // allow comparing literal null to things
if ( !(left instanceof SqmLiteralNull) && !(right instanceof SqmLiteralNull) ) { if ( !(left instanceof SqmLiteralNull) && !(right instanceof SqmLiteralNull) ) {
final SqmExpressible<?> leftType = left.getNodeType(); 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) { // public static void assertNumeric(SqmExpression<?> expression, BinaryArithmeticOperator op) {
// final SqmExpressible<?> nodeType = expression.getNodeType(); // final SqmExpressible<?> nodeType = expression.getNodeType();
// if ( nodeType != null ) { // 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.SqmCopyContext;
import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.expression.SqmExpression;
import static org.hibernate.query.sqm.internal.TypecheckUtil.assertComparable;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@ -32,6 +34,9 @@ public class SqmBetweenPredicate extends AbstractNegatableSqmPredicate {
this.lowerBound = lowerBound; this.lowerBound = lowerBound;
this.upperBound = upperBound; this.upperBound = upperBound;
assertComparable( expression, lowerBound, nodeBuilder.getSessionFactory() );
assertComparable( expression, upperBound, nodeBuilder.getSessionFactory() );
final SqmExpressible<?> expressibleType = QueryHelper.highestPrecedenceType( final SqmExpressible<?> expressibleType = QueryHelper.highestPrecedenceType(
expression.getExpressible(), expression.getExpressible(),
lowerBound.getExpressible(), lowerBound.getExpressible(),

View File

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

View File

@ -17,6 +17,8 @@ import org.hibernate.query.sqm.tree.select.SqmSubQuery;
import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Expression;
import static org.hibernate.query.sqm.internal.TypecheckUtil.assertComparable;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@ -40,6 +42,8 @@ public class SqmInSubQueryPredicate<T> extends AbstractNegatableSqmPredicate imp
this.testExpression = testExpression; this.testExpression = testExpression;
this.subQueryExpression = subQueryExpression; this.subQueryExpression = subQueryExpression;
assertComparable( testExpression, subQueryExpression, nodeBuilder.getSessionFactory() );
final SqmExpressible<?> expressibleType = QueryHelper.highestPrecedenceType2( final SqmExpressible<?> expressibleType = QueryHelper.highestPrecedenceType2(
testExpression.getExpressible(), testExpression.getExpressible(),
subQueryExpression.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.SqmCopyContext;
import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.expression.SqmExpression;
import static org.hibernate.query.sqm.internal.TypecheckUtil.assertString;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@ -55,8 +57,13 @@ public class SqmLikePredicate extends AbstractNegatableSqmPredicate {
matchExpression.getExpressible(), matchExpression.getExpressible(),
pattern.getExpressible() pattern.getExpressible()
); );
assertString( matchExpression );
assertString( pattern );
matchExpression.applyInferableType( expressibleType ); matchExpression.applyInferableType( expressibleType );
pattern.applyInferableType( expressibleType ); pattern.applyInferableType( expressibleType );
if ( escapeCharacter != null ) { if ( escapeCharacter != null ) {
escapeCharacter.applyInferableType( nodeBuilder.getCharacterType() ); escapeCharacter.applyInferableType( nodeBuilder.getCharacterType() );
} }

View File

@ -6,27 +6,30 @@
*/ */
package org.hibernate.query.sqm.tree.predicate; 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.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmCopyContext; 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.domain.SqmPluralValuedSimplePath;
import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.expression.SqmExpression;
import static org.hibernate.query.sqm.internal.TypecheckUtil.areTypesComparable;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class SqmMemberOfPredicate extends AbstractNegatableSqmPredicate { public class SqmMemberOfPredicate extends AbstractNegatableSqmPredicate {
private final SqmExpression<?> leftHandExpression; 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 ); this( leftHandExpression, pluralPath, false, nodeBuilder );
} }
public SqmMemberOfPredicate( public SqmMemberOfPredicate(
SqmExpression<?> leftHandExpression, SqmExpression<?> leftHandExpression,
SqmPath<?> pluralPath, SqmPluralValuedSimplePath<?> pluralPath,
boolean negated, boolean negated,
NodeBuilder nodeBuilder) { NodeBuilder nodeBuilder) {
super( negated, nodeBuilder ); super( negated, nodeBuilder );
@ -34,9 +37,19 @@ public class SqmMemberOfPredicate extends AbstractNegatableSqmPredicate {
this.pluralPath = pluralPath; this.pluralPath = pluralPath;
this.leftHandExpression = leftHandExpression; this.leftHandExpression = leftHandExpression;
leftHandExpression.applyInferableType( final SimpleDomainType<?> simpleDomainType = pluralPath.getReferencedPathSource().getElementType();
( (SqmPluralValuedSimplePath<?>) 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 @Override
@ -62,7 +75,7 @@ public class SqmMemberOfPredicate extends AbstractNegatableSqmPredicate {
return leftHandExpression; return leftHandExpression;
} }
public SqmPath<?> getPluralPath() { public SqmPluralValuedSimplePath<?> getPluralPath() {
return pluralPath; return pluralPath;
} }

View File

@ -2646,7 +2646,7 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase {
List<Person> persons = entityManager.createQuery( List<Person> persons = entityManager.createQuery(
"select p " + "select p " +
"from Person 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) Person.class)
.getResultList(); .getResultList();
//end::hql-between-predicate-example[] //end::hql-between-predicate-example[]