Skip to content

Commit

Permalink
Avoid using ^ and ~ on value-converted expressions
Browse files Browse the repository at this point in the history
The transformation of equality/in-equality in a (negated) XOR is only possible
when the expressions are BIT or integer types on the SQL side (i.e. taking value
conversion into account).

Similarly, the Boolean negation `NOT` can be implemented as `~` only if the
underlying expression is a BIT.

Fixes dotnet#35093.
  • Loading branch information
ranma42 committed Nov 28, 2024
1 parent 3769433 commit a40e52c
Showing 1 changed file with 9 additions and 4 deletions.
13 changes: 9 additions & 4 deletions src/EFCore.SqlServer/Query/Internal/SearchConditionConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,11 @@ protected virtual Expression VisitSqlBinary(SqlBinaryExpression binary, bool inS

if (binary.OperatorType is ExpressionType.NotEqual or ExpressionType.Equal)
{
var leftType = newLeft.TypeMapping?.Converter?.ProviderClrType ?? newLeft.Type;
var rightType = newRight.TypeMapping?.Converter?.ProviderClrType ?? newRight.Type;
if (!inSearchConditionContext
&& (newLeft.Type == typeof(bool) || newLeft.Type.IsEnum || newLeft.Type.IsInteger())
&& (newRight.Type == typeof(bool) || newRight.Type.IsEnum || newRight.Type.IsInteger()))
&& (leftType == typeof(bool) || leftType.IsInteger())
&& (rightType == typeof(bool) || rightType.IsInteger()))
{
// "lhs != rhs" is the same as "CAST(lhs ^ rhs AS BIT)", except that
// the first is a boolean, the second is a BIT
Expand Down Expand Up @@ -262,10 +264,13 @@ protected virtual Expression VisitSqlUnary(SqlUnaryExpression sqlUnaryExpression

switch (sqlUnaryExpression.OperatorType)
{
case ExpressionType.Not when sqlUnaryExpression.Type == typeof(bool):
case ExpressionType.Not
when (sqlUnaryExpression.TypeMapping?.Converter?.ProviderClrType ?? sqlUnaryExpression.Type) == typeof(bool):
{
// when possible, avoid converting to/from predicate form
if (!inSearchConditionContext && sqlUnaryExpression.Operand is not (ExistsExpression or InExpression or LikeExpression))
if (!inSearchConditionContext &&
sqlUnaryExpression.TypeMapping?.Converter is null &&
sqlUnaryExpression.Operand is not (ExistsExpression or InExpression or LikeExpression))
{
var negatedOperand = (SqlExpression)Visit(sqlUnaryExpression.Operand);

Expand Down

0 comments on commit a40e52c

Please sign in to comment.