Skip to content

Commit

Permalink
Implement translation for XOR (#34071)
Browse files Browse the repository at this point in the history
  • Loading branch information
ranma42 committed Jun 24, 2024
1 parent f1fef24 commit 7e313ab
Show file tree
Hide file tree
Showing 14 changed files with 84 additions and 15 deletions.
9 changes: 7 additions & 2 deletions src/EFCore.Cosmos/Query/Internal/CosmosQuerySqlGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -476,8 +476,8 @@ protected override Expression VisitSqlBinary(SqlBinaryExpression sqlBinaryExpres
// Arithmetic
ExpressionType.Add => " + ",
ExpressionType.Subtract => " - ",
ExpressionType.Multiply => " * " ,
ExpressionType.Divide => " / " ,
ExpressionType.Multiply => " * ",
ExpressionType.Divide => " / ",
ExpressionType.Modulo => " % ",

// Bitwise >>> (zero-fill right shift) not available in C#
Expand Down Expand Up @@ -513,6 +513,11 @@ protected override Expression VisitSqlBinary(SqlBinaryExpression sqlBinaryExpres
{
op = " || ";
}
else if (sqlBinaryExpression.OperatorType == ExpressionType.ExclusiveOr
&& sqlBinaryExpression.Type == typeof(bool))
{
op = " != ";
}

_sqlBuilder.Append(op);

Expand Down
1 change: 1 addition & 0 deletions src/EFCore.Cosmos/Query/Internal/SqlExpressionFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ private SqlExpression ApplyTypeMappingOnSqlBinary(
case ExpressionType.RightShift:
case ExpressionType.And:
case ExpressionType.Or:
case ExpressionType.ExclusiveOr:
case ExpressionType.Coalesce:
{
inferredTypeMapping = typeMapping ?? ExpressionExtensions.InferTypeMapping(left, right);
Expand Down
1 change: 1 addition & 0 deletions src/EFCore.Relational/Query/QuerySqlGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1096,6 +1096,7 @@ protected virtual string GetOperator(SqlBinaryExpression binaryExpression)
ExpressionType.Modulo => " % ",
ExpressionType.And => " & ",
ExpressionType.Or => " | ",
ExpressionType.ExclusiveOr => " ^ ",

_ => throw new UnreachableException($"Unsupported unary OperatorType: {binaryExpression.OperatorType}")
};
Expand Down
1 change: 1 addition & 0 deletions src/EFCore.Relational/Query/SqlExpressionFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ private SqlExpression ApplyTypeMappingOnSqlBinary(
case ExpressionType.Modulo:
case ExpressionType.And:
case ExpressionType.Or:
case ExpressionType.ExclusiveOr:
{
inferredTypeMapping = typeMapping ?? ExpressionExtensions.InferTypeMapping(left, right);
resultType = inferredTypeMapping?.ClrType ?? left.Type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ internal static bool IsValidOperator(ExpressionType operatorType)
case ExpressionType.Equal:
case ExpressionType.NotEqual:
case ExpressionType.Coalesce:
case ExpressionType.ExclusiveOr:
return true;
default:
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,7 @@ protected override bool TryGetOperatorInfo(SqlExpression expression, out int pre
ExpressionType.Subtract => (700, false),
ExpressionType.And => (700, true),
ExpressionType.Or => (700, true),
ExpressionType.ExclusiveOr => (700, true),
ExpressionType.LeftShift => (700, true),
ExpressionType.RightShift => (700, true),
ExpressionType.LessThan => (500, false),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,11 @@ protected override Expression VisitBinary(BinaryExpression binaryExpression)

if (visitedExpression is SqlBinaryExpression sqlBinary)
{
if (sqlBinary.OperatorType == ExpressionType.ExclusiveOr)
{
return QueryCompilationContext.NotTranslatedExpression;
}

if (sqlBinary.OperatorType == ExpressionType.Modulo
&& (ModuloFunctions.TryGetValue(GetProviderType(sqlBinary.Left), out var function)
|| ModuloFunctions.TryGetValue(GetProviderType(sqlBinary.Right), out function)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2369,6 +2369,20 @@ public override Task Where_bitwise_binary_or(bool async)
SELECT c
FROM root c
WHERE ((c["Discriminator"] = "Order") AND ((c["OrderID"] | 10248) = 10248))
""");
});

public override Task Where_bitwise_binary_xor(bool async)
=> Fixture.NoSyncTest(
async, async a =>
{
await base.Where_bitwise_binary_xor(async);
AssertSql(
"""
SELECT c
FROM root c
WHERE ((c["Discriminator"] = "Order") AND ((c["OrderID"] ^ 1) = 10249))
""");
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,21 @@ FROM root c
""");
});

public override async Task Where_bitwise_xor(bool async)
{
// Bitwise operators on booleans. Issue #13168.
Assert.Equal(
CosmosStrings.UnsupportedOperatorForSqlExpression("ExclusiveOr", "SqlBinaryExpression"),
(await Assert.ThrowsAsync<InvalidOperationException>(() => base.Where_bitwise_xor(async))).Message);
[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public override Task Where_bitwise_xor(bool async)
=> Fixture.NoSyncTest(
async, async a =>
{
await base.Where_bitwise_xor(a);

AssertSql();
}
AssertSql(
"""
SELECT c
FROM root c
WHERE ((c["Discriminator"] = "Customer") AND ((c["CustomerID"] = "ALFKI") != true))
""");
});

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3265,6 +3265,16 @@ public virtual Task Where_bitwise_binary_or(bool async)
async,
ss => ss.Set<Order>().Where(o => (o.OrderID | 10248) == 10248));


[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Where_bitwise_binary_xor(bool async)
{
return AssertQuery(
async,
ss => ss.Set<Order>().Where(o => (o.OrderID ^ 1) == 10249));
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Select_bitwise_or_with_logical_or(bool async)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3257,6 +3257,18 @@ FROM [Orders] AS [o]
""");
}

public override async Task Where_bitwise_binary_xor(bool async)
{
await base.Where_bitwise_binary_xor(async);

AssertSql(
"""
SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate]
FROM [Orders] AS [o]
WHERE [o].[OrderID] ^ 1 = 10249
""");
}

public override async Task Select_bitwise_or_with_logical_or(bool async)
{
await base.Select_bitwise_or_with_logical_or(async);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2446,14 +2446,14 @@ public override async Task Projection_when_arithmetic_mixed_subqueries(bool asyn
"""
@__p_0='3'

SELECT CAST([e0].[EmployeeID] AS bigint) + CAST([o0].[OrderID] AS bigint), [e0].[EmployeeID], [e0].[City], [e0].[Country], [e0].[FirstName], [e0].[ReportsTo], [e0].[Title], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate], [o0].[OrderID] % 2
SELECT CAST([e0].[EmployeeID] AS bigint) + CAST([o0].[OrderID] AS bigint) AS [Add], [e0].[Square], [e0].[EmployeeID], [e0].[City], [e0].[Country], [e0].[FirstName], [e0].[ReportsTo], [e0].[Title], 42 AS [Literal], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate], [o0].[OrderID] % 2 AS [Mod]
FROM (
SELECT TOP(@__p_0) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate]
FROM [Orders] AS [o]
ORDER BY [o].[OrderID]
) AS [o0]
CROSS JOIN (
SELECT TOP(2) [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title]
SELECT TOP(2) [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title], [e].[EmployeeID] ^ 2 AS [Square]
FROM [Employees] AS [e]
ORDER BY [e].[EmployeeID]
) AS [e0]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -515,10 +515,17 @@ FROM [Customers] AS [c]

public override async Task Where_bitwise_xor(bool async)
{
// Cannot eval 'where (([c].CustomerID == \"ALFKI\") ^ True)'. Issue #16645.
await AssertTranslationFailed(() => base.Where_bitwise_xor(async));
await base.Where_bitwise_xor(async);

AssertSql();
AssertSql(
"""
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
WHERE CASE
WHEN [c].[CustomerID] = N'ALFKI' THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END ^ CAST(1 AS bit) = CAST(1 AS bit)
""");
}

public override async Task Where_simple_shadow(bool async)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,11 @@ LIMIT @__p_0
""");
}

[ConditionalTheory(Skip = "Issue #16645 bitwise xor support")]
[MemberData(nameof(IsAsyncData))]
public override Task Where_bitwise_binary_xor(bool async)
=> AssertTranslationFailed(() => base.Where_bitwise_binary_xor(async));

public override Task Complex_nested_query_doesnt_try_binding_to_grandparent_when_parent_returns_complex_result(bool async)
=> null;

Expand Down

0 comments on commit 7e313ab

Please sign in to comment.