From d09e2e45cb267de00dafa0e2b67ebaff4a6bea37 Mon Sep 17 00:00:00 2001 From: Christopher Jolly Date: Sat, 12 Oct 2024 17:30:02 +0800 Subject: [PATCH 1/2] Add translations for greatest/least,math.min/math.max using if statements --- .../JetSqlTranslatingExpressionVisitor.cs | 38 ++++++++++++++ .../Query/ComplexNavigationsQueryJetTest.cs | 6 ++- .../Query/DbFunctionsJetTest.cs | 52 ++++++++++++++++--- ...orthwindFunctionsQueryJetTest.Functions.cs | 42 +++++++++------ 4 files changed, 112 insertions(+), 26 deletions(-) diff --git a/src/EFCore.Jet/Query/Internal/JetSqlTranslatingExpressionVisitor.cs b/src/EFCore.Jet/Query/Internal/JetSqlTranslatingExpressionVisitor.cs index 3f78265d..7d819722 100644 --- a/src/EFCore.Jet/Query/Internal/JetSqlTranslatingExpressionVisitor.cs +++ b/src/EFCore.Jet/Query/Internal/JetSqlTranslatingExpressionVisitor.cs @@ -452,6 +452,44 @@ private Expression TranslateByteArrayElementAccess(Expression array, Expression : QueryCompilationContext.NotTranslatedExpression; } + public override SqlExpression? GenerateGreatest(IReadOnlyList expressions, Type resultType) + { + if (expressions.Count == 0) + { + return null; + } + + return expressions.Aggregate((current, next) => + Dependencies.SqlExpressionFactory.Case( + new[] + { + new CaseWhenClause( + Dependencies.SqlExpressionFactory.GreaterThan(current, next), + current) + }, + elseResult: next)); + } + + public override SqlExpression? GenerateLeast(IReadOnlyList expressions, Type resultType) + { + if (expressions.Count == 0) + { + return null; + } + + return expressions.Aggregate((current, next) => + Dependencies.SqlExpressionFactory.Case( + new[] + { + new CaseWhenClause( + Dependencies.SqlExpressionFactory.LessThan(current, next), + current) + }, + elseResult: next)); + } + + private static string? GetProviderType(SqlExpression expression) => expression.TypeMapping?.StoreType; + } diff --git a/test/EFCore.Jet.FunctionalTests/Query/ComplexNavigationsQueryJetTest.cs b/test/EFCore.Jet.FunctionalTests/Query/ComplexNavigationsQueryJetTest.cs index cb84080c..b43c255f 100644 --- a/test/EFCore.Jet.FunctionalTests/Query/ComplexNavigationsQueryJetTest.cs +++ b/test/EFCore.Jet.FunctionalTests/Query/ComplexNavigationsQueryJetTest.cs @@ -2948,10 +2948,12 @@ public override async Task Nav_rewrite_doesnt_apply_null_protection_for_function await base.Nav_rewrite_doesnt_apply_null_protection_for_function_arguments(isAsync); AssertSql( - $@"SELECT `l0`.`Level1_Required_Id` + """ +SELECT IIF(`l0`.`Level1_Required_Id` > 7, `l0`.`Level1_Required_Id`, 7) FROM `LevelOne` AS `l` LEFT JOIN `LevelTwo` AS `l0` ON `l`.`Id` = `l0`.`OneToOne_Optional_PK_Inverse2Id` -WHERE `l0`.`Id` IS NOT NULL"); +WHERE `l0`.`Id` IS NOT NULL +"""); } public override async Task Accessing_optional_property_inside_result_operator_subquery(bool isAsync) diff --git a/test/EFCore.Jet.FunctionalTests/Query/DbFunctionsJetTest.cs b/test/EFCore.Jet.FunctionalTests/Query/DbFunctionsJetTest.cs index 201b97bc..eebb5053 100644 --- a/test/EFCore.Jet.FunctionalTests/Query/DbFunctionsJetTest.cs +++ b/test/EFCore.Jet.FunctionalTests/Query/DbFunctionsJetTest.cs @@ -138,17 +138,53 @@ SELECT COUNT(*) """); } - public override Task Least(bool async) - => AssertTranslationFailed(() => base.Least(async)); + public override async Task Least(bool async) + { + await base.Least(async); + + AssertSql( + """ +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` +FROM `Order Details` AS `o` +WHERE IIF(`o`.`OrderID` < 10251, `o`.`OrderID`, 10251) = 10251 +"""); + } + + public override async Task Greatest(bool async) + { + await base.Greatest(async); + + AssertSql( + """ +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` +FROM `Order Details` AS `o` +WHERE IIF(`o`.`OrderID` > 10251, `o`.`OrderID`, 10251) = 10251 +"""); + } + + public override async Task Least_with_nullable_value_type(bool async) + { + await base.Least_with_nullable_value_type(async); - public override Task Greatest(bool async) - => AssertTranslationFailed(() => base.Greatest(async)); + AssertSql( + """ +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` +FROM `Order Details` AS `o` +WHERE IIF(`o`.`OrderID` < 10251, `o`.`OrderID`, 10251) = 10251 +"""); + } - public override Task Least_with_nullable_value_type(bool async) - => AssertTranslationFailed(() => base.Least_with_nullable_value_type(async)); + public override async Task Greatest_with_nullable_value_type(bool async) + { + await base.Greatest_with_nullable_value_type(async); - public override Task Greatest_with_nullable_value_type(bool async) - => AssertTranslationFailed(() => base.Greatest_with_nullable_value_type(async)); + AssertSql( + """ +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` +FROM `Order Details` AS `o` +WHERE IIF(`o`.`OrderID` > 10251, `o`.`OrderID`, 10251) = 10251 +"""); + } public override async Task Least_with_parameter_array_is_not_supported(bool async) { diff --git a/test/EFCore.Jet.FunctionalTests/Query/NorthwindFunctionsQueryJetTest.Functions.cs b/test/EFCore.Jet.FunctionalTests/Query/NorthwindFunctionsQueryJetTest.Functions.cs index 8ed9aa20..d721826f 100644 --- a/test/EFCore.Jet.FunctionalTests/Query/NorthwindFunctionsQueryJetTest.Functions.cs +++ b/test/EFCore.Jet.FunctionalTests/Query/NorthwindFunctionsQueryJetTest.Functions.cs @@ -1220,9 +1220,14 @@ public override async Task Where_math_sign(bool isAsync) public override async Task Where_math_min(bool async) { // Translate Math.Min. - await AssertTranslationFailed(() => base.Where_math_min(async)); + await base.Where_math_min(async); - AssertSql(); + AssertSql( + """ +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` +FROM `Order Details` AS `o` +WHERE `o`.`OrderID` = 11077 AND IIF(`o`.`OrderID` < `o`.`ProductID`, `o`.`OrderID`, `o`.`ProductID`) = `o`.`ProductID` +"""); } public override async Task Where_math_min_nested(bool async) @@ -1231,9 +1236,9 @@ public override async Task Where_math_min_nested(bool async) AssertSql( """ -SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice] -FROM [Order Details] AS [o] -WHERE [o].[OrderID] = 11077 AND LEAST([o].[OrderID], [o].[ProductID], 99999) = [o].[ProductID] +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` +FROM `Order Details` AS `o` +WHERE `o`.`OrderID` = 11077 AND IIF(IIF(`o`.`OrderID` < `o`.`ProductID`, `o`.`OrderID`, `o`.`ProductID`) < 99999, IIF(`o`.`OrderID` < `o`.`ProductID`, `o`.`OrderID`, `o`.`ProductID`), 99999) = `o`.`ProductID` """); } @@ -1243,18 +1248,23 @@ public override async Task Where_math_min_nested_twice(bool async) AssertSql( """ -SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice] -FROM [Order Details] AS [o] -WHERE [o].[OrderID] = 11077 AND LEAST(99999, [o].[OrderID], 99998, [o].[ProductID]) = [o].[ProductID] +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` +FROM `Order Details` AS `o` +WHERE `o`.`OrderID` = 11077 AND IIF(IIF(IIF(99999 < `o`.`OrderID`, 99999, `o`.`OrderID`) < 99998, IIF(99999 < `o`.`OrderID`, 99999, `o`.`OrderID`), 99998) < `o`.`ProductID`, IIF(IIF(99999 < `o`.`OrderID`, 99999, `o`.`OrderID`) < 99998, IIF(99999 < `o`.`OrderID`, 99999, `o`.`OrderID`), 99998), `o`.`ProductID`) = `o`.`ProductID` """); } public override async Task Where_math_max(bool async) { // Translate Math.Max. - await AssertTranslationFailed(() => base.Where_math_max(async)); + await base.Where_math_max(async); - AssertSql(); + AssertSql( + """ +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` +FROM `Order Details` AS `o` +WHERE `o`.`OrderID` = 11077 AND IIF(`o`.`OrderID` > `o`.`ProductID`, `o`.`OrderID`, `o`.`ProductID`) = `o`.`OrderID` +"""); } public override async Task Where_math_max_nested(bool async) @@ -1263,9 +1273,9 @@ public override async Task Where_math_max_nested(bool async) AssertSql( """ -SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice] -FROM [Order Details] AS [o] -WHERE [o].[OrderID] = 11077 AND GREATEST([o].[OrderID], [o].[ProductID], 1) = [o].[OrderID] +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` +FROM `Order Details` AS `o` +WHERE `o`.`OrderID` = 11077 AND IIF(IIF(`o`.`OrderID` > `o`.`ProductID`, `o`.`OrderID`, `o`.`ProductID`) > 1, IIF(`o`.`OrderID` > `o`.`ProductID`, `o`.`OrderID`, `o`.`ProductID`), 1) = `o`.`OrderID` """); } @@ -1275,9 +1285,9 @@ public override async Task Where_math_max_nested_twice(bool async) AssertSql( """ -SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice] -FROM [Order Details] AS [o] -WHERE [o].[OrderID] = 11077 AND GREATEST(1, [o].[OrderID], 2, [o].[ProductID]) = [o].[OrderID] +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` +FROM `Order Details` AS `o` +WHERE `o`.`OrderID` = 11077 AND IIF(IIF(IIF(1 > `o`.`OrderID`, 1, `o`.`OrderID`) > 2, IIF(1 > `o`.`OrderID`, 1, `o`.`OrderID`), 2) > `o`.`ProductID`, IIF(IIF(1 > `o`.`OrderID`, 1, `o`.`OrderID`) > 2, IIF(1 > `o`.`OrderID`, 1, `o`.`OrderID`), 2), `o`.`ProductID`) = `o`.`OrderID` """); } From bc9c18397c53cf1c872a71a7662fa77d23e1285e Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 13 Oct 2024 13:29:29 +0000 Subject: [PATCH 2/2] [GitHub Actions] Update green tests. --- .../GreenTests/ace_2010_odbc_x86.txt | 8 ++++++++ .../GreenTests/ace_2010_oledb_x86.txt | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_odbc_x86.txt b/test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_odbc_x86.txt index 8be808ee..c0cd8e7d 100644 --- a/test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_odbc_x86.txt +++ b/test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_odbc_x86.txt @@ -13238,8 +13238,16 @@ EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Whe EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_log(isAsync: True) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_log10(isAsync: False) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_log10(isAsync: True) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_max_nested_twice(async: False) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_max_nested_twice(async: True) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_max_nested(async: False) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_max_nested(async: True) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_max(async: False) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_max(async: True) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_min_nested_twice(async: False) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_min_nested_twice(async: True) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_min_nested(async: False) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_min_nested(async: True) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_min(async: False) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_min(async: True) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_power(isAsync: False) diff --git a/test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_oledb_x86.txt b/test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_oledb_x86.txt index a7051d59..01e30e8f 100644 --- a/test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_oledb_x86.txt +++ b/test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_oledb_x86.txt @@ -14528,8 +14528,16 @@ EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Whe EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_log(isAsync: True) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_log10(isAsync: False) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_log10(isAsync: True) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_max_nested_twice(async: False) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_max_nested_twice(async: True) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_max_nested(async: False) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_max_nested(async: True) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_max(async: False) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_max(async: True) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_min_nested_twice(async: False) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_min_nested_twice(async: True) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_min_nested(async: False) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_min_nested(async: True) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_min(async: False) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_min(async: True) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_math_power(isAsync: False)