From 0eb8128d93a05cc1fd53f6762de01b812c161b54 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Sat, 25 May 2024 21:18:52 +0200 Subject: [PATCH] Fix comparison of nullable values In C# an ordered comparison (<, >, <=, >=) between two nullable values always returns a boolean value: if either operand is null, the result is false; otherwise, the result is that of the comparison of the (non-null) values. Fixes #33752 --- .../Query/SqlNullabilityProcessor.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs index c17c378b096..55dc323e588 100644 --- a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs +++ b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs @@ -1327,6 +1327,27 @@ protected virtual SqlExpression VisitSqlBinary( nullable = leftNullable || rightNullable; var result = sqlBinaryExpression.Update(left, right); + if (nullable && !optimize && result.OperatorType + is ExpressionType.GreaterThan + or ExpressionType.GreaterThanOrEqual + or ExpressionType.LessThan + or ExpressionType.LessThanOrEqual) + { + // https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types#lifted-operators + // For the comparison operators <, >, <=, and >=, if one or both + // operands are null, the result is false; otherwise, the contained + // values of operands are compared. + + // if either operand is NULL, the SQL comparison would return NULL; + // to match the C# semantics, replace expr -> COALESCE(expr, FALSE) + + nullable = false; + return _sqlExpressionFactory.Case( + [new(result, _sqlExpressionFactory.Constant(true, result.TypeMapping))], + _sqlExpressionFactory.Constant(false, result.TypeMapping) + ); + } + return result is SqlBinaryExpression sqlBinaryResult && sqlBinaryExpression.OperatorType is ExpressionType.AndAlso or ExpressionType.OrElse ? SimplifyLogicalSqlBinaryExpression(sqlBinaryResult)