diff --git a/src/EFCore.Relational/Query/Internal/SqlExpressionOptimizingExpressionVisitor.cs b/src/EFCore.Relational/Query/Internal/SqlExpressionOptimizingExpressionVisitor.cs index 294d9f5f9d9..47ba1df1242 100644 --- a/src/EFCore.Relational/Query/Internal/SqlExpressionOptimizingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Internal/SqlExpressionOptimizingExpressionVisitor.cs @@ -241,13 +241,11 @@ private SqlExpression SimplifyNullNotNullExpression( // for coalesce: // (a ?? b) == null -> a == null && b == null // (a ?? b) != null -> a != null || b != null - // for AndAlso, OrElse, And, Or we can't do this optimization + // for AndAlso, OrElse we can't do this optimization // we could do something like this, but it seems too complicated: // (a && b) == null -> a == null && b != 0 || a != 0 && b == null if (sqlBinaryOperand.OperatorType != ExpressionType.AndAlso - && sqlBinaryOperand.OperatorType != ExpressionType.OrElse - && sqlBinaryOperand.OperatorType != ExpressionType.And - && sqlBinaryOperand.OperatorType != ExpressionType.Or) + && sqlBinaryOperand.OperatorType != ExpressionType.OrElse) { var newLeft = SimplifyNullNotNullExpression(operatorType, sqlBinaryOperand.Left, typeof(bool), typeMapping); var newRight = SimplifyNullNotNullExpression(operatorType, sqlBinaryOperand.Right, typeof(bool), typeMapping); diff --git a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs index fc0e77dd47d..1ec629e813f 100644 --- a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs @@ -7513,25 +7513,21 @@ public virtual Task OrderBy_StartsWith_with_null_parameter_as_argument(bool isAs public virtual async Task Where_with_enum_flags_parameter(bool isAsync) { MilitaryRank? rank = MilitaryRank.Private; - await AssertQuery( isAsync, ss => ss.Set().Where(g => (g.Rank & rank) == rank)); rank = null; - await AssertQuery( isAsync, ss => ss.Set().Where(g => (g.Rank & rank) == rank)); rank = MilitaryRank.Corporal; - await AssertQuery( isAsync, ss => ss.Set().Where(g => (g.Rank | rank) != rank)); rank = null; - await AssertQuery( isAsync, ss => ss.Set().Where(g => (g.Rank | rank) != rank)); @@ -7547,6 +7543,72 @@ public virtual Task FirstOrDefault_navigation_access_entity_equality_in_where_pr .Where(f => f.Capital == ss.Set().OrderBy(s => s.Nickname).FirstOrDefault().CityOfBirth)); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Bitwise_operation_with_non_null_parameter_optimizes_null_checks(bool isAsync) + { + var ranks = MilitaryRank.Corporal | MilitaryRank.Sergeant | MilitaryRank.General; + + await AssertQuery( + isAsync, + ss => ss.Set().Where(g => (g.Rank & ranks) != 0)); + + await AssertQueryScalar( + isAsync, + ss => ss.Set().Select(g => (g.Rank | ranks) == ranks)); + + await AssertQueryScalar( + isAsync, + ss => ss.Set().Select(g => (g.Rank | (g.Rank | (ranks | (g.Rank | ranks)))) == ranks)); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Bitwise_operation_with_null_arguments(bool isAsync) + { + await AssertQuery( + isAsync, + ss => ss.Set().Where(w => (w.AmmunitionType & AmmunitionType.Cartridge) == null)); + + await AssertQuery( + isAsync, + ss => ss.Set().Where(w => (w.AmmunitionType | AmmunitionType.Shell) == null)); + + AmmunitionType? prm = null; + await AssertQuery( + isAsync, + ss => ss.Set().Where(w => (w.AmmunitionType | AmmunitionType.Shell) == prm)); + + await AssertQuery( + isAsync, + ss => ss.Set().Where(w => (w.AmmunitionType & prm) == prm)); + + prm = AmmunitionType.Shell; + await AssertQuery( + isAsync, + ss => ss.Set().Where(w => (w.AmmunitionType & prm) != 0)); + + prm = AmmunitionType.Cartridge; + await AssertQuery( + isAsync, + ss => ss.Set().Where(w => (w.AmmunitionType & prm) == prm)); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Logical_operation_with_non_null_parameter_optimizes_null_checks(bool isAsync) + { + var prm = true; + await AssertQuery( + isAsync, + ss => ss.Set().Where(g => (g.HasSoulPatch && prm) != prm)); + + prm = false; + await AssertQuery( + isAsync, + ss => ss.Set().Where(g => (g.HasSoulPatch || prm) != prm)); + } + protected async Task AssertTranslationFailed(Func testCode) { Assert.Contains( diff --git a/test/EFCore.Specification.Tests/TestModels/GearsOfWarModel/MilitaryRank.cs b/test/EFCore.Specification.Tests/TestModels/GearsOfWarModel/MilitaryRank.cs index b1565a70584..476fbd27897 100644 --- a/test/EFCore.Specification.Tests/TestModels/GearsOfWarModel/MilitaryRank.cs +++ b/test/EFCore.Specification.Tests/TestModels/GearsOfWarModel/MilitaryRank.cs @@ -8,13 +8,14 @@ namespace Microsoft.EntityFrameworkCore.TestModels.GearsOfWarModel [Flags] public enum MilitaryRank { - Private = 0, - Corporal = 1, - Sergeant = 2, - Lieutenant = 4, - Captain = 8, - Major = 16, - Colonel = 32, - General = 64 + None = 0, + Private = 1, + Corporal = 2, + Sergeant = 4, + Lieutenant = 8, + Captain = 16, + Major = 32, + Colonel = 64, + General = 128 } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index 9c45d62ab35..90f9bb60554 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -364,7 +364,7 @@ public override async Task Where_enum(bool isAsync) AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Rank] = 2)"); +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Rank] = 4)"); } public override async Task Where_nullable_enum_with_constant(bool isAsync) @@ -422,11 +422,11 @@ public override async Task Where_bitwise_and_enum(bool isAsync) AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] & 1) > 0)", +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] & 2) > 0)", // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] & 1) = 1)"); +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] & 2) = 2)"); } public override async Task Where_bitwise_and_integral(bool isAsync) @@ -504,7 +504,7 @@ public override async Task Where_bitwise_or_enum(bool isAsync) AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] | 1) > 0)"); +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] | 2) > 0)"); } public override async Task Bitwise_projects_values_in_select(bool isAsync) @@ -513,14 +513,14 @@ public override async Task Bitwise_projects_values_in_select(bool isAsync) AssertSql( @"SELECT TOP(1) CASE - WHEN ([g].[Rank] & 1) = 1 THEN CAST(1 AS bit) + WHEN ([g].[Rank] & 2) = 2 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [BitwiseTrue], CASE - WHEN ([g].[Rank] & 1) = 2 THEN CAST(1 AS bit) + WHEN ([g].[Rank] & 2) = 4 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) -END AS [BitwiseFalse], [g].[Rank] & 1 AS [BitwiseValue] +END AS [BitwiseFalse], [g].[Rank] & 2 AS [BitwiseValue] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] & 1) = 1)"); +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] & 2) = 2)"); } public override async Task Where_enum_has_flag(bool isAsync) @@ -530,11 +530,11 @@ public override async Task Where_enum_has_flag(bool isAsync) AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] & 1) = 1)", +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] & 2) = 2)", // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] & 9) = 9)", +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] & 18) = 18)", // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] @@ -546,7 +546,7 @@ WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] & 1) = 1)", // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ((1 & [g].[Rank]) = [g].[Rank])"); +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ((2 & [g].[Rank]) = [g].[Rank])"); } public override async Task Where_enum_has_flag_subquery(bool isAsync) @@ -564,19 +564,15 @@ WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId])) OR ([g].[Rank] & ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL AND ( + ORDER BY [g0].[Nickname], [g0].[SquadId])) OR ( SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL))", + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL)", // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (((1 & ( +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (((2 & ( SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') @@ -584,15 +580,11 @@ WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId])) OR (1 & ( + ORDER BY [g0].[Nickname], [g0].[SquadId])) OR ( SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL AND ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL))"); + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL)"); } public override async Task Where_enum_has_flag_subquery_with_pushdown(bool isAsync) @@ -610,19 +602,15 @@ WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId])) OR ([g].[Rank] & ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL AND ( + ORDER BY [g0].[Nickname], [g0].[SquadId])) OR ( SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL))", + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL)", // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (((1 & ( +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (((2 & ( SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') @@ -630,15 +618,11 @@ WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId])) OR (1 & ( + ORDER BY [g0].[Nickname], [g0].[SquadId])) OR ( SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL AND ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL))"); + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL)"); } public override async Task Where_enum_has_flag_subquery_client_eval(bool isAsync) @@ -656,15 +640,11 @@ WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId])) OR ([g].[Rank] & ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL AND ( + ORDER BY [g0].[Nickname], [g0].[SquadId])) OR ( SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL))"); + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL)"); } public override async Task Where_enum_has_flag_with_non_nullable_parameter(bool isAsync) @@ -672,7 +652,7 @@ public override async Task Where_enum_has_flag_with_non_nullable_parameter(bool await base.Where_enum_has_flag_with_non_nullable_parameter(isAsync); AssertSql( - @"@__parameter_0='1' + @"@__parameter_0='2' SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] @@ -684,7 +664,7 @@ public override async Task Where_has_flag_with_nullable_parameter(bool isAsync) await base.Where_has_flag_with_nullable_parameter(isAsync); AssertSql( - @"@__parameter_0='1' (Nullable = true) + @"@__parameter_0='2' (Nullable = true) SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] @@ -697,14 +677,14 @@ public override async Task Select_enum_has_flag(bool isAsync) AssertSql( @"SELECT TOP(1) CASE - WHEN ([g].[Rank] & 1) = 1 THEN CAST(1 AS bit) + WHEN ([g].[Rank] & 2) = 2 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [hasFlagTrue], CASE - WHEN ([g].[Rank] & 2) = 2 THEN CAST(1 AS bit) + WHEN ([g].[Rank] & 4) = 4 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [hasFlagFalse] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] & 1) = 1)"); +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] & 2) = 2)"); } public override async Task Where_count_subquery_without_collision(bool isAsync) @@ -7458,29 +7438,25 @@ public override async Task Where_with_enum_flags_parameter(bool isAsync) await base.Where_with_enum_flags_parameter(isAsync); AssertSql( - @"@__rank_0='0' (Nullable = true) + @"@__rank_0='1' (Nullable = true) SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] & @__rank_0) = @__rank_0)", // - @"@__rank_0=NULL (DbType = Int32) - -SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] + @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND [g].[Rank] & @__rank_0 IS NULL", +WHERE [g].[Discriminator] IN (N'Gear', N'Officer')", // - @"@__rank_0='1' (Nullable = true) + @"@__rank_0='2' (Nullable = true) SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ((([g].[Rank] | @__rank_0) <> @__rank_0) OR [g].[Rank] | @__rank_0 IS NULL)", +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] | @__rank_0) <> @__rank_0)", // - @"@__rank_0=NULL (DbType = Int32) - -SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] + @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND [g].[Rank] | @__rank_0 IS NOT NULL"); +WHERE CAST(0 AS bit) = CAST(1 AS bit)"); } public override async Task FirstOrDefault_navigation_access_entity_equality_in_where_predicate_apply_peneding_selector(bool isAsync) @@ -7504,6 +7480,87 @@ WHERE [g].[Discriminator] IN (N'Gear', N'Officer') ORDER BY [g].[Nickname]) IS NULL))"); } + public override async Task Bitwise_operation_with_non_null_parameter_optimizes_null_checks(bool isAsync) + { + await base.Bitwise_operation_with_non_null_parameter_optimizes_null_checks(isAsync); + + AssertSql( + @"@__ranks_0='134' + +SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] +FROM [Gears] AS [g] +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] & @__ranks_0) <> 0)", + // + @"@__ranks_0='134' + +SELECT CASE + WHEN ([g].[Rank] | @__ranks_0) = @__ranks_0 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END +FROM [Gears] AS [g] +WHERE [g].[Discriminator] IN (N'Gear', N'Officer')", + // + @"@__ranks_0='134' + +SELECT CASE + WHEN ([g].[Rank] | ([g].[Rank] | (@__ranks_0 | ([g].[Rank] | @__ranks_0)))) = @__ranks_0 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END +FROM [Gears] AS [g] +WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); + } + + public override async Task Bitwise_operation_with_null_arguments(bool isAsync) + { + await base.Bitwise_operation_with_null_arguments(isAsync); + + AssertSql( + @"SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] +FROM [Weapons] AS [w] +WHERE [w].[AmmunitionType] IS NULL", + // + @"SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] +FROM [Weapons] AS [w] +WHERE [w].[AmmunitionType] IS NULL", + // + @"SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] +FROM [Weapons] AS [w] +WHERE [w].[AmmunitionType] IS NULL", + // + @"SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] +FROM [Weapons] AS [w]", + // + @"@__prm_0='2' (Nullable = true) + +SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] +FROM [Weapons] AS [w] +WHERE (([w].[AmmunitionType] & @__prm_0) <> 0) OR [w].[AmmunitionType] IS NULL", + // + @"@__prm_0='1' (Nullable = true) + +SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] +FROM [Weapons] AS [w] +WHERE ([w].[AmmunitionType] & @__prm_0) = @__prm_0"); + } + + public override async Task Logical_operation_with_non_null_parameter_optimizes_null_checks(bool isAsync) + { + await base.Logical_operation_with_non_null_parameter_optimizes_null_checks(isAsync); + + AssertSql( + @"@__prm_0='True' + +SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] +FROM [Gears] AS [g] +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] <> @__prm_0)", + // + @"@__prm_0='False' + +SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] +FROM [Gears] AS [g] +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] <> @__prm_0)"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); }