HHH-17804 treat 'null in ()' correctly

This commit is contained in:
Gavin King 2024-03-05 00:25:49 +01:00
parent 492e947b4c
commit e7dea589ca
3 changed files with 83 additions and 55 deletions

View File

@ -3255,7 +3255,7 @@ public abstract class AbstractEntityPersister
Map<String, EntityNameUse> entityNameUses,
MappingMetamodelImplementor mappingMetamodel,
String alias) {
final InFragment frag = new InFragment();
final InFragment frag = new InFragment( false );
if ( isDiscriminatorFormula() ) {
frag.setFormula( alias, getDiscriminatorFormulaTemplate() );
}

View File

@ -21,10 +21,15 @@ import org.hibernate.internal.util.StringHelper;
@Internal
public class InFragment {
public InFragment(boolean columnCanBeNull) {
this.columnCanBeNull = columnCanBeNull;
}
public static final String NULL = "null";
public static final String NOT_NULL = "not null";
protected String columnName;
protected boolean columnCanBeNull;
protected List<Object> values = new ArrayList<>();
/**
@ -62,67 +67,80 @@ public class InFragment {
}
public String toFragmentString() {
if ( values.size() == 0 ) {
return "1=2";
}
final StringBuilder buf = new StringBuilder( values.size() * 5 );
StringBuilder buf = new StringBuilder( values.size() * 5 );
if ( values.size() == 1 ) {
Object value = values.get( 0 );
buf.append( columnName );
if ( NULL.equals( value ) ) {
buf.append( " is null" );
}
else {
if ( NOT_NULL.equals( value ) ) {
buf.append( " is not null" );
switch ( values.size() ) {
case 0: {
if ( columnCanBeNull ) {
return buf.append( "(1 = case when " )
.append( columnName )
.append(" is not null then 0 end)")
.toString();
}
else {
buf.append( '=' ).append( value );
return "0=1";
}
}
return buf.toString();
}
case 1: {
Object value = values.get( 0 );
buf.append( columnName );
boolean allowNull = false;
for ( Object value : values ) {
if ( NULL.equals( value ) ) {
allowNull = true;
}
else {
if ( NOT_NULL.equals( value ) ) {
throw new IllegalArgumentException( "not null makes no sense for in expression" );
if ( NULL.equals( value ) ) {
buf.append( " is null" );
}
else {
if ( NOT_NULL.equals( value ) ) {
buf.append( " is not null" );
}
else {
buf.append( '=' ).append( value );
}
}
return buf.toString();
}
default: {
boolean allowNull = false;
for ( Object value : values ) {
if ( NULL.equals( value ) ) {
allowNull = true;
}
else {
if ( NOT_NULL.equals( value ) ) {
throw new IllegalArgumentException( "not null makes no sense for in expression" );
}
}
}
if ( allowNull ) {
buf.append( '(' )
.append( columnName )
.append( " is null or " )
.append( columnName )
.append( " in (" );
}
else {
buf.append( columnName ).append( " in (" );
}
for ( Object value : values ) {
if ( !NULL.equals( value ) ) {
buf.append( value );
buf.append( ", " );
}
}
buf.setLength( buf.length() - 2 );
if ( allowNull ) {
buf.append( "))" );
}
else {
buf.append( ')' );
}
return buf.toString();
}
}
if ( allowNull ) {
buf.append( '(' ).append( columnName ).append( " is null or " ).append( columnName ).append( " in (" );
}
else {
buf.append( columnName ).append( " in (" );
}
for ( Object value : values ) {
if ( !NULL.equals( value ) ) {
buf.append( value );
buf.append( ", " );
}
}
buf.setLength( buf.length() - 2 );
if ( allowNull ) {
buf.append( "))" );
}
else {
buf.append( ')' );
}
return buf.toString();
}
}

View File

@ -7603,7 +7603,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
public void visitInListPredicate(InListPredicate inListPredicate) {
final List<Expression> listExpressions = inListPredicate.getListExpressions();
if ( listExpressions.isEmpty() ) {
appendSql( "1=" + ( inListPredicate.isNegated() ? "1" : "0" ) );
emptyInList( inListPredicate );
return;
}
Function<Expression, Expression> itemAccessor = Function.identity();
@ -7710,6 +7710,16 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
}
}
protected void emptyInList(InListPredicate inListPredicate) {
appendSql("(");
appendSql( inListPredicate.isNegated() ? "0" : "1" );
appendSql(" = case when ");
inListPredicate.getTestExpression().accept( this );
appendSql( " is not null then 0");
// dialect.appendBooleanValueString( this, inListPredicate.isNegated() );
appendSql(" end)");
}
private void appendInClauseSeparator(InListPredicate inListPredicate) {
appendSql( CLOSE_PARENTHESIS );
appendSql( inListPredicate.isNegated() ? " and " : " or " );