Fix rendering of negated boolean expression predicate

This commit is contained in:
Andrea Boriero 2022-01-26 16:50:29 +01:00 committed by Steve Ebersole
parent 96931d8094
commit b9d4a74693
13 changed files with 205 additions and 2 deletions

View File

@ -54,7 +54,14 @@ public class FirebirdSqlAstTranslator<T extends JdbcOperation> extends AbstractS
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
if ( getDialect().getVersion().isSameOrAfter( 3 ) ) {
final boolean isNegated = booleanExpressionPredicate.isNegated();
if ( isNegated ) {
appendSql( "not(" );
}
booleanExpressionPredicate.getExpression().accept( this );
if ( isNegated ) {
appendSql( CLOSE_PARENTHESIS );
}
}
else {
super.visitBooleanExpressionPredicate( booleanExpressionPredicate );

View File

@ -37,7 +37,19 @@ public class CockroachSqlAstTranslator<T extends JdbcOperation> extends Abstract
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
booleanExpressionPredicate.getExpression().accept( this );
if ( booleanExpressionPredicate.isNegated() ) {
super.visitBooleanExpressionPredicate( booleanExpressionPredicate );
}
else {
final boolean isNegated = booleanExpressionPredicate.isNegated();
if ( isNegated ) {
appendSql( "not(" );
}
booleanExpressionPredicate.getExpression().accept( this );
if ( isNegated ) {
appendSql( CLOSE_PARENTHESIS );
}
}
}
@Override

View File

@ -52,7 +52,14 @@ public class DB2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAst
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
if ( getDB2Version().isSameOrAfter( 11 ) ) {
final boolean isNegated = booleanExpressionPredicate.isNegated();
if ( isNegated ) {
appendSql( "not(" );
}
booleanExpressionPredicate.getExpression().accept( this );
if ( isNegated ) {
appendSql( CLOSE_PARENTHESIS );
}
}
else {
super.visitBooleanExpressionPredicate( booleanExpressionPredicate );

View File

@ -48,7 +48,14 @@ public class DerbySqlAstTranslator<T extends JdbcOperation> extends AbstractSqlA
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
final boolean isNegated = booleanExpressionPredicate.isNegated();
if ( isNegated ) {
appendSql( "not(" );
}
booleanExpressionPredicate.getExpression().accept( this );
if ( isNegated ) {
appendSql( CLOSE_PARENTHESIS );
}
}
// Derby does not allow CASE expressions where all result arms contain plain parameters.

View File

@ -47,7 +47,14 @@ public class H2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstT
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
final boolean isNegated = booleanExpressionPredicate.isNegated();
if ( isNegated ) {
appendSql( "not(" );
}
booleanExpressionPredicate.getExpression().accept( this );
if ( isNegated ) {
appendSql( CLOSE_PARENTHESIS );
}
}
@Override

View File

@ -47,7 +47,14 @@ public class HSQLSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAs
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
final boolean isNegated = booleanExpressionPredicate.isNegated();
if ( isNegated ) {
appendSql( "not(" );
}
booleanExpressionPredicate.getExpression().accept( this );
if ( isNegated ) {
appendSql( CLOSE_PARENTHESIS );
}
}
// HSQL does not allow CASE expressions where all result arms contain plain parameters.

View File

@ -39,7 +39,14 @@ public class MariaDBSqlAstTranslator<T extends JdbcOperation> extends AbstractSq
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
final boolean isNegated = booleanExpressionPredicate.isNegated();
if ( isNegated ) {
appendSql( "not(" );
}
booleanExpressionPredicate.getExpression().accept( this );
if ( isNegated ) {
appendSql( CLOSE_PARENTHESIS );
}
}
@Override

View File

@ -40,7 +40,14 @@ public class MySQLSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlA
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
final boolean isNegated = booleanExpressionPredicate.isNegated();
if ( isNegated ) {
appendSql( "not(" );
}
booleanExpressionPredicate.getExpression().accept( this );
if ( isNegated ) {
appendSql( CLOSE_PARENTHESIS );
}
}
@Override

View File

@ -40,7 +40,14 @@ public class PostgreSQLSqlAstTranslator<T extends JdbcOperation> extends Abstrac
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
final boolean isNegated = booleanExpressionPredicate.isNegated();
if ( isNegated ) {
appendSql( "not(" );
}
booleanExpressionPredicate.getExpression().accept( this );
if ( isNegated ) {
appendSql( CLOSE_PARENTHESIS );
}
}
@Override

View File

@ -40,7 +40,14 @@ public class TiDBSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAs
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
final boolean isNegated = booleanExpressionPredicate.isNegated();
if ( isNegated ) {
appendSql( "not(" );
}
booleanExpressionPredicate.getExpression().accept( this );
if ( isNegated ) {
appendSql( CLOSE_PARENTHESIS );
}
}
protected boolean shouldEmulateFetchClause(QueryPart queryPart) {

View File

@ -13,6 +13,7 @@ import jakarta.persistence.criteria.Expression;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.sql.ast.tree.predicate.NegatedPredicate;
/**
* Represents an expression whose type is boolean, and can therefore be used as a predicate.

View File

@ -4630,7 +4630,13 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
// Most databases do not support boolean expressions in a predicate context, so we render `expr=true`
booleanExpressionPredicate.getExpression().accept( this );
appendSql( '=' );
getDialect().appendBooleanValueString( this, true );
if ( booleanExpressionPredicate.isNegated() ) {
getDialect().appendBooleanValueString( this, false );
}
else {
getDialect().appendBooleanValueString( this, true );
}
}
@Override

View File

@ -0,0 +1,121 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.jpa.compliance;
import java.util.List;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.Jpa;
import org.junit.jupiter.api.Test;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import static org.junit.jupiter.api.Assertions.assertEquals;
@Jpa(
annotatedClasses = {
CriteriaIsFalseTest.Person.class,
CriteriaIsFalseTest.Address.class
}
)
public class CriteriaIsFalseTest {
@Test
public void testIsFalse(EntityManagerFactoryScope scope) {
Address validAddress = new Address( 1, "Lollard street London", true );
Address invalidAddress = new Address( 2, "Oxfort street London", false );
Person personWithValidAddress = new Person( 1, "Luigi", validAddress );
Person personWithInvalidAddredd = new Person( 2, "Andrea", invalidAddress );
scope.inTransaction(
entityManager -> {
entityManager.persist( validAddress );
entityManager.persist( invalidAddress );
entityManager.persist( personWithValidAddress );
entityManager.persist( personWithInvalidAddredd );
}
);
scope.inEntityManager(
entityManager -> {
final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
final CriteriaQuery<Integer> query = criteriaBuilder.createQuery( Integer.class );
final Root<Person> personRoot = query.from( Person.class );
query.select( personRoot.get( "id" ) );
query.where( criteriaBuilder.isFalse( personRoot.get( "address" ).get( "valid" ) ) );
final List<Integer> ids = entityManager.createQuery( query ).getResultList();
assertEquals( 1, ids.size() );
assertEquals( personWithInvalidAddredd.getId(), ids.get( 0 ) );
}
);
}
@Entity(name = "Person")
@Table(name = "PERSON_TABLE")
public static class Person {
@Id
private Integer id;
private String name;
@OneToOne
private Address address;
public Person() {
}
public Person(Integer id, String name, Address address) {
this.id = id;
this.name = name;
this.address = address;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public Address getAddress() {
return address;
}
}
@Entity(name = "Address")
@Table(name = "ADDRESS_TABLE")
public static class Address {
@Id
private Integer id;
private String street;
private boolean valid;
public Address() {
}
public Address(Integer id, String street, boolean valid) {
this.id = id;
this.street = street;
this.valid = valid;
}
}
}