From b1719dcc0c793e94383023ae10de62d9c9cd92e7 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Sun, 19 May 2024 22:52:46 +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 | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs index 07f7c9297f7..014880cac63 100644 --- a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs +++ b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs @@ -1304,6 +1304,28 @@ 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.Coalesce( + result, + _sqlExpressionFactory.Constant(false), + result.TypeMapping + ); + } + return result is SqlBinaryExpression sqlBinaryResult && sqlBinaryExpression.OperatorType is ExpressionType.AndAlso or ExpressionType.OrElse ? SimplifyLogicalSqlBinaryExpression(sqlBinaryResult)