From bc5e8ad130e407f1c600bbab60c619297d5d1f31 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Sun, 23 Jun 2024 20:42:46 +0200 Subject: [PATCH 1/6] Add exhaustive tests for null semantics rewrites --- .../Query/NullSemanticsQueryTestBase.cs | 91 ++ .../Query/NullSemanticsQuerySqlServerTest.cs | 1132 +++++++++++++++++ .../Query/NullSemanticsQuerySqliteTest.cs | 892 +++++++++++++ 3 files changed, 2115 insertions(+) diff --git a/test/EFCore.Relational.Specification.Tests/Query/NullSemanticsQueryTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/NullSemanticsQueryTestBase.cs index ceebfdb3126..8f3c3ecd7df 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/NullSemanticsQueryTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/NullSemanticsQueryTestBase.cs @@ -25,6 +25,97 @@ protected NullSemanticsQueryTestBase(TFixture fixture) { } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Rewrite_compare_int_with_int(bool async) + { + var bools = new bool[] { false, true }; + + foreach (var neq in bools) + { + foreach (var negated in bools) + { + foreach (var nullableB in bools) + { + foreach (var nullableA in bools) + { + var queryBuilder = (ISetSource ss) => + { + var data = nullableA + ? ss.Set().Select(e => new { e.Id, A = e.NullableIntA, e.IntB, e.NullableIntB }) + : ss.Set().Select(e => new { e.Id, A = (int?)e.IntA, e.IntB, e.NullableIntB }); + + var query = nullableB + ? data.Select(e => new { e.Id, e.A, B = e.NullableIntB }) + : data.Select(e => new { e.Id, e.A, B = (int?)e.IntB }); + + var result = neq + ? query.Select(e => new { e.Id, X = e.A != e.B }) + : query.Select(e => new { e.Id, X = e.A == e.B }); + + return negated + ? result.Select(e => new { e.Id, X = !e.X }) + : result; + }; + + await AssertQuery(async, queryBuilder); + await AssertQueryScalar(async, ss => queryBuilder(ss).Where(e => e.X).Select(e => e.Id)); + } + } + } + } + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Rewrite_compare_bool_with_bool(bool async) + { + var bools = new bool[] { false, true }; + + foreach (var neq in bools) + { + foreach (var negated in bools) + { + foreach (var negateB in bools) + { + foreach (var nullableA in bools) + { + foreach (var negateA in bools) + { + foreach (var nullableB in bools) + { + var queryBuilder = (ISetSource ss) => + { + var data = nullableA + ? ss.Set().Select(e => new { e.Id, A = e.NullableBoolA, e.BoolB, e.NullableBoolB }) + : ss.Set().Select(e => new { e.Id, A = (bool?)e.BoolA, e.BoolB, e.NullableBoolB }); + + var query = nullableB + ? data.Select(e => new { e.Id, e.A, B = e.NullableBoolB }) + : data.Select(e => new { e.Id, e.A, B = (bool?)e.BoolB }); + + query = negateA ? query.Select(e => new { e.Id, A = !e.A, e.B }) : query; + query = negateB ? query.Select(e => new { e.Id, e.A, B = !e.B }) : query; + + var result = neq + ? query.Select(e => new { e.Id, X = e.A != e.B }) + : query.Select(e => new { e.Id, X = e.A == e.B }); + + return negated + ? result.Select(e => new { e.Id, X = !e.X }) + : result; + }; + + await AssertQuery(async, queryBuilder); + await AssertQueryScalar(async, ss => queryBuilder(ss).Where(e => e.X).Select(e => e.Id)); + } + } + } + } + } + } + } + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task Compare_bool_with_bool_equal(bool async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs index f6ffe26b610..9c31f926137 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs @@ -16,6 +16,1138 @@ public NullSemanticsQuerySqlServerTest(NullSemanticsQuerySqlServerFixture fixtur Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } + public override async Task Rewrite_compare_int_with_int(bool async) + { + await base.Rewrite_compare_int_with_int(async); + + AssertSql( + """ +SELECT [e].[Id], CASE + WHEN [e].[IntA] = [e].[IntB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[IntA] = [e].[IntB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableIntA] = [e].[IntB] AND [e].[NullableIntA] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableIntA] = [e].[IntB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[IntA] = [e].[NullableIntB] AND [e].[NullableIntB] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[IntA] = [e].[NullableIntB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableIntA] = [e].[NullableIntB] AND [e].[NullableIntA] IS NOT NULL AND [e].[NullableIntB] IS NOT NULL) OR ([e].[NullableIntA] IS NULL AND [e].[NullableIntB] IS NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableIntA] = [e].[NullableIntB] OR ([e].[NullableIntA] IS NULL AND [e].[NullableIntB] IS NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[IntA] <> [e].[IntB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[IntA] <> [e].[IntB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableIntA] <> [e].[IntB] OR [e].[NullableIntA] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableIntA] <> [e].[IntB] OR [e].[NullableIntA] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[IntA] <> [e].[NullableIntB] OR [e].[NullableIntB] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[IntA] <> [e].[NullableIntB] OR [e].[NullableIntB] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableIntA] <> [e].[NullableIntB] OR [e].[NullableIntA] IS NULL OR [e].[NullableIntB] IS NULL) AND ([e].[NullableIntA] IS NOT NULL OR [e].[NullableIntB] IS NOT NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableIntA] <> [e].[NullableIntB] OR [e].[NullableIntA] IS NULL OR [e].[NullableIntB] IS NULL) AND ([e].[NullableIntA] IS NOT NULL OR [e].[NullableIntB] IS NOT NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[IntA] <> [e].[IntB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[IntA] <> [e].[IntB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableIntA] <> [e].[IntB] OR [e].[NullableIntA] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableIntA] <> [e].[IntB] OR [e].[NullableIntA] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[IntA] <> [e].[NullableIntB] OR [e].[NullableIntB] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[IntA] <> [e].[NullableIntB] OR [e].[NullableIntB] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableIntA] <> [e].[NullableIntB] OR [e].[NullableIntA] IS NULL OR [e].[NullableIntB] IS NULL) AND ([e].[NullableIntA] IS NOT NULL OR [e].[NullableIntB] IS NOT NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableIntA] <> [e].[NullableIntB] OR [e].[NullableIntA] IS NULL OR [e].[NullableIntB] IS NULL) AND ([e].[NullableIntA] IS NOT NULL OR [e].[NullableIntB] IS NOT NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[IntA] = [e].[IntB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[IntA] = [e].[IntB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableIntA] = [e].[IntB] AND [e].[NullableIntA] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableIntA] = [e].[IntB] AND [e].[NullableIntA] IS NOT NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[IntA] = [e].[NullableIntB] AND [e].[NullableIntB] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[IntA] = [e].[NullableIntB] AND [e].[NullableIntB] IS NOT NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableIntA] = [e].[NullableIntB] AND [e].[NullableIntA] IS NOT NULL AND [e].[NullableIntB] IS NOT NULL) OR ([e].[NullableIntA] IS NULL AND [e].[NullableIntB] IS NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableIntA] = [e].[NullableIntB] AND [e].[NullableIntA] IS NOT NULL AND [e].[NullableIntB] IS NOT NULL) OR ([e].[NullableIntA] IS NULL AND [e].[NullableIntB] IS NULL) +"""); + } + + public override async Task Rewrite_compare_bool_with_bool(bool async) + { + await base.Rewrite_compare_bool_with_bool(async); + + AssertSql( + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] = [e].[BoolB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] = [e].[BoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] = [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] = [e].[NullableBoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] <> [e].[BoolB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] <> [e].[BoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableBoolA] = [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableBoolA] = [e].[BoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableBoolA] = [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableBoolA] = [e].[NullableBoolB] OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableBoolA] <> [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableBoolA] <> [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableBoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableBoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] <> [e].[BoolB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] <> [e].[BoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] = [e].[BoolB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] = [e].[BoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] = [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] = [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableBoolA] <> [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableBoolA] <> [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableBoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableBoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableBoolA] = [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableBoolA] = [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableBoolA] = [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableBoolA] = [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] <> [e].[BoolB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] <> [e].[BoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] = [e].[BoolB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] = [e].[BoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] = [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] = [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableBoolA] <> [e].[BoolB] OR [e].[NullableBoolA] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableBoolA] <> [e].[BoolB] OR [e].[NullableBoolA] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableBoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolA] IS NULL OR [e].[NullableBoolB] IS NULL) AND ([e].[NullableBoolA] IS NOT NULL OR [e].[NullableBoolB] IS NOT NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableBoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolA] IS NULL OR [e].[NullableBoolB] IS NULL) AND ([e].[NullableBoolA] IS NOT NULL OR [e].[NullableBoolB] IS NOT NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableBoolA] = [e].[BoolB] OR [e].[NullableBoolA] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableBoolA] = [e].[BoolB] OR [e].[NullableBoolA] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableBoolA] = [e].[NullableBoolB] OR [e].[NullableBoolA] IS NULL OR [e].[NullableBoolB] IS NULL) AND ([e].[NullableBoolA] IS NOT NULL OR [e].[NullableBoolB] IS NOT NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableBoolA] = [e].[NullableBoolB] OR [e].[NullableBoolA] IS NULL OR [e].[NullableBoolB] IS NULL) AND ([e].[NullableBoolA] IS NOT NULL OR [e].[NullableBoolB] IS NOT NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] = [e].[BoolB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] = [e].[BoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] = [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] = [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] <> [e].[BoolB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] <> [e].[BoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableBoolA] = [e].[BoolB] OR [e].[NullableBoolA] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableBoolA] = [e].[BoolB] OR [e].[NullableBoolA] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableBoolA] = [e].[NullableBoolB] OR [e].[NullableBoolA] IS NULL OR [e].[NullableBoolB] IS NULL) AND ([e].[NullableBoolA] IS NOT NULL OR [e].[NullableBoolB] IS NOT NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableBoolA] = [e].[NullableBoolB] OR [e].[NullableBoolA] IS NULL OR [e].[NullableBoolB] IS NULL) AND ([e].[NullableBoolA] IS NOT NULL OR [e].[NullableBoolB] IS NOT NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableBoolA] <> [e].[BoolB] OR [e].[NullableBoolA] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableBoolA] <> [e].[BoolB] OR [e].[NullableBoolA] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableBoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolA] IS NULL OR [e].[NullableBoolB] IS NULL) AND ([e].[NullableBoolA] IS NOT NULL OR [e].[NullableBoolB] IS NOT NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableBoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolA] IS NULL OR [e].[NullableBoolB] IS NULL) AND ([e].[NullableBoolA] IS NOT NULL OR [e].[NullableBoolB] IS NOT NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] <> [e].[BoolB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] <> [e].[BoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] = [e].[BoolB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] = [e].[BoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] = [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] = [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableBoolA] <> [e].[BoolB] OR [e].[NullableBoolA] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableBoolA] <> [e].[BoolB] OR [e].[NullableBoolA] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableBoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolA] IS NULL OR [e].[NullableBoolB] IS NULL) AND ([e].[NullableBoolA] IS NOT NULL OR [e].[NullableBoolB] IS NOT NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableBoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolA] IS NULL OR [e].[NullableBoolB] IS NULL) AND ([e].[NullableBoolA] IS NOT NULL OR [e].[NullableBoolB] IS NOT NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableBoolA] = [e].[BoolB] OR [e].[NullableBoolA] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableBoolA] = [e].[BoolB] OR [e].[NullableBoolA] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableBoolA] = [e].[NullableBoolB] OR [e].[NullableBoolA] IS NULL OR [e].[NullableBoolB] IS NULL) AND ([e].[NullableBoolA] IS NOT NULL OR [e].[NullableBoolB] IS NOT NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableBoolA] = [e].[NullableBoolB] OR [e].[NullableBoolA] IS NULL OR [e].[NullableBoolB] IS NULL) AND ([e].[NullableBoolA] IS NOT NULL OR [e].[NullableBoolB] IS NOT NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] = [e].[BoolB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] = [e].[BoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] = [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] = [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] <> [e].[BoolB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] <> [e].[BoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableBoolA] = [e].[BoolB] OR [e].[NullableBoolA] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableBoolA] = [e].[BoolB] OR [e].[NullableBoolA] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableBoolA] = [e].[NullableBoolB] OR [e].[NullableBoolA] IS NULL OR [e].[NullableBoolB] IS NULL) AND ([e].[NullableBoolA] IS NOT NULL OR [e].[NullableBoolB] IS NOT NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableBoolA] = [e].[NullableBoolB] OR [e].[NullableBoolA] IS NULL OR [e].[NullableBoolB] IS NULL) AND ([e].[NullableBoolA] IS NOT NULL OR [e].[NullableBoolB] IS NOT NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableBoolA] <> [e].[BoolB] OR [e].[NullableBoolA] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableBoolA] <> [e].[BoolB] OR [e].[NullableBoolA] IS NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableBoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolA] IS NULL OR [e].[NullableBoolB] IS NULL) AND ([e].[NullableBoolA] IS NOT NULL OR [e].[NullableBoolB] IS NOT NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableBoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolA] IS NULL OR [e].[NullableBoolB] IS NULL) AND ([e].[NullableBoolA] IS NOT NULL OR [e].[NullableBoolB] IS NOT NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] = [e].[BoolB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] = [e].[BoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] = [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] = [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] <> [e].[BoolB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] <> [e].[BoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableBoolA] = [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableBoolA] = [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableBoolA] = [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableBoolA] = [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableBoolA] <> [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableBoolA] <> [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableBoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableBoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] <> [e].[BoolB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] <> [e].[BoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] = [e].[BoolB] THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] = [e].[BoolB] +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[BoolA] = [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[BoolA] = [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableBoolA] <> [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableBoolA] <> [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableBoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableBoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) +""", + // + """ +SELECT [e].[Id], CASE + WHEN [e].[NullableBoolA] = [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE [e].[NullableBoolA] = [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL +""", + // + """ +SELECT [e].[Id], CASE + WHEN ([e].[NullableBoolA] = [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [X] +FROM [Entities1] AS [e] +""", + // + """ +SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ([e].[NullableBoolA] = [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) +"""); + } + public override async Task Compare_bool_with_bool_equal(bool async) { await base.Compare_bool_with_bool_equal(async); diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/NullSemanticsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/NullSemanticsQuerySqliteTest.cs index d5e16911667..e5e4fa04790 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/NullSemanticsQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/NullSemanticsQuerySqliteTest.cs @@ -17,6 +17,898 @@ public NullSemanticsQuerySqliteTest(NullSemanticsQuerySqliteFixture fixture, ITe //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } + public override async Task Rewrite_compare_int_with_int(bool async) + { + await base.Rewrite_compare_int_with_int(async); + + AssertSql( + """ +SELECT "e"."Id", "e"."IntA" = "e"."IntB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."IntA" = "e"."IntB" +""", + // + """ +SELECT "e"."Id", "e"."NullableIntA" = "e"."IntB" AND "e"."NullableIntA" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableIntA" = "e"."IntB" +""", + // + """ +SELECT "e"."Id", "e"."IntA" = "e"."NullableIntB" AND "e"."NullableIntB" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."IntA" = "e"."NullableIntB" +""", + // + """ +SELECT "e"."Id", ("e"."NullableIntA" = "e"."NullableIntB" AND "e"."NullableIntA" IS NOT NULL AND "e"."NullableIntB" IS NOT NULL) OR ("e"."NullableIntA" IS NULL AND "e"."NullableIntB" IS NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableIntA" = "e"."NullableIntB" OR ("e"."NullableIntA" IS NULL AND "e"."NullableIntB" IS NULL) +""", + // + """ +SELECT "e"."Id", "e"."IntA" <> "e"."IntB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."IntA" <> "e"."IntB" +""", + // + """ +SELECT "e"."Id", "e"."NullableIntA" <> "e"."IntB" OR "e"."NullableIntA" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableIntA" <> "e"."IntB" OR "e"."NullableIntA" IS NULL +""", + // + """ +SELECT "e"."Id", "e"."IntA" <> "e"."NullableIntB" OR "e"."NullableIntB" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."IntA" <> "e"."NullableIntB" OR "e"."NullableIntB" IS NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableIntA" <> "e"."NullableIntB" OR "e"."NullableIntA" IS NULL OR "e"."NullableIntB" IS NULL) AND ("e"."NullableIntA" IS NOT NULL OR "e"."NullableIntB" IS NOT NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableIntA" <> "e"."NullableIntB" OR "e"."NullableIntA" IS NULL OR "e"."NullableIntB" IS NULL) AND ("e"."NullableIntA" IS NOT NULL OR "e"."NullableIntB" IS NOT NULL) +""", + // + """ +SELECT "e"."Id", "e"."IntA" <> "e"."IntB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."IntA" <> "e"."IntB" +""", + // + """ +SELECT "e"."Id", "e"."NullableIntA" <> "e"."IntB" OR "e"."NullableIntA" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableIntA" <> "e"."IntB" OR "e"."NullableIntA" IS NULL +""", + // + """ +SELECT "e"."Id", "e"."IntA" <> "e"."NullableIntB" OR "e"."NullableIntB" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."IntA" <> "e"."NullableIntB" OR "e"."NullableIntB" IS NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableIntA" <> "e"."NullableIntB" OR "e"."NullableIntA" IS NULL OR "e"."NullableIntB" IS NULL) AND ("e"."NullableIntA" IS NOT NULL OR "e"."NullableIntB" IS NOT NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableIntA" <> "e"."NullableIntB" OR "e"."NullableIntA" IS NULL OR "e"."NullableIntB" IS NULL) AND ("e"."NullableIntA" IS NOT NULL OR "e"."NullableIntB" IS NOT NULL) +""", + // + """ +SELECT "e"."Id", "e"."IntA" = "e"."IntB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."IntA" = "e"."IntB" +""", + // + """ +SELECT "e"."Id", "e"."NullableIntA" = "e"."IntB" AND "e"."NullableIntA" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableIntA" = "e"."IntB" AND "e"."NullableIntA" IS NOT NULL +""", + // + """ +SELECT "e"."Id", "e"."IntA" = "e"."NullableIntB" AND "e"."NullableIntB" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."IntA" = "e"."NullableIntB" AND "e"."NullableIntB" IS NOT NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableIntA" = "e"."NullableIntB" AND "e"."NullableIntA" IS NOT NULL AND "e"."NullableIntB" IS NOT NULL) OR ("e"."NullableIntA" IS NULL AND "e"."NullableIntB" IS NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableIntA" = "e"."NullableIntB" AND "e"."NullableIntA" IS NOT NULL AND "e"."NullableIntB" IS NOT NULL) OR ("e"."NullableIntA" IS NULL AND "e"."NullableIntB" IS NULL) +"""); + } + + public override async Task Rewrite_compare_bool_with_bool(bool async) + { + await base.Rewrite_compare_bool_with_bool(async); + + AssertSql( + """ +SELECT "e"."Id", "e"."BoolA" = "e"."BoolB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" = "e"."BoolB" +""", + // + """ +SELECT "e"."Id", "e"."BoolA" = "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" = "e"."NullableBoolB" +""", + // + """ +SELECT "e"."Id", "e"."BoolA" <> "e"."BoolB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" <> "e"."BoolB" +""", + // + """ +SELECT "e"."Id", "e"."BoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL +""", + // + """ +SELECT "e"."Id", "e"."NullableBoolA" = "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableBoolA" = "e"."BoolB" +""", + // + """ +SELECT "e"."Id", ("e"."NullableBoolA" = "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableBoolA" = "e"."NullableBoolB" OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) +""", + // + """ +SELECT "e"."Id", "e"."NullableBoolA" <> "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableBoolA" <> "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableBoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableBoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) +""", + // + """ +SELECT "e"."Id", "e"."BoolA" <> "e"."BoolB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" <> "e"."BoolB" +""", + // + """ +SELECT "e"."Id", "e"."BoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL +""", + // + """ +SELECT "e"."Id", "e"."BoolA" = "e"."BoolB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" = "e"."BoolB" +""", + // + """ +SELECT "e"."Id", "e"."BoolA" = "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" = "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL +""", + // + """ +SELECT "e"."Id", "e"."NullableBoolA" <> "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableBoolA" <> "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableBoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableBoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) +""", + // + """ +SELECT "e"."Id", "e"."NullableBoolA" = "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableBoolA" = "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableBoolA" = "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableBoolA" = "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) +""", + // + """ +SELECT "e"."Id", "e"."BoolA" <> "e"."BoolB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" <> "e"."BoolB" +""", + // + """ +SELECT "e"."Id", "e"."BoolA" <> "e"."NullableBoolB" OR "e"."NullableBoolB" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" <> "e"."NullableBoolB" OR "e"."NullableBoolB" IS NULL +""", + // + """ +SELECT "e"."Id", "e"."BoolA" = "e"."BoolB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" = "e"."BoolB" +""", + // + """ +SELECT "e"."Id", "e"."BoolA" = "e"."NullableBoolB" OR "e"."NullableBoolB" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" = "e"."NullableBoolB" OR "e"."NullableBoolB" IS NULL +""", + // + """ +SELECT "e"."Id", "e"."NullableBoolA" <> "e"."BoolB" OR "e"."NullableBoolA" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableBoolA" <> "e"."BoolB" OR "e"."NullableBoolA" IS NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableBoolA" <> "e"."NullableBoolB" OR "e"."NullableBoolA" IS NULL OR "e"."NullableBoolB" IS NULL) AND ("e"."NullableBoolA" IS NOT NULL OR "e"."NullableBoolB" IS NOT NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableBoolA" <> "e"."NullableBoolB" OR "e"."NullableBoolA" IS NULL OR "e"."NullableBoolB" IS NULL) AND ("e"."NullableBoolA" IS NOT NULL OR "e"."NullableBoolB" IS NOT NULL) +""", + // + """ +SELECT "e"."Id", "e"."NullableBoolA" = "e"."BoolB" OR "e"."NullableBoolA" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableBoolA" = "e"."BoolB" OR "e"."NullableBoolA" IS NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableBoolA" = "e"."NullableBoolB" OR "e"."NullableBoolA" IS NULL OR "e"."NullableBoolB" IS NULL) AND ("e"."NullableBoolA" IS NOT NULL OR "e"."NullableBoolB" IS NOT NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableBoolA" = "e"."NullableBoolB" OR "e"."NullableBoolA" IS NULL OR "e"."NullableBoolB" IS NULL) AND ("e"."NullableBoolA" IS NOT NULL OR "e"."NullableBoolB" IS NOT NULL) +""", + // + """ +SELECT "e"."Id", "e"."BoolA" = "e"."BoolB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" = "e"."BoolB" +""", + // + """ +SELECT "e"."Id", "e"."BoolA" = "e"."NullableBoolB" OR "e"."NullableBoolB" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" = "e"."NullableBoolB" OR "e"."NullableBoolB" IS NULL +""", + // + """ +SELECT "e"."Id", "e"."BoolA" <> "e"."BoolB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" <> "e"."BoolB" +""", + // + """ +SELECT "e"."Id", "e"."BoolA" <> "e"."NullableBoolB" OR "e"."NullableBoolB" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" <> "e"."NullableBoolB" OR "e"."NullableBoolB" IS NULL +""", + // + """ +SELECT "e"."Id", "e"."NullableBoolA" = "e"."BoolB" OR "e"."NullableBoolA" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableBoolA" = "e"."BoolB" OR "e"."NullableBoolA" IS NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableBoolA" = "e"."NullableBoolB" OR "e"."NullableBoolA" IS NULL OR "e"."NullableBoolB" IS NULL) AND ("e"."NullableBoolA" IS NOT NULL OR "e"."NullableBoolB" IS NOT NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableBoolA" = "e"."NullableBoolB" OR "e"."NullableBoolA" IS NULL OR "e"."NullableBoolB" IS NULL) AND ("e"."NullableBoolA" IS NOT NULL OR "e"."NullableBoolB" IS NOT NULL) +""", + // + """ +SELECT "e"."Id", "e"."NullableBoolA" <> "e"."BoolB" OR "e"."NullableBoolA" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableBoolA" <> "e"."BoolB" OR "e"."NullableBoolA" IS NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableBoolA" <> "e"."NullableBoolB" OR "e"."NullableBoolA" IS NULL OR "e"."NullableBoolB" IS NULL) AND ("e"."NullableBoolA" IS NOT NULL OR "e"."NullableBoolB" IS NOT NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableBoolA" <> "e"."NullableBoolB" OR "e"."NullableBoolA" IS NULL OR "e"."NullableBoolB" IS NULL) AND ("e"."NullableBoolA" IS NOT NULL OR "e"."NullableBoolB" IS NOT NULL) +""", + // + """ +SELECT "e"."Id", "e"."BoolA" <> "e"."BoolB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" <> "e"."BoolB" +""", + // + """ +SELECT "e"."Id", "e"."BoolA" <> "e"."NullableBoolB" OR "e"."NullableBoolB" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" <> "e"."NullableBoolB" OR "e"."NullableBoolB" IS NULL +""", + // + """ +SELECT "e"."Id", "e"."BoolA" = "e"."BoolB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" = "e"."BoolB" +""", + // + """ +SELECT "e"."Id", "e"."BoolA" = "e"."NullableBoolB" OR "e"."NullableBoolB" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" = "e"."NullableBoolB" OR "e"."NullableBoolB" IS NULL +""", + // + """ +SELECT "e"."Id", "e"."NullableBoolA" <> "e"."BoolB" OR "e"."NullableBoolA" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableBoolA" <> "e"."BoolB" OR "e"."NullableBoolA" IS NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableBoolA" <> "e"."NullableBoolB" OR "e"."NullableBoolA" IS NULL OR "e"."NullableBoolB" IS NULL) AND ("e"."NullableBoolA" IS NOT NULL OR "e"."NullableBoolB" IS NOT NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableBoolA" <> "e"."NullableBoolB" OR "e"."NullableBoolA" IS NULL OR "e"."NullableBoolB" IS NULL) AND ("e"."NullableBoolA" IS NOT NULL OR "e"."NullableBoolB" IS NOT NULL) +""", + // + """ +SELECT "e"."Id", "e"."NullableBoolA" = "e"."BoolB" OR "e"."NullableBoolA" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableBoolA" = "e"."BoolB" OR "e"."NullableBoolA" IS NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableBoolA" = "e"."NullableBoolB" OR "e"."NullableBoolA" IS NULL OR "e"."NullableBoolB" IS NULL) AND ("e"."NullableBoolA" IS NOT NULL OR "e"."NullableBoolB" IS NOT NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableBoolA" = "e"."NullableBoolB" OR "e"."NullableBoolA" IS NULL OR "e"."NullableBoolB" IS NULL) AND ("e"."NullableBoolA" IS NOT NULL OR "e"."NullableBoolB" IS NOT NULL) +""", + // + """ +SELECT "e"."Id", "e"."BoolA" = "e"."BoolB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" = "e"."BoolB" +""", + // + """ +SELECT "e"."Id", "e"."BoolA" = "e"."NullableBoolB" OR "e"."NullableBoolB" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" = "e"."NullableBoolB" OR "e"."NullableBoolB" IS NULL +""", + // + """ +SELECT "e"."Id", "e"."BoolA" <> "e"."BoolB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" <> "e"."BoolB" +""", + // + """ +SELECT "e"."Id", "e"."BoolA" <> "e"."NullableBoolB" OR "e"."NullableBoolB" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" <> "e"."NullableBoolB" OR "e"."NullableBoolB" IS NULL +""", + // + """ +SELECT "e"."Id", "e"."NullableBoolA" = "e"."BoolB" OR "e"."NullableBoolA" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableBoolA" = "e"."BoolB" OR "e"."NullableBoolA" IS NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableBoolA" = "e"."NullableBoolB" OR "e"."NullableBoolA" IS NULL OR "e"."NullableBoolB" IS NULL) AND ("e"."NullableBoolA" IS NOT NULL OR "e"."NullableBoolB" IS NOT NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableBoolA" = "e"."NullableBoolB" OR "e"."NullableBoolA" IS NULL OR "e"."NullableBoolB" IS NULL) AND ("e"."NullableBoolA" IS NOT NULL OR "e"."NullableBoolB" IS NOT NULL) +""", + // + """ +SELECT "e"."Id", "e"."NullableBoolA" <> "e"."BoolB" OR "e"."NullableBoolA" IS NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableBoolA" <> "e"."BoolB" OR "e"."NullableBoolA" IS NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableBoolA" <> "e"."NullableBoolB" OR "e"."NullableBoolA" IS NULL OR "e"."NullableBoolB" IS NULL) AND ("e"."NullableBoolA" IS NOT NULL OR "e"."NullableBoolB" IS NOT NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableBoolA" <> "e"."NullableBoolB" OR "e"."NullableBoolA" IS NULL OR "e"."NullableBoolB" IS NULL) AND ("e"."NullableBoolA" IS NOT NULL OR "e"."NullableBoolB" IS NOT NULL) +""", + // + """ +SELECT "e"."Id", "e"."BoolA" = "e"."BoolB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" = "e"."BoolB" +""", + // + """ +SELECT "e"."Id", "e"."BoolA" = "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" = "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL +""", + // + """ +SELECT "e"."Id", "e"."BoolA" <> "e"."BoolB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" <> "e"."BoolB" +""", + // + """ +SELECT "e"."Id", "e"."BoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL +""", + // + """ +SELECT "e"."Id", "e"."NullableBoolA" = "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableBoolA" = "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableBoolA" = "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableBoolA" = "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) +""", + // + """ +SELECT "e"."Id", "e"."NullableBoolA" <> "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableBoolA" <> "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableBoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableBoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) +""", + // + """ +SELECT "e"."Id", "e"."BoolA" <> "e"."BoolB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" <> "e"."BoolB" +""", + // + """ +SELECT "e"."Id", "e"."BoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL +""", + // + """ +SELECT "e"."Id", "e"."BoolA" = "e"."BoolB" AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" = "e"."BoolB" +""", + // + """ +SELECT "e"."Id", "e"."BoolA" = "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."BoolA" = "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL +""", + // + """ +SELECT "e"."Id", "e"."NullableBoolA" <> "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableBoolA" <> "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableBoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableBoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) +""", + // + """ +SELECT "e"."Id", "e"."NullableBoolA" = "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE "e"."NullableBoolA" = "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL +""", + // + """ +SELECT "e"."Id", ("e"."NullableBoolA" = "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) AS "X" +FROM "Entities1" AS "e" +""", + // + """ +SELECT "e"."Id" +FROM "Entities1" AS "e" +WHERE ("e"."NullableBoolA" = "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) +"""); + } + public override async Task Join_uses_database_semantics(bool async) { await base.Join_uses_database_semantics(async); From 84ec52f1450d94092f149b09312d745136f71e16 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Sun, 23 Jun 2024 19:04:16 +0200 Subject: [PATCH 2/6] Simplify null semantics rewriting --- .../Query/SqlNullabilityProcessor.cs | 134 +----------------- 1 file changed, 6 insertions(+), 128 deletions(-) diff --git a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs index c8fb53f61cf..c586420cfb1 100644 --- a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs +++ b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs @@ -1812,62 +1812,16 @@ private SqlExpression RewriteNullSemantics( if (sqlBinaryExpression.OperatorType == ExpressionType.Equal) { - if (leftNullable && rightNullable) - { - // ?a == ?b <=> !(?a) == !(?b) -> [(a == b) && (a != null && b != null)] || (a == null && b == null)) - // !(?a) == ?b <=> ?a == !(?b) -> [(a != b) && (a != null && b != null)] || (a == null && b == null) - return leftNegated == rightNegated - ? ExpandNullableEqualNullable(left, right, leftIsNull, leftIsNotNull, rightIsNull, rightIsNotNull) - : ExpandNegatedNullableEqualNullable(left, right, leftIsNull, leftIsNotNull, rightIsNull, rightIsNotNull); - } - - if (leftNullable && !rightNullable) - { - // ?a == b <=> !(?a) == !b -> (a == b) && (a != null) - // !(?a) == b <=> ?a == !b -> (a != b) && (a != null) - return leftNegated == rightNegated - ? ExpandNullableEqualNonNullable(left, right, leftIsNotNull) - : ExpandNegatedNullableEqualNonNullable(left, right, leftIsNotNull); - } - - if (rightNullable && !leftNullable) - { - // a == ?b <=> !a == !(?b) -> (a == b) && (b != null) - // !a == ?b <=> a == !(?b) -> (a != b) && (b != null) - return leftNegated == rightNegated - ? ExpandNullableEqualNonNullable(left, right, rightIsNotNull) - : ExpandNegatedNullableEqualNonNullable(left, right, rightIsNotNull); - } + return leftNegated == rightNegated + ? ExpandNullableEqualNullable(left, right, leftIsNull, leftIsNotNull, rightIsNull, rightIsNotNull) + : ExpandNegatedNullableEqualNullable(left, right, leftIsNull, leftIsNotNull, rightIsNull, rightIsNotNull); } if (sqlBinaryExpression.OperatorType == ExpressionType.NotEqual) { - if (leftNullable && rightNullable) - { - // ?a != ?b <=> !(?a) != !(?b) -> [(a != b) || (a == null || b == null)] && (a != null || b != null) - // !(?a) != ?b <=> ?a != !(?b) -> [(a == b) || (a == null || b == null)] && (a != null || b != null) - return leftNegated == rightNegated - ? ExpandNullableNotEqualNullable(left, right, leftIsNull, leftIsNotNull, rightIsNull, rightIsNotNull) - : ExpandNegatedNullableNotEqualNullable(left, right, leftIsNull, leftIsNotNull, rightIsNull, rightIsNotNull); - } - - if (leftNullable && !rightNullable) - { - // ?a != b <=> !(?a) != !b -> (a != b) || (a == null) - // !(?a) != b <=> ?a != !b -> (a == b) || (a == null) - return leftNegated == rightNegated - ? ExpandNullableNotEqualNonNullable(left, right, leftIsNull) - : ExpandNegatedNullableNotEqualNonNullable(left, right, leftIsNull); - } - - if (rightNullable && !leftNullable) - { - // a != ?b <=> !a != !(?b) -> (a != b) || (b == null) - // !a != ?b <=> a != !(?b) -> (a == b) || (b == null) - return leftNegated == rightNegated - ? ExpandNullableNotEqualNonNullable(left, right, rightIsNull) - : ExpandNegatedNullableNotEqualNonNullable(left, right, rightIsNull); - } + return leftNegated == rightNegated + ? ExpandNullableNotEqualNullable(left, right, leftIsNull, leftIsNotNull, rightIsNull, rightIsNotNull) + : ExpandNegatedNullableNotEqualNullable(left, right, leftIsNull, leftIsNotNull, rightIsNull, rightIsNotNull); } return sqlBinaryExpression.Update(left, right); @@ -2485,44 +2439,6 @@ private SqlExpression ExpandNegatedNullableEqualNullable( SimplifyLogicalSqlBinaryExpression( _sqlExpressionFactory.AndAlso(leftIsNull, rightIsNull)))); - // ?a == b -> (a == b) && (a != null) - // - // a | b | F1 = a == b | F2 = (a != null) | Final = F1 && F2 | - // | | | | | - // 0 | 0 | 1 | 1 | 1 | - // 0 | 1 | 0 | 1 | 0 | - // 1 | 0 | 0 | 1 | 0 | - // 1 | 1 | 1 | 1 | 1 | - // N | 0 | N | 0 | 0 | - // N | 1 | N | 0 | 0 | - private SqlExpression ExpandNullableEqualNonNullable( - SqlExpression left, - SqlExpression right, - SqlExpression leftIsNotNull) - => SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.AndAlso( - _sqlExpressionFactory.Equal(left, right), - leftIsNotNull)); - - // !(?a) == b -> (a != b) && (a != null) - // - // a | b | F1 = a != b | F2 = (a != null) | Final = F1 && F2 | - // | | | | | - // 0 | 0 | 0 | 1 | 0 | - // 0 | 1 | 1 | 1 | 1 | - // 1 | 0 | 1 | 1 | 1 | - // 1 | 1 | 0 | 1 | 0 | - // N | 0 | N | 0 | 0 | - // N | 1 | N | 0 | 0 | - private SqlExpression ExpandNegatedNullableEqualNonNullable( - SqlExpression left, - SqlExpression right, - SqlExpression leftIsNotNull) - => SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.AndAlso( - _sqlExpressionFactory.NotEqual(left, right), - leftIsNotNull)); - // ?a != ?b -> [(a != b) || (a == null || b == null)] && (a != null || b != null) // // a | b | F1 = a != b | F2 = (a == null || b == null) | F3 = F1 || F2 | @@ -2606,42 +2522,4 @@ private SqlExpression ExpandNegatedNullableNotEqualNullable( _sqlExpressionFactory.OrElse(leftIsNull, rightIsNull)))), SimplifyLogicalSqlBinaryExpression( _sqlExpressionFactory.OrElse(leftIsNotNull, rightIsNotNull)))); - - // ?a != b -> (a != b) || (a == null) - // - // a | b | F1 = a != b | F2 = (a == null) | Final = F1 OR F2 | - // | | | | | - // 0 | 0 | 0 | 0 | 0 | - // 0 | 1 | 1 | 0 | 1 | - // 1 | 0 | 1 | 0 | 1 | - // 1 | 1 | 0 | 0 | 0 | - // N | 0 | N | 1 | 1 | - // N | 1 | N | 1 | 1 | - private SqlExpression ExpandNullableNotEqualNonNullable( - SqlExpression left, - SqlExpression right, - SqlExpression leftIsNull) - => SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.OrElse( - _sqlExpressionFactory.NotEqual(left, right), - leftIsNull)); - - // !(?a) != b -> (a == b) || (a == null) - // - // a | b | F1 = a == b | F2 = (a == null) | F3 = F1 OR F2 | - // | | | | | - // 0 | 0 | 1 | 0 | 1 | - // 0 | 1 | 0 | 0 | 0 | - // 1 | 0 | 0 | 0 | 0 | - // 1 | 1 | 1 | 0 | 1 | - // N | 0 | N | 1 | 1 | - // N | 1 | N | 1 | 1 | - private SqlExpression ExpandNegatedNullableNotEqualNonNullable( - SqlExpression left, - SqlExpression right, - SqlExpression leftIsNull) - => SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.OrElse( - _sqlExpressionFactory.Equal(left, right), - leftIsNull)); } From e041d0bfdf6de395c8ff4f4cb3a147bb4b0606f9 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Sun, 23 Jun 2024 19:39:36 +0200 Subject: [PATCH 3/6] Further simplify null semantics rewriting --- .../Query/SqlNullabilityProcessor.cs | 198 ++---------------- 1 file changed, 22 insertions(+), 176 deletions(-) diff --git a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs index c586420cfb1..ad01e2561fc 100644 --- a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs +++ b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs @@ -1810,21 +1810,35 @@ private SqlExpression RewriteNullSemantics( // doing a full null semantics rewrite - removing all nulls from truth table nullable = false; - if (sqlBinaryExpression.OperatorType == ExpressionType.Equal) + SqlExpression body; + if (leftNegated == rightNegated) { - return leftNegated == rightNegated - ? ExpandNullableEqualNullable(left, right, leftIsNull, leftIsNotNull, rightIsNull, rightIsNotNull) - : ExpandNegatedNullableEqualNullable(left, right, leftIsNull, leftIsNotNull, rightIsNull, rightIsNotNull); + body = _sqlExpressionFactory.Equal(left, right); } + else + { + // a == !b and !a == b in SQL evaluate the same as a != b + body = _sqlExpressionFactory.NotEqual(left, right); + } + + // (a == b && (a != null && b != null)) || (a == null && b == null) + body = SimplifyLogicalSqlBinaryExpression( + _sqlExpressionFactory.OrElse( + SimplifyLogicalSqlBinaryExpression( + _sqlExpressionFactory.AndAlso( + body, + SimplifyLogicalSqlBinaryExpression( + _sqlExpressionFactory.AndAlso(leftIsNotNull, rightIsNotNull)))), + SimplifyLogicalSqlBinaryExpression( + _sqlExpressionFactory.AndAlso(leftIsNull, rightIsNull)))); if (sqlBinaryExpression.OperatorType == ExpressionType.NotEqual) { - return leftNegated == rightNegated - ? ExpandNullableNotEqualNullable(left, right, leftIsNull, leftIsNotNull, rightIsNull, rightIsNotNull) - : ExpandNegatedNullableNotEqualNullable(left, right, leftIsNull, leftIsNotNull, rightIsNull, rightIsNotNull); + // simplify using DeMorgan + body = OptimizeNonNullableNotExpression(_sqlExpressionFactory.Not(body)); } - return sqlBinaryExpression.Update(left, right); + return body; } private SqlExpression SimplifyLogicalSqlBinaryExpression(SqlBinaryExpression sqlBinaryExpression) @@ -2354,172 +2368,4 @@ private SqlExpression ProcessNullNotNull(SqlUnaryExpression sqlUnaryExpression, private static bool IsLogicalNot(SqlUnaryExpression? sqlUnaryExpression) => sqlUnaryExpression is { OperatorType: ExpressionType.Not } && sqlUnaryExpression.Type == typeof(bool); - - // ?a == ?b -> [(a == b) && (a != null && b != null)] || (a == null && b == null)) - // - // a | b | F1 = a == b | F2 = (a != null && b != null) | F3 = F1 && F2 | - // | | | | | - // 0 | 0 | 1 | 1 | 1 | - // 0 | 1 | 0 | 1 | 0 | - // 0 | N | N | 0 | 0 | - // 1 | 0 | 0 | 1 | 0 | - // 1 | 1 | 1 | 1 | 1 | - // 1 | N | N | 0 | 0 | - // N | 0 | N | 0 | 0 | - // N | 1 | N | 0 | 0 | - // N | N | N | 0 | 0 | - // - // a | b | F4 = (a == null && b == null) | Final = F3 OR F4 | - // | | | | - // 0 | 0 | 0 | 1 OR 0 = 1 | - // 0 | 1 | 0 | 0 OR 0 = 0 | - // 0 | N | 0 | 0 OR 0 = 0 | - // 1 | 0 | 0 | 0 OR 0 = 0 | - // 1 | 1 | 0 | 1 OR 0 = 1 | - // 1 | N | 0 | 0 OR 0 = 0 | - // N | 0 | 0 | 0 OR 0 = 0 | - // N | 1 | 0 | 0 OR 0 = 0 | - // N | N | 1 | 0 OR 1 = 1 | - private SqlExpression ExpandNullableEqualNullable( - SqlExpression left, - SqlExpression right, - SqlExpression leftIsNull, - SqlExpression leftIsNotNull, - SqlExpression rightIsNull, - SqlExpression rightIsNotNull) - => SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.OrElse( - SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.AndAlso( - _sqlExpressionFactory.Equal(left, right), - SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.AndAlso(leftIsNotNull, rightIsNotNull)))), - SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.AndAlso(leftIsNull, rightIsNull)))); - - // !(?a) == ?b -> [(a != b) && (a != null && b != null)] || (a == null && b == null) - // - // a | b | F1 = a != b | F2 = (a != null && b != null) | F3 = F1 && F2 | - // | | | | | - // 0 | 0 | 0 | 1 | 0 | - // 0 | 1 | 1 | 1 | 1 | - // 0 | N | N | 0 | 0 | - // 1 | 0 | 1 | 1 | 1 | - // 1 | 1 | 0 | 1 | 0 | - // 1 | N | N | 0 | 0 | - // N | 0 | N | 0 | 0 | - // N | 1 | N | 0 | 0 | - // N | N | N | 0 | 0 | - // - // a | b | F4 = (a == null && b == null) | Final = F3 OR F4 | - // | | | | - // 0 | 0 | 0 | 0 OR 0 = 0 | - // 0 | 1 | 0 | 1 OR 0 = 1 | - // 0 | N | 0 | 0 OR 0 = 0 | - // 1 | 0 | 0 | 1 OR 0 = 1 | - // 1 | 1 | 0 | 0 OR 0 = 0 | - // 1 | N | 0 | 0 OR 0 = 0 | - // N | 0 | 0 | 0 OR 0 = 0 | - // N | 1 | 0 | 0 OR 0 = 0 | - // N | N | 1 | 0 OR 1 = 1 | - private SqlExpression ExpandNegatedNullableEqualNullable( - SqlExpression left, - SqlExpression right, - SqlExpression leftIsNull, - SqlExpression leftIsNotNull, - SqlExpression rightIsNull, - SqlExpression rightIsNotNull) - => SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.OrElse( - SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.AndAlso( - _sqlExpressionFactory.NotEqual(left, right), - SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.AndAlso(leftIsNotNull, rightIsNotNull)))), - SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.AndAlso(leftIsNull, rightIsNull)))); - - // ?a != ?b -> [(a != b) || (a == null || b == null)] && (a != null || b != null) - // - // a | b | F1 = a != b | F2 = (a == null || b == null) | F3 = F1 || F2 | - // | | | | | - // 0 | 0 | 0 | 0 | 0 | - // 0 | 1 | 1 | 0 | 1 | - // 0 | N | N | 1 | 1 | - // 1 | 0 | 1 | 0 | 1 | - // 1 | 1 | 0 | 0 | 0 | - // 1 | N | N | 1 | 1 | - // N | 0 | N | 1 | 1 | - // N | 1 | N | 1 | 1 | - // N | N | N | 1 | 1 | - // - // a | b | F4 = (a != null || b != null) | Final = F3 && F4 | - // | | | | - // 0 | 0 | 1 | 0 && 1 = 0 | - // 0 | 1 | 1 | 1 && 1 = 1 | - // 0 | N | 1 | 1 && 1 = 1 | - // 1 | 0 | 1 | 1 && 1 = 1 | - // 1 | 1 | 1 | 0 && 1 = 0 | - // 1 | N | 1 | 1 && 1 = 1 | - // N | 0 | 1 | 1 && 1 = 1 | - // N | 1 | 1 | 1 && 1 = 1 | - // N | N | 0 | 1 && 0 = 0 | - private SqlExpression ExpandNullableNotEqualNullable( - SqlExpression left, - SqlExpression right, - SqlExpression leftIsNull, - SqlExpression leftIsNotNull, - SqlExpression rightIsNull, - SqlExpression rightIsNotNull) - => SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.AndAlso( - SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.OrElse( - _sqlExpressionFactory.NotEqual(left, right), - SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.OrElse(leftIsNull, rightIsNull)))), - SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.OrElse(leftIsNotNull, rightIsNotNull)))); - - // !(?a) != ?b -> [(a == b) || (a == null || b == null)] && (a != null || b != null) - // - // a | b | F1 = a == b | F2 = (a == null || b == null) | F3 = F1 || F2 | - // | | | | | - // 0 | 0 | 1 | 0 | 1 | - // 0 | 1 | 0 | 0 | 0 | - // 0 | N | N | 1 | 1 | - // 1 | 0 | 0 | 0 | 0 | - // 1 | 1 | 1 | 0 | 1 | - // 1 | N | N | 1 | 1 | - // N | 0 | N | 1 | 1 | - // N | 1 | N | 1 | 1 | - // N | N | N | 1 | 1 | - // - // a | b | F4 = (a != null || b != null) | Final = F3 && F4 | - // | | | | - // 0 | 0 | 1 | 1 && 1 = 1 | - // 0 | 1 | 1 | 0 && 1 = 0 | - // 0 | N | 1 | 1 && 1 = 1 | - // 1 | 0 | 1 | 0 && 1 = 0 | - // 1 | 1 | 1 | 1 && 1 = 1 | - // 1 | N | 1 | 1 && 1 = 1 | - // N | 0 | 1 | 1 && 1 = 1 | - // N | 1 | 1 | 1 && 1 = 1 | - // N | N | 0 | 1 && 0 = 0 | - private SqlExpression ExpandNegatedNullableNotEqualNullable( - SqlExpression left, - SqlExpression right, - SqlExpression leftIsNull, - SqlExpression leftIsNotNull, - SqlExpression rightIsNull, - SqlExpression rightIsNotNull) - => SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.AndAlso( - SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.OrElse( - _sqlExpressionFactory.Equal(left, right), - SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.OrElse(leftIsNull, rightIsNull)))), - SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.OrElse(leftIsNotNull, rightIsNotNull)))); } From c5e82ab3a5832762bc2badaea8e0cdd39fc1b7b6 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Sun, 23 Jun 2024 19:39:45 +0200 Subject: [PATCH 4/6] Update baselines --- .../Query/GearsOfWarQuerySqlServerTest.cs | 6 +++--- .../Query/TPCGearsOfWarQuerySqlServerTest.cs | 6 +++--- .../Query/TPTGearsOfWarQuerySqlServerTest.cs | 6 +++--- .../Query/TemporalGearsOfWarQuerySqlServerTest.cs | 6 +++--- .../Query/GearsOfWarQuerySqliteTest.cs | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index f948f7fc776..aa70761d1f6 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -5028,7 +5028,7 @@ INNER JOIN ( FROM [Factions] AS [f] WHERE [f].[Name] = N'Swarm' ) AS [f0] ON [l].[Name] = [f0].[CommanderName] -WHERE [f0].[Eradicated] <> CAST(1 AS bit) OR [f0].[Eradicated] IS NULL +WHERE [f0].[Eradicated] = CAST(0 AS bit) OR [f0].[Eradicated] IS NULL """); } @@ -5045,7 +5045,7 @@ LEFT JOIN ( FROM [Factions] AS [f] WHERE [f].[Name] = N'Swarm' ) AS [f0] ON [l].[Name] = [f0].[CommanderName] -WHERE [f0].[Eradicated] <> CAST(1 AS bit) OR [f0].[Eradicated] IS NULL +WHERE [f0].[Eradicated] = CAST(0 AS bit) OR [f0].[Eradicated] IS NULL """); } @@ -7618,7 +7618,7 @@ FROM [LocustLeaders] AS [l] WHERE CASE WHEN [f].[Name] = N'Locust' THEN CAST(1 AS bit) ELSE NULL -END <> CAST(1 AS bit) OR CASE +END = CAST(0 AS bit) OR CASE WHEN [f].[Name] = N'Locust' THEN CAST(1 AS bit) ELSE NULL END IS NULL diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs index 22e58c54fc5..09b54e04f61 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs @@ -6850,7 +6850,7 @@ INNER JOIN ( FROM [LocustHordes] AS [l1] WHERE [l1].[Name] = N'Swarm' ) AS [l2] ON [u].[Name] = [l2].[CommanderName] -WHERE [l2].[Eradicated] <> CAST(1 AS bit) OR [l2].[Eradicated] IS NULL +WHERE [l2].[Eradicated] = CAST(0 AS bit) OR [l2].[Eradicated] IS NULL """); } @@ -6873,7 +6873,7 @@ LEFT JOIN ( FROM [LocustHordes] AS [l1] WHERE [l1].[Name] = N'Swarm' ) AS [l2] ON [u].[Name] = [l2].[CommanderName] -WHERE [l2].[Eradicated] <> CAST(1 AS bit) OR [l2].[Eradicated] IS NULL +WHERE [l2].[Eradicated] = CAST(0 AS bit) OR [l2].[Eradicated] IS NULL """); } @@ -10181,7 +10181,7 @@ FROM [LocustCommanders] AS [l0] WHERE CASE WHEN [l1].[Name] = N'Locust' THEN CAST(1 AS bit) ELSE NULL -END <> CAST(1 AS bit) OR CASE +END = CAST(0 AS bit) OR CASE WHEN [l1].[Name] = N'Locust' THEN CAST(1 AS bit) ELSE NULL END IS NULL diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs index cadd97ff667..6c404ce1542 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs @@ -5791,7 +5791,7 @@ FROM [Factions] AS [f] LEFT JOIN [LocustHordes] AS [l0] ON [f].[Id] = [l0].[Id] WHERE [l0].[Id] IS NOT NULL AND [f].[Name] = N'Swarm' ) AS [s] ON [l].[Name] = [s].[CommanderName] -WHERE [s].[Eradicated] <> CAST(1 AS bit) OR [s].[Eradicated] IS NULL +WHERE [s].[Eradicated] = CAST(0 AS bit) OR [s].[Eradicated] IS NULL """); } @@ -5811,7 +5811,7 @@ FROM [Factions] AS [f] LEFT JOIN [LocustHordes] AS [l0] ON [f].[Id] = [l0].[Id] WHERE [l0].[Id] IS NOT NULL AND [f].[Name] = N'Swarm' ) AS [s] ON [l].[Name] = [s].[CommanderName] -WHERE [s].[Eradicated] <> CAST(1 AS bit) OR [s].[Eradicated] IS NULL +WHERE [s].[Eradicated] = CAST(0 AS bit) OR [s].[Eradicated] IS NULL """); } @@ -8649,7 +8649,7 @@ WHERE [l0].[Id] IS NOT NULL WHERE CASE WHEN [s].[Name] = N'Locust' THEN CAST(1 AS bit) ELSE NULL -END <> CAST(1 AS bit) OR CASE +END = CAST(0 AS bit) OR CASE WHEN [s].[Name] = N'Locust' THEN CAST(1 AS bit) ELSE NULL END IS NULL diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs index efe49c9bce9..6cfaebb3f97 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs @@ -2587,7 +2587,7 @@ ELSE NULL WHERE CASE WHEN [f].[Name] = N'Locust' THEN CAST(1 AS bit) ELSE NULL -END <> CAST(1 AS bit) OR CASE +END = CAST(0 AS bit) OR CASE WHEN [f].[Name] = N'Locust' THEN CAST(1 AS bit) ELSE NULL END IS NULL @@ -4534,7 +4534,7 @@ INNER JOIN ( FROM [Factions] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [f] WHERE [f].[Name] = N'Swarm' ) AS [f0] ON [l].[Name] = [f0].[CommanderName] -WHERE [f0].[Eradicated] <> CAST(1 AS bit) OR [f0].[Eradicated] IS NULL +WHERE [f0].[Eradicated] = CAST(0 AS bit) OR [f0].[Eradicated] IS NULL """); } @@ -6490,7 +6490,7 @@ LEFT JOIN ( FROM [Factions] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [f] WHERE [f].[Name] = N'Swarm' ) AS [f0] ON [l].[Name] = [f0].[CommanderName] -WHERE [f0].[Eradicated] <> CAST(1 AS bit) OR [f0].[Eradicated] IS NULL +WHERE [f0].[Eradicated] = CAST(0 AS bit) OR [f0].[Eradicated] IS NULL """); } diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs index a01b1bcc00d..c793024fea3 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs @@ -2883,7 +2883,7 @@ ELSE NULL WHERE CASE WHEN "f"."Name" = 'Locust' THEN 1 ELSE NULL -END <> 1 OR CASE +END = 0 OR CASE WHEN "f"."Name" = 'Locust' THEN 1 ELSE NULL END IS NULL @@ -5497,7 +5497,7 @@ LEFT JOIN ( FROM "Factions" AS "f" WHERE "f"."Name" = 'Swarm' ) AS "f0" ON "l"."Name" = "f0"."CommanderName" -WHERE "f0"."Eradicated" <> 1 OR "f0"."Eradicated" IS NULL +WHERE "f0"."Eradicated" = 0 OR "f0"."Eradicated" IS NULL """); } @@ -5565,7 +5565,7 @@ INNER JOIN ( FROM "Factions" AS "f" WHERE "f"."Name" = 'Swarm' ) AS "f0" ON "l"."Name" = "f0"."CommanderName" -WHERE "f0"."Eradicated" <> 1 OR "f0"."Eradicated" IS NULL +WHERE "f0"."Eradicated" = 0 OR "f0"."Eradicated" IS NULL """); } From c63d865bd306374e11cf866d8757f98eb12db53a Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Sun, 23 Jun 2024 20:56:12 +0200 Subject: [PATCH 5/6] Simplify null rewrites of filters using the same techniques as projections. --- .../Query/SqlNullabilityProcessor.cs | 45 +++++++------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs index ad01e2561fc..5e0b88d5037 100644 --- a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs +++ b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs @@ -1780,36 +1780,6 @@ private SqlExpression RewriteNullSemantics( var rightIsNull = ProcessNullNotNull(_sqlExpressionFactory.IsNull(right), rightNullable); var rightIsNotNull = OptimizeNonNullableNotExpression(_sqlExpressionFactory.Not(rightIsNull)); - // optimized expansion which doesn't distinguish between null and false - if (optimize - && sqlBinaryExpression.OperatorType == ExpressionType.Equal - && !leftNegated - && !rightNegated) - { - // when we use optimized form, the result can still be nullable - if (leftNullable && rightNullable) - { - nullable = true; - - return SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.OrElse( - _sqlExpressionFactory.Equal(left, right), - SimplifyLogicalSqlBinaryExpression( - _sqlExpressionFactory.AndAlso(leftIsNull, rightIsNull)))); - } - - if ((leftNullable && !rightNullable) - || (!leftNullable && rightNullable)) - { - nullable = true; - - return _sqlExpressionFactory.Equal(left, right); - } - } - - // doing a full null semantics rewrite - removing all nulls from truth table - nullable = false; - SqlExpression body; if (leftNegated == rightNegated) { @@ -1821,6 +1791,21 @@ private SqlExpression RewriteNullSemantics( body = _sqlExpressionFactory.NotEqual(left, right); } + // optimized expansion which doesn't distinguish between null and false + if (optimize && sqlBinaryExpression.OperatorType == ExpressionType.Equal) + { + nullable = leftNullable || rightNullable; + + return SimplifyLogicalSqlBinaryExpression( + _sqlExpressionFactory.OrElse( + body, + SimplifyLogicalSqlBinaryExpression( + _sqlExpressionFactory.AndAlso(leftIsNull, rightIsNull)))); + } + + // doing a full null semantics rewrite - removing all nulls from truth table + nullable = false; + // (a == b && (a != null && b != null)) || (a == null && b == null) body = SimplifyLogicalSqlBinaryExpression( _sqlExpressionFactory.OrElse( From 77e820c01810e9fbaf5de9b05a6fafb50948d244 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Sun, 23 Jun 2024 21:00:37 +0200 Subject: [PATCH 6/6] Update baselines --- .../Query/NullSemanticsQuerySqlServerTest.cs | 36 +++++++++---------- .../Query/NullSemanticsQuerySqliteTest.cs | 18 +++++----- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs index 9c31f926137..0a8052fa749 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs @@ -304,7 +304,7 @@ FROM [Entities1] AS [e] """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[BoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL +WHERE [e].[BoolA] <> [e].[NullableBoolB] """, // """ @@ -346,7 +346,7 @@ FROM [Entities1] AS [e] """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableBoolA] <> [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL +WHERE [e].[NullableBoolA] <> [e].[BoolB] """, // """ @@ -360,7 +360,7 @@ FROM [Entities1] AS [e] """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ([e].[NullableBoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) +WHERE [e].[NullableBoolA] <> [e].[NullableBoolB] OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) """, // """ @@ -388,7 +388,7 @@ FROM [Entities1] AS [e] """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[BoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL +WHERE [e].[BoolA] <> [e].[NullableBoolB] """, // """ @@ -416,7 +416,7 @@ FROM [Entities1] AS [e] """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[BoolA] = [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL +WHERE [e].[BoolA] = [e].[NullableBoolB] """, // """ @@ -430,7 +430,7 @@ FROM [Entities1] AS [e] """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableBoolA] <> [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL +WHERE [e].[NullableBoolA] <> [e].[BoolB] """, // """ @@ -444,7 +444,7 @@ FROM [Entities1] AS [e] """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ([e].[NullableBoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) +WHERE [e].[NullableBoolA] <> [e].[NullableBoolB] OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) """, // """ @@ -458,7 +458,7 @@ FROM [Entities1] AS [e] """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableBoolA] = [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL +WHERE [e].[NullableBoolA] = [e].[BoolB] """, // """ @@ -472,7 +472,7 @@ FROM [Entities1] AS [e] """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ([e].[NullableBoolA] = [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) +WHERE [e].[NullableBoolA] = [e].[NullableBoolB] OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) """, // """ @@ -1192,19 +1192,19 @@ WHERE [e].[BoolA] <> [e].[BoolB] """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[BoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL +WHERE [e].[BoolA] <> [e].[NullableBoolB] """, // """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableBoolA] <> [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL +WHERE [e].[NullableBoolA] <> [e].[BoolB] """, // """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ([e].[NullableBoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) +WHERE [e].[NullableBoolA] <> [e].[NullableBoolB] OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) """); } @@ -1222,19 +1222,19 @@ WHERE [e].[BoolA] <> [e].[BoolB] """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[BoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL +WHERE [e].[BoolA] <> [e].[NullableBoolB] """, // """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableBoolA] <> [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL +WHERE [e].[NullableBoolA] <> [e].[BoolB] """, // """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ([e].[NullableBoolA] <> [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) +WHERE [e].[NullableBoolA] <> [e].[NullableBoolB] OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) """); } @@ -1252,19 +1252,19 @@ FROM [Entities1] AS [e] """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[BoolA] = [e].[NullableBoolB] AND [e].[NullableBoolB] IS NOT NULL +WHERE [e].[BoolA] = [e].[NullableBoolB] """, // """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableBoolA] = [e].[BoolB] AND [e].[NullableBoolA] IS NOT NULL +WHERE [e].[NullableBoolA] = [e].[BoolB] """, // """ SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ([e].[NullableBoolA] = [e].[NullableBoolB] AND [e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) +WHERE [e].[NullableBoolA] = [e].[NullableBoolB] OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL) """); } diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/NullSemanticsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/NullSemanticsQuerySqliteTest.cs index e5e4fa04790..a1c45c915cc 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/NullSemanticsQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/NullSemanticsQuerySqliteTest.cs @@ -245,7 +245,7 @@ public override async Task Rewrite_compare_bool_with_bool(bool async) """ SELECT "e"."Id" FROM "Entities1" AS "e" -WHERE "e"."BoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL +WHERE "e"."BoolA" <> "e"."NullableBoolB" """, // """ @@ -278,7 +278,7 @@ public override async Task Rewrite_compare_bool_with_bool(bool async) """ SELECT "e"."Id" FROM "Entities1" AS "e" -WHERE "e"."NullableBoolA" <> "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL +WHERE "e"."NullableBoolA" <> "e"."BoolB" """, // """ @@ -289,7 +289,7 @@ public override async Task Rewrite_compare_bool_with_bool(bool async) """ SELECT "e"."Id" FROM "Entities1" AS "e" -WHERE ("e"."NullableBoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) +WHERE "e"."NullableBoolA" <> "e"."NullableBoolB" OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) """, // """ @@ -311,7 +311,7 @@ public override async Task Rewrite_compare_bool_with_bool(bool async) """ SELECT "e"."Id" FROM "Entities1" AS "e" -WHERE "e"."BoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL +WHERE "e"."BoolA" <> "e"."NullableBoolB" """, // """ @@ -333,7 +333,7 @@ public override async Task Rewrite_compare_bool_with_bool(bool async) """ SELECT "e"."Id" FROM "Entities1" AS "e" -WHERE "e"."BoolA" = "e"."NullableBoolB" AND "e"."NullableBoolB" IS NOT NULL +WHERE "e"."BoolA" = "e"."NullableBoolB" """, // """ @@ -344,7 +344,7 @@ public override async Task Rewrite_compare_bool_with_bool(bool async) """ SELECT "e"."Id" FROM "Entities1" AS "e" -WHERE "e"."NullableBoolA" <> "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL +WHERE "e"."NullableBoolA" <> "e"."BoolB" """, // """ @@ -355,7 +355,7 @@ public override async Task Rewrite_compare_bool_with_bool(bool async) """ SELECT "e"."Id" FROM "Entities1" AS "e" -WHERE ("e"."NullableBoolA" <> "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) +WHERE "e"."NullableBoolA" <> "e"."NullableBoolB" OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) """, // """ @@ -366,7 +366,7 @@ public override async Task Rewrite_compare_bool_with_bool(bool async) """ SELECT "e"."Id" FROM "Entities1" AS "e" -WHERE "e"."NullableBoolA" = "e"."BoolB" AND "e"."NullableBoolA" IS NOT NULL +WHERE "e"."NullableBoolA" = "e"."BoolB" """, // """ @@ -377,7 +377,7 @@ public override async Task Rewrite_compare_bool_with_bool(bool async) """ SELECT "e"."Id" FROM "Entities1" AS "e" -WHERE ("e"."NullableBoolA" = "e"."NullableBoolB" AND "e"."NullableBoolA" IS NOT NULL AND "e"."NullableBoolB" IS NOT NULL) OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) +WHERE "e"."NullableBoolA" = "e"."NullableBoolB" OR ("e"."NullableBoolA" IS NULL AND "e"."NullableBoolB" IS NULL) """, // """