HHH-16801 add HQL 'is true', 'is not true', 'is false', 'is not false' operators

This commit is contained in:
Gavin King 2023-06-24 23:02:43 +02:00
parent 158bf7e697
commit 987a0dfe3c
23 changed files with 337 additions and 28 deletions

View File

@ -622,6 +622,8 @@ predicate
: LEFT_PAREN predicate RIGHT_PAREN # GroupedPredicate
| expression IS NOT? NULL # IsNullPredicate
| expression IS NOT? EMPTY # IsEmptyPredicate
| expression IS NOT? TRUE # IsTruePredicate
| expression IS NOT? FALSE # IsFalsePredicate
| expression NOT? IN inList # InPredicate
| expression NOT? BETWEEN expression AND expression # BetweenPredicate
| expression NOT? (LIKE | ILIKE) expression likeEscape? # LikePredicate

View File

@ -860,6 +860,11 @@ public class DB2Dialect extends Dialect {
return new CteInsertStrategy( rootEntityDescriptor, runtimeModelCreationContext );
}
@Override
public boolean supportsIsTrue() {
return true;
}
@Override
public boolean supportsCurrentTimestampSelection() {
return true;

View File

@ -280,5 +280,4 @@ public class DerbySqlAstTranslator<T extends JdbcOperation> extends AbstractSqlA
appendSql( CLOSE_PARENTHESIS );
}
}
}

View File

@ -2924,6 +2924,18 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
return true;
}
/**
* Does this dialect support the {@code is true} and {@code is false}
* operators?
*
* @return {@code true} if the database supports {@code is true} and
* {@code is false}, or {@code false} if it does not. The
* default is {@code is false}.
*/
public boolean supportsIsTrue() {
return false;
}
/**
* Meant as a means for end users to affect the select strings being sent
* to the database and perhaps manipulate them in some fashion.

View File

@ -591,6 +591,11 @@ public class H2Dialect extends Dialect {
return TimeZoneSupport.NATIVE;
}
@Override
public boolean supportsIsTrue() {
return true;
}
@Override
public void appendBooleanValueString(SqlAppender appender, boolean bool) {
appender.appendSql( bool );

View File

@ -1120,6 +1120,11 @@ public class MySQLDialect extends Dialect {
return 64;
}
@Override
public boolean supportsIsTrue() {
return true;
}
@Override
public boolean supportsCurrentTimestampSelection() {
return true;

View File

@ -19,7 +19,6 @@ import org.hibernate.query.sqm.ComparisonOperator;
import org.hibernate.query.sqm.FetchClauseType;
import org.hibernate.query.sqm.FrameExclusion;
import org.hibernate.query.sqm.FrameKind;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteMaterialization;

View File

@ -891,6 +891,11 @@ public class PostgreSQLDialect extends Dialect {
return true;
}
@Override
public boolean supportsIsTrue() {
return true;
}
@Override
public boolean requiresParensForTupleDistinctCounts() {
return true;

View File

@ -10,7 +10,6 @@ import java.util.List;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.sqm.ComparisonOperator;
import org.hibernate.sql.ast.Clause;
@ -18,7 +17,6 @@ import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;

View File

@ -45,6 +45,7 @@ import org.hibernate.query.sqm.tree.expression.SqmEvery;
import org.hibernate.query.sqm.tree.from.SqmCteJoin;
import org.hibernate.query.sqm.tree.from.SqmDerivedJoin;
import org.hibernate.query.sqm.tree.from.SqmJoin;
import org.hibernate.query.sqm.tree.predicate.SqmTruthnessPredicate;
import org.hibernate.query.sqm.tree.select.SqmSelectQuery;
import org.hibernate.spi.NavigablePath;
import org.hibernate.query.hql.spi.SqmCreationOptions;
@ -1177,6 +1178,16 @@ public class QuerySplitter {
);
}
@Override
public Object visitIsTruePredicate(SqmTruthnessPredicate predicate) {
return new SqmTruthnessPredicate(
(SqmExpression<?>) predicate.getExpression().accept( this ),
predicate.getBooleanValue(),
predicate.isNegated(),
predicate.nodeBuilder()
);
}
@Override
public SqmBetweenPredicate visitBetweenPredicate(SqmBetweenPredicate predicate) {
return new SqmBetweenPredicate(

View File

@ -188,6 +188,7 @@ import org.hibernate.query.sqm.tree.predicate.SqmNegatablePredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmTruthnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.AbstractSqmSelectQuery;
import org.hibernate.query.sqm.tree.select.SqmAliasedNode;
@ -2312,7 +2313,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override
public SqmGroupedPredicate visitGroupedPredicate(HqlParser.GroupedPredicateContext ctx) {
return new SqmGroupedPredicate(
(SqmPredicate) ctx.getChild( 1 ).accept( this ),
(SqmPredicate) ctx.predicate().accept( this ),
creationContext.getNodeBuilder()
);
}
@ -2321,8 +2322,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
public SqmPredicate visitAndPredicate(HqlParser.AndPredicateContext ctx) {
return junction(
Predicate.BooleanOperator.AND,
(SqmPredicate) ctx.getChild( 0 ).accept( this ),
(SqmPredicate) ctx.getChild( 2 ).accept( this )
(SqmPredicate) ctx.predicate( 0 ).accept( this ),
(SqmPredicate) ctx.predicate( 1 ).accept( this )
);
}
@ -2330,8 +2331,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
public SqmPredicate visitOrPredicate(HqlParser.OrPredicateContext ctx) {
return junction(
Predicate.BooleanOperator.OR,
(SqmPredicate) ctx.getChild( 0 ).accept( this ),
(SqmPredicate) ctx.getChild( 2 ).accept( this )
(SqmPredicate) ctx.predicate( 0 ).accept( this ),
(SqmPredicate) ctx.predicate( 1 ).accept( this )
);
}
@ -2360,7 +2361,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override
public SqmPredicate visitNegatedPredicate(HqlParser.NegatedPredicateContext ctx) {
SqmPredicate predicate = (SqmPredicate) ctx.getChild( 1 ).accept( this );
SqmPredicate predicate = (SqmPredicate) ctx.predicate().accept( this );
if ( predicate instanceof SqmNegatablePredicate ) {
( (SqmNegatablePredicate) predicate ).negate();
return predicate;
@ -2372,13 +2373,11 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override
public SqmBetweenPredicate visitBetweenPredicate(HqlParser.BetweenPredicateContext ctx) {
final boolean negated = ( (TerminalNode) ctx.getChild( 1 ) ).getSymbol().getType() == HqlParser.NOT;
final int startIndex = negated ? 3 : 2;
return new SqmBetweenPredicate(
(SqmExpression<?>) ctx.getChild( 0 ).accept( this ),
(SqmExpression<?>) ctx.getChild( startIndex ).accept( this ),
(SqmExpression<?>) ctx.getChild( startIndex + 2 ).accept( this ),
negated,
(SqmExpression<?>) ctx.expression( 0 ).accept( this ),
(SqmExpression<?>) ctx.expression( 1 ).accept( this ),
(SqmExpression<?>) ctx.expression( 2 ).accept( this ),
ctx.NOT() != null,
creationContext.getNodeBuilder()
);
}
@ -2386,22 +2385,20 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override
public SqmNullnessPredicate visitIsNullPredicate(HqlParser.IsNullPredicateContext ctx) {
final boolean negated = ctx.getChildCount() == 4;
return new SqmNullnessPredicate(
(SqmExpression<?>) ctx.expression().accept( this ),
negated,
ctx.NOT() != null,
creationContext.getNodeBuilder()
);
}
@Override
public SqmEmptinessPredicate visitIsEmptyPredicate(HqlParser.IsEmptyPredicateContext ctx) {
final boolean negated = ctx.getChildCount() == 4;
SqmExpression<?> expression = (SqmExpression<?>) ctx.expression().accept(this);
if ( expression instanceof SqmPluralValuedSimplePath ) {
return new SqmEmptinessPredicate(
(SqmPluralValuedSimplePath<?>) expression,
negated,
ctx.NOT() != null,
creationContext.getNodeBuilder()
);
}
@ -2410,6 +2407,26 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
}
}
@Override
public Object visitIsTruePredicate(HqlParser.IsTruePredicateContext ctx) {
return new SqmTruthnessPredicate(
(SqmExpression<?>) ctx.expression().accept( this ),
true,
ctx.NOT() != null,
creationContext.getNodeBuilder()
);
}
@Override
public Object visitIsFalsePredicate(HqlParser.IsFalsePredicateContext ctx) {
return new SqmTruthnessPredicate(
(SqmExpression<?>) ctx.expression().accept( this ),
false,
ctx.NOT() != null,
creationContext.getNodeBuilder()
);
}
@Override
public Object visitComparisonOperator(HqlParser.ComparisonOperatorContext ctx) {
final TerminalNode firstToken = (TerminalNode) ctx.getChild( 0 );

View File

@ -103,6 +103,7 @@ import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmTruthnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
import org.hibernate.query.sqm.tree.select.SqmJpaCompoundSelection;
@ -361,6 +362,8 @@ public interface SemanticQueryWalker<T> {
T visitIsNullPredicate(SqmNullnessPredicate predicate);
T visitIsTruePredicate(SqmTruthnessPredicate predicate);
T visitBetweenPredicate(SqmBetweenPredicate predicate);
T visitLikePredicate(SqmLikePredicate predicate);

View File

@ -94,6 +94,7 @@ import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmTruthnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
import org.hibernate.query.sqm.tree.select.SqmJpaCompoundSelection;
@ -937,6 +938,17 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
return null;
}
@Override
public Object visitIsTruePredicate(SqmTruthnessPredicate predicate) {
processStanza(
(predicate.isNegated() ? "is-not-" : "is-") + predicate.getBooleanValue(),
true,
() -> predicate.getExpression().accept( this )
);
return null;
}
@Override
public Object visitBetweenPredicate(SqmBetweenPredicate predicate) {
processStanza(

View File

@ -93,6 +93,7 @@ import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmTruthnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
import org.hibernate.query.sqm.tree.select.SqmJpaCompoundSelection;
@ -462,6 +463,12 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
return predicate;
}
@Override
public Object visitIsTruePredicate(SqmTruthnessPredicate predicate) {
predicate.getExpression().accept( this );
return predicate;
}
@Override
public Object visitBetweenPredicate(SqmBetweenPredicate predicate) {
predicate.getExpression().accept( this );

View File

@ -261,6 +261,7 @@ import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmTruthnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.SqmAliasedNode;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
@ -365,6 +366,7 @@ import org.hibernate.sql.ast.tree.predicate.NullnessPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.ast.tree.predicate.PredicateCollector;
import org.hibernate.sql.ast.tree.predicate.SelfRenderingPredicate;
import org.hibernate.sql.ast.tree.predicate.ThruthnessPredicate;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -7539,6 +7541,16 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
);
}
@Override
public Object visitIsTruePredicate(SqmTruthnessPredicate predicate) {
return new ThruthnessPredicate(
(Expression) visitWithInferredType( predicate.getExpression(), () -> basicType( Boolean.class )),
predicate.getBooleanValue(),
predicate.isNegated(),
getBooleanType()
);
}
@Override
public Predicate visitInListPredicate(SqmInListPredicate<?> predicate) {
// special case: if there is just a single "value" element and it is a parameter

View File

@ -34,6 +34,7 @@ import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmLikePredicate;
import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmTruthnessPredicate;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
/**
@ -260,6 +261,12 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
return predicate;
}
@Override
public Object visitIsTruePredicate(SqmTruthnessPredicate predicate) {
withTypeInference( null, () -> super.visitIsTruePredicate( predicate ) );
return predicate;
}
@Override
public Object visitComparisonPredicate(SqmComparisonPredicate predicate) {
withTypeInference( predicate.getRightHandExpression(), () -> predicate.getLeftHandExpression().accept( this ) );

View File

@ -0,0 +1,73 @@
/*
* 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.query.sqm.tree.predicate;
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.expression.SqmExpression;
/**
* @author Gavin King
*/
public class SqmTruthnessPredicate extends AbstractNegatableSqmPredicate {
private final SqmExpression<?> expression;
private final boolean value;
public SqmTruthnessPredicate(SqmExpression<?> expression, boolean value, boolean negated, NodeBuilder nodeBuilder) {
super( negated, nodeBuilder );
this.expression = expression;
this.value = value;
}
public boolean getBooleanValue() {
return value;
}
@Override
public SqmTruthnessPredicate copy(SqmCopyContext context) {
final SqmTruthnessPredicate existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmTruthnessPredicate predicate = context.registerCopy(
this,
new SqmTruthnessPredicate(
expression.copy( context ),
getBooleanValue(),
isNegated(),
nodeBuilder()
)
);
copyTo( predicate, context );
return predicate;
}
public SqmExpression<?> getExpression() {
return expression;
}
@Override
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitIsTruePredicate( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
expression.appendHqlString( sb );
sb.append(" is ");
if ( isNegated() ) {
sb.append( "not " );
}
sb.append( getBooleanValue() );
}
@Override
protected SqmNegatablePredicate createNegatedNode() {
return new SqmTruthnessPredicate( expression, getBooleanValue(), !isNegated(), nodeBuilder() );
}
}

View File

@ -62,6 +62,7 @@ import org.hibernate.sql.ast.tree.predicate.LikePredicate;
import org.hibernate.sql.ast.tree.predicate.NegatedPredicate;
import org.hibernate.sql.ast.tree.predicate.NullnessPredicate;
import org.hibernate.sql.ast.tree.predicate.SelfRenderingPredicate;
import org.hibernate.sql.ast.tree.predicate.ThruthnessPredicate;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -202,6 +203,8 @@ public interface SqlAstWalker {
void visitNullnessPredicate(NullnessPredicate nullnessPredicate);
void visitThruthnessPredicate(ThruthnessPredicate predicate);
void visitRelationalPredicate(ComparisonPredicate comparisonPredicate);
void visitSelfRenderingPredicate(SelfRenderingPredicate selfRenderingPredicate);

View File

@ -164,6 +164,7 @@ import org.hibernate.sql.ast.tree.predicate.NegatedPredicate;
import org.hibernate.sql.ast.tree.predicate.NullnessPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.ast.tree.predicate.SelfRenderingPredicate;
import org.hibernate.sql.ast.tree.predicate.ThruthnessPredicate;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -389,7 +390,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
/**
* A lazy session implementation that is needed for rendering literals.
* Usually, only the {@link WrapperOptions} interface is needed,
* but for creating LOBs, it might be to have a full blown session.
* but for creating LOBs, it might be to have a full-blown session.
*/
private static class LazySessionWrapperOptions extends AbstractDelegatingWrapperOptions {
@ -7369,13 +7370,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
@Override
public void visitNullnessPredicate(NullnessPredicate nullnessPredicate) {
final Expression expression = nullnessPredicate.getExpression();
final String predicateValue;
if ( nullnessPredicate.isNegated() ) {
predicateValue = " is not null";
}
else {
predicateValue = " is null";
}
final String predicateValue = nullnessPredicate.isNegated() ? " is not null" : " is null";
final SqlTuple tuple;
if ( ( tuple = SqlTupleContainer.getSqlTuple( expression ) ) != null ) {
String separator = NO_SEPARATOR;
@ -7408,6 +7403,37 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
}
}
@Override
public void visitThruthnessPredicate(ThruthnessPredicate thruthnessPredicate) {
if ( dialect.supportsIsTrue() ) {
thruthnessPredicate.getExpression().accept( this );
appendSql(" is ");
if ( thruthnessPredicate.isNegated() ) {
appendSql("not ");
}
appendSql( thruthnessPredicate.getBooleanValue() );
}
else {
String literalTrue = dialect.toBooleanValueString(true);
String literalFalse = dialect.toBooleanValueString(false);
appendSql("(case ");
thruthnessPredicate.getExpression().accept(this);
appendSql(" when ");
appendSql(thruthnessPredicate.getBooleanValue() ? literalTrue : literalFalse);
appendSql(" then ");
appendSql(thruthnessPredicate.isNegated()? literalFalse : literalTrue);
appendSql(" when ");
appendSql(thruthnessPredicate.getBooleanValue() ? literalFalse : literalTrue);
appendSql(" then ");
appendSql(thruthnessPredicate.isNegated()? literalTrue : literalFalse);
appendSql(" else ");
appendSql(thruthnessPredicate.isNegated()? literalTrue : literalFalse);
appendSql(" end = ");
appendSql(literalTrue);
appendSql(")");
}
}
@Override
public void visitRelationalPredicate(ComparisonPredicate comparisonPredicate) {
// todo (6.0) : do we want to allow multi-valued parameters in a relational predicate?

View File

@ -70,6 +70,7 @@ import org.hibernate.sql.ast.tree.predicate.NegatedPredicate;
import org.hibernate.sql.ast.tree.predicate.NullnessPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.ast.tree.predicate.SelfRenderingPredicate;
import org.hibernate.sql.ast.tree.predicate.ThruthnessPredicate;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -235,6 +236,11 @@ public class AbstractSqlAstWalker implements SqlAstWalker {
nullnessPredicate.getExpression().accept( this );
}
@Override
public void visitThruthnessPredicate(ThruthnessPredicate thruthnessPredicate) {
thruthnessPredicate.getExpression().accept( this );
}
@Override
public void visitRelationalPredicate(ComparisonPredicate comparisonPredicate) {
comparisonPredicate.getLeftHandExpression().accept( this );

View File

@ -68,6 +68,7 @@ import org.hibernate.sql.ast.tree.predicate.NegatedPredicate;
import org.hibernate.sql.ast.tree.predicate.NullnessPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.ast.tree.predicate.SelfRenderingPredicate;
import org.hibernate.sql.ast.tree.predicate.ThruthnessPredicate;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -441,6 +442,22 @@ public class ExpressionReplacementWalker implements SqlAstWalker {
}
}
@Override
public void visitThruthnessPredicate(ThruthnessPredicate thruthnessPredicate) {
final Expression expression = replaceExpression( thruthnessPredicate.getExpression() );
if ( expression != thruthnessPredicate.getExpression() ) {
returnedNode = new ThruthnessPredicate(
expression,
thruthnessPredicate.getBooleanValue(),
thruthnessPredicate.isNegated(),
thruthnessPredicate.getExpressionType()
);
}
else {
returnedNode = thruthnessPredicate;
}
}
@Override
public void visitRelationalPredicate(ComparisonPredicate comparisonPredicate) {
final Expression lhs = replaceExpression( comparisonPredicate.getLeftHandExpression() );

View File

@ -0,0 +1,38 @@
/*
* 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.sql.ast.tree.predicate;
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.tree.expression.Expression;
/**
* @author Gavin King
*/
public class ThruthnessPredicate extends AbstractPredicate {
private final Expression expression;
private final boolean value;
public ThruthnessPredicate(Expression expression, boolean value, boolean negated, JdbcMappingContainer expressionType) {
super( expressionType, negated );
this.expression = expression;
this.value = value;
}
public boolean getBooleanValue() {
return value;
}
public Expression getExpression() {
return expression;
}
@Override
public void accept(SqlAstWalker sqlTreeWalker) {
sqlTreeWalker.visitThruthnessPredicate( this );
}
}

View File

@ -0,0 +1,47 @@
package org.hibernate.orm.test.hql;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.SkipForDialect;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@SessionFactory
@DomainModel
public class BooleanPredicateTest {
@Test void test(SessionFactoryScope scope) {
scope.inSession(session -> {
assertEquals(1, session.createSelectionQuery("select 1 where true is true").getResultList().size());
assertEquals(0, session.createSelectionQuery("select 1 where false is true").getResultList().size());
assertEquals(0, session.createSelectionQuery("select 1 where true is not true").getResultList().size());
assertEquals(1, session.createSelectionQuery("select 1 where false is not true").getResultList().size());
assertEquals(0, session.createSelectionQuery("select 1 where true is false").getResultList().size());
assertEquals(1, session.createSelectionQuery("select 1 where false is false").getResultList().size());
assertEquals(1, session.createSelectionQuery("select 1 where true is not false").getResultList().size());
assertEquals(0, session.createSelectionQuery("select 1 where false is not false").getResultList().size());
});
}
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby doesn't accept literal null in case")
@Test void testNulls(SessionFactoryScope scope) {
scope.inSession(session -> {
assertEquals(1, session.createSelectionQuery("select 1 where true is true").getResultList().size());
assertEquals(0, session.createSelectionQuery("select 1 where false is true").getResultList().size());
assertEquals(0, session.createSelectionQuery("select 1 where null is true").getResultList().size());
assertEquals(0, session.createSelectionQuery("select 1 where true is not true").getResultList().size());
assertEquals(1, session.createSelectionQuery("select 1 where false is not true").getResultList().size());
assertEquals(1, session.createSelectionQuery("select 1 where null is not true").getResultList().size());
assertEquals(0, session.createSelectionQuery("select 1 where true is false").getResultList().size());
assertEquals(1, session.createSelectionQuery("select 1 where false is false").getResultList().size());
assertEquals(0, session.createSelectionQuery("select 1 where null is false").getResultList().size());
assertEquals(1, session.createSelectionQuery("select 1 where true is not false").getResultList().size());
assertEquals(0, session.createSelectionQuery("select 1 where false is not false").getResultList().size());
assertEquals(1, session.createSelectionQuery("select 1 where null is not false").getResultList().size());
});
}
}