From 93564ffe7d5332dc305be2217402e7d3a6625e34 Mon Sep 17 00:00:00 2001 From: MaRK0960 Date: Mon, 27 Jun 2022 21:46:01 +0200 Subject: [PATCH 01/11] Added tests against x.Parse(string) --- .../Query/NorthwindFunctionsQueryTestBase.cs | 66 +++++++++++++++++++ .../NorthwindFunctionsQuerySqlServerTest.cs | 60 +++++++++++++++++ 2 files changed, 126 insertions(+) diff --git a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs index d2da16bccf9..f5858064f75 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs @@ -1479,6 +1479,72 @@ public virtual async Task Convert_ToString(bool async) } } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Byte_Parse(bool async) + { + await AssertQuery( + async, + ss => ss.Set().Where(o => o.CustomerID == "ALFKI") + .Where(o => byte.Parse(Convert.ToString(o.OrderID % 1)) >= 0), + entryCount: 6); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Decimal_Parse(bool async) + { + await AssertQuery( + async, + ss => ss.Set().Where(o => o.CustomerID == "ALFKI") + .Where(o => decimal.Parse(Convert.ToString(o.OrderID % 1)) >= 0), + entryCount: 6); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Double_Parse(bool async) + { + await AssertQuery( + async, + ss => ss.Set().Where(o => o.CustomerID == "ALFKI") + .Where(o => double.Parse(Convert.ToString(o.OrderID % 1)) >= 0), + entryCount: 6); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Short_Parse(bool async) + { + await AssertQuery( + async, + ss => ss.Set().Where(o => o.CustomerID == "ALFKI") + .Where(o => short.Parse(Convert.ToString(o.OrderID % 1)) >= 0), + entryCount: 6); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Int_Parse(bool async) + { + await AssertQuery( + async, + ss => ss.Set().Where(o => o.CustomerID == "ALFKI") + .Where(o => int.Parse(Convert.ToString(o.OrderID % 1)) >= 0), + entryCount: 6); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Long_Parse(bool async) + { + await AssertQuery( + async, + ss => ss.Set().Where(o => o.CustomerID == "ALFKI") + .Where(o => long.Parse(Convert.ToString(o.OrderID % 1)) >= 0), + entryCount: 6); + } + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Indexof_with_emptystring(bool async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs index 8b58746c66d..fb699b05cb7 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs @@ -1618,6 +1618,66 @@ public override async Task Convert_ToString(bool async) WHERE [o].[CustomerID] = N'ALFKI' AND ((CONVERT(nvarchar(max), [o].[OrderDate]) LIKE N'%1997%') OR (CONVERT(nvarchar(max), [o].[OrderDate]) LIKE N'%1998%'))"); } + public override async Task Byte_Parse(bool async) + { + await base.Byte_Parse(async); + + AssertSql( + @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM [Orders] AS [o] +WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(tinyint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS tinyint)"); + } + + public override async Task Decimal_Parse(bool async) + { + await base.Decimal_Parse(async); + + AssertSql( + @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM [Orders] AS [o] +WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(decimal(18, 2), CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0.0"); + } + + public override async Task Double_Parse(bool async) + { + await base.Double_Parse(async); + + AssertSql( + @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM [Orders] AS [o] +WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(float, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0.0E0"); + } + + public override async Task Short_Parse(bool async) + { + await base.Short_Parse(async); + + AssertSql( + @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM [Orders] AS [o] +WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(smallint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS smallint)"); + } + + public override async Task Int_Parse(bool async) + { + await base.Int_Parse(async); + + AssertSql( + @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM [Orders] AS [o] +WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(int, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0"); + } + + public override async Task Long_Parse(bool async) + { + await base.Long_Parse(async); + + AssertSql( + @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM [Orders] AS [o] +WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(bigint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS bigint)"); + } + public override async Task Indexof_with_emptystring(bool async) { await base.Indexof_with_emptystring(async); From 79b94e8d20f4d6ceac28d28420eac818953d80ef Mon Sep 17 00:00:00 2001 From: MaRK0960 Date: Mon, 27 Jun 2022 23:19:59 +0200 Subject: [PATCH 02/11] Added SqlServerParseTranslator --- .../SqlServerMethodCallTranslatorProvider.cs | 1 + .../Internal/SqlServerParseTranslator.cs | 68 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerMethodCallTranslatorProvider.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerMethodCallTranslatorProvider.cs index 2b977dc7ba3..b254cdd93e7 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerMethodCallTranslatorProvider.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerMethodCallTranslatorProvider.cs @@ -27,6 +27,7 @@ public SqlServerMethodCallTranslatorProvider(RelationalMethodCallTranslatorProvi { new SqlServerByteArrayMethodTranslator(sqlExpressionFactory), new SqlServerConvertTranslator(sqlExpressionFactory), + new SqlServerParseTranslator(sqlExpressionFactory), new SqlServerDataLengthFunctionTranslator(sqlExpressionFactory), new SqlServerDateDiffFunctionsTranslator(sqlExpressionFactory), new SqlServerDateTimeMethodTranslator(sqlExpressionFactory, typeMappingSource), diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs new file mode 100644 index 00000000000..9d4712b1ac8 --- /dev/null +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs @@ -0,0 +1,68 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.EntityFrameworkCore.Query.SqlExpressions; + +namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal; + +/// +/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to +/// the same compatibility standards as public APIs. It may be changed or removed without notice in +/// any release. You should only use it directly in your code with extreme caution and knowing that +/// doing so can result in application failures when updating to a new Entity Framework Core release. +/// +public class SqlServerParseTranslator : IMethodCallTranslator +{ + private static readonly Dictionary TypeMapping = new() + { + [typeof(bool)] = "bit", + [typeof(byte)] = "tinyint", + [typeof(decimal)] = "decimal(18, 2)", + [typeof(double)] = "float", + [typeof(float)] = "float", + [typeof(short)] = "smallint", + [typeof(int)] = "int", + [typeof(long)] = "bigint" + }; + + private static readonly IEnumerable SupportedMethods + = TypeMapping.Keys + .SelectMany( + t => t.GetTypeInfo().GetDeclaredMethods("Parse") + .Where( + m => m.GetParameters().Length == 1 + && m.GetParameters().First().ParameterType == typeof(string))); + + private readonly ISqlExpressionFactory _sqlExpressionFactory; + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public SqlServerParseTranslator(ISqlExpressionFactory sqlExpressionFactory) + { + _sqlExpressionFactory = sqlExpressionFactory; + } + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public virtual SqlExpression? Translate( + SqlExpression? instance, + MethodInfo method, + IReadOnlyList arguments, + IDiagnosticsLogger logger) + => SupportedMethods.Contains(method) + ? _sqlExpressionFactory.Function( + "CONVERT", + new[] { _sqlExpressionFactory.Fragment(TypeMapping[method.DeclaringType!]), arguments[0] }, + nullable: true, + argumentsPropagateNullability: new[] { false, true }, + method.ReturnType) + : null; +} From 92401eb8bbb9bf1aa1b82fa45e0dcb1046180ccc Mon Sep 17 00:00:00 2001 From: MaRK0960 Date: Tue, 28 Jun 2022 20:16:41 +0200 Subject: [PATCH 03/11] Add failing tests in Sqlite and Cosmos --- .../NorthwindFunctionsQueryCosmosTest.cs | 48 +++++++++++++++++++ .../NorthwindFunctionsQuerySqliteTest.cs | 18 +++++++ 2 files changed, 66 insertions(+) diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs index a67e1e4ced6..2f3e2907b75 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs @@ -815,6 +815,54 @@ public override async Task Convert_ToString(bool async) AssertSql(); } + public override async Task Byte_Parse(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Byte_Parse(async)); + + AssertSql(); + } + + public override async Task Decimal_Parse(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Decimal_Parse(async)); + + AssertSql(); + } + + public override async Task Double_Parse(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Double_Parse(async)); + + AssertSql(); + } + + public override async Task Short_Parse(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Short_Parse(async)); + + AssertSql(); + } + + public override async Task Int_Parse(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Int_Parse(async)); + + AssertSql(); + } + + public override async Task Long_Parse(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Long_Parse(async)); + + AssertSql(); + } + public override async Task Indexof_with_emptystring(bool async) { await base.Indexof_with_emptystring(async); diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs index 3e79290721e..eba0dd4acc2 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs @@ -39,6 +39,24 @@ public override Task Convert_ToInt64(bool async) public override Task Convert_ToString(bool async) => AssertTranslationFailed(() => base.Convert_ToString(async)); + public override Task Byte_Parse(bool async) + => AssertTranslationFailed(() => base.Byte_Parse(async)); + + public override Task Decimal_Parse(bool async) + => AssertTranslationFailed(() => base.Decimal_Parse(async)); + + public override Task Double_Parse(bool async) + => AssertTranslationFailed(() => base.Double_Parse(async)); + + public override Task Short_Parse(bool async) + => AssertTranslationFailed(() => base.Short_Parse(async)); + + public override Task Int_Parse(bool async) + => AssertTranslationFailed(() => base.Int_Parse(async)); + + public override Task Long_Parse(bool async) + => AssertTranslationFailed(() => base.Long_Parse(async)); + public override Task Projecting_Math_Truncate_and_ordering_by_it_twice(bool async) => AssertTranslationFailed(() => base.Projecting_Math_Truncate_and_ordering_by_it_twice(async)); From c758b48f1458740ced662819159e4d6688ff1d67 Mon Sep 17 00:00:00 2001 From: MaRK0960 Date: Wed, 29 Jun 2022 20:25:17 +0200 Subject: [PATCH 04/11] Order translators alphabetically --- .../Query/Internal/SqlServerMethodCallTranslatorProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerMethodCallTranslatorProvider.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerMethodCallTranslatorProvider.cs index b254cdd93e7..7bf3e86b179 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerMethodCallTranslatorProvider.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerMethodCallTranslatorProvider.cs @@ -27,7 +27,6 @@ public SqlServerMethodCallTranslatorProvider(RelationalMethodCallTranslatorProvi { new SqlServerByteArrayMethodTranslator(sqlExpressionFactory), new SqlServerConvertTranslator(sqlExpressionFactory), - new SqlServerParseTranslator(sqlExpressionFactory), new SqlServerDataLengthFunctionTranslator(sqlExpressionFactory), new SqlServerDateDiffFunctionsTranslator(sqlExpressionFactory), new SqlServerDateTimeMethodTranslator(sqlExpressionFactory, typeMappingSource), @@ -38,6 +37,7 @@ public SqlServerMethodCallTranslatorProvider(RelationalMethodCallTranslatorProvi new SqlServerMathTranslator(sqlExpressionFactory), new SqlServerNewGuidTranslator(sqlExpressionFactory), new SqlServerObjectToStringTranslator(sqlExpressionFactory), + new SqlServerParseTranslator(sqlExpressionFactory), new SqlServerStringMethodTranslator(sqlExpressionFactory) }); } From 2acf36279298a8101f6ff0f95f95830bd30d0019 Mon Sep 17 00:00:00 2001 From: MaRK0960 Date: Wed, 29 Jun 2022 21:43:14 +0200 Subject: [PATCH 05/11] Renamed TypeMapping to ClrTypeToStoreTypeMap --- .../Query/Internal/SqlServerParseTranslator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs index 9d4712b1ac8..fa8eb1b8ada 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs @@ -13,7 +13,7 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal; /// public class SqlServerParseTranslator : IMethodCallTranslator { - private static readonly Dictionary TypeMapping = new() + private static readonly Dictionary ClrTypeToStoreTypeMap = new() { [typeof(bool)] = "bit", [typeof(byte)] = "tinyint", @@ -26,7 +26,7 @@ public class SqlServerParseTranslator : IMethodCallTranslator }; private static readonly IEnumerable SupportedMethods - = TypeMapping.Keys + = ClrTypeToStoreTypeMap.Keys .SelectMany( t => t.GetTypeInfo().GetDeclaredMethods("Parse") .Where( @@ -60,7 +60,7 @@ public SqlServerParseTranslator(ISqlExpressionFactory sqlExpressionFactory) => SupportedMethods.Contains(method) ? _sqlExpressionFactory.Function( "CONVERT", - new[] { _sqlExpressionFactory.Fragment(TypeMapping[method.DeclaringType!]), arguments[0] }, + new[] { _sqlExpressionFactory.Fragment(ClrTypeToStoreTypeMap[method.DeclaringType!]), arguments[0] }, nullable: true, argumentsPropagateNullability: new[] { false, true }, method.ReturnType) From 3976d4ba8504d422f94aab779fbaee2ca819db1f Mon Sep 17 00:00:00 2001 From: MaRK0960 Date: Thu, 7 Jul 2022 23:37:15 +0200 Subject: [PATCH 06/11] Added more tests. Added tests against overflow. Added tests against bad format. --- .../NorthwindFunctionsQueryCosmosTest.cs | 104 ++++++++++ .../NorthwindFunctionsQueryInMemoryTest.cs | 52 +++++ .../Query/NorthwindFunctionsQueryTestBase.cs | 195 ++++++++++++++++++ .../NorthwindFunctionsQuerySqlServerTest.cs | 169 ++++++++++++++- .../NorthwindFunctionsQuerySqliteTest.cs | 41 +++- 5 files changed, 554 insertions(+), 7 deletions(-) diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs index 2f3e2907b75..c42c3affa1c 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs @@ -823,6 +823,38 @@ public override async Task Byte_Parse(bool async) AssertSql(); } + public override async Task Byte_Parse_Non_Numeric_Bad_Format(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Byte_Parse_Non_Numeric_Bad_Format(async)); + + AssertSql(); + } + + public override async Task Byte_Parse_Greater_Than_Max_Value_Overflows(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Byte_Parse_Greater_Than_Max_Value_Overflows(async)); + + AssertSql(); + } + + public override async Task Byte_Parse_Negative_Overflows(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Byte_Parse_Negative_Overflows(async)); + + AssertSql(); + } + + public override async Task Byte_Parse_Decimal_Bad_Format(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Byte_Parse_Decimal_Bad_Format(async)); + + AssertSql(); + } + public override async Task Decimal_Parse(bool async) { // Cosmos client evaluation. Issue #17246. @@ -831,6 +863,14 @@ public override async Task Decimal_Parse(bool async) AssertSql(); } + public override async Task Decimal_Parse_Non_Numeric_Bad_Format(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Decimal_Parse_Non_Numeric_Bad_Format(async)); + + AssertSql(); + } + public override async Task Double_Parse(bool async) { // Cosmos client evaluation. Issue #17246. @@ -839,6 +879,14 @@ public override async Task Double_Parse(bool async) AssertSql(); } + public override async Task Double_Parse_Non_Numeric_Bad_Format(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Double_Parse_Non_Numeric_Bad_Format(async)); + + AssertSql(); + } + public override async Task Short_Parse(bool async) { // Cosmos client evaluation. Issue #17246. @@ -847,6 +895,30 @@ public override async Task Short_Parse(bool async) AssertSql(); } + public override async Task Short_Parse_Non_Numeric_Bad_Format(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Short_Parse_Non_Numeric_Bad_Format(async)); + + AssertSql(); + } + + public override async Task Short_Parse_Greater_Than_Max_Value_Overflows(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Short_Parse_Greater_Than_Max_Value_Overflows(async)); + + AssertSql(); + } + + public override async Task Short_Parse_Decimal_Bad_Format(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Short_Parse_Decimal_Bad_Format(async)); + + AssertSql(); + } + public override async Task Int_Parse(bool async) { // Cosmos client evaluation. Issue #17246. @@ -855,6 +927,22 @@ public override async Task Int_Parse(bool async) AssertSql(); } + public override async Task Int_Parse_Non_Numeric_Bad_Format(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Int_Parse_Non_Numeric_Bad_Format(async)); + + AssertSql(); + } + + public override async Task Int_Parse_Decimal_Bad_Format(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Int_Parse_Decimal_Bad_Format(async)); + + AssertSql(); + } + public override async Task Long_Parse(bool async) { // Cosmos client evaluation. Issue #17246. @@ -863,6 +951,22 @@ public override async Task Long_Parse(bool async) AssertSql(); } + public override async Task Long_Parse_Non_Numeric_Bad_Format(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Long_Parse_Non_Numeric_Bad_Format(async)); + + AssertSql(); + } + + public override async Task Long_Parse_Decimal_Bad_Format(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Long_Parse_Decimal_Bad_Format(async)); + + AssertSql(); + } + public override async Task Indexof_with_emptystring(bool async) { await base.Indexof_with_emptystring(async); diff --git a/test/EFCore.InMemory.FunctionalTests/Query/NorthwindFunctionsQueryInMemoryTest.cs b/test/EFCore.InMemory.FunctionalTests/Query/NorthwindFunctionsQueryInMemoryTest.cs index 0963a03494e..c80a025a1ff 100644 --- a/test/EFCore.InMemory.FunctionalTests/Query/NorthwindFunctionsQueryInMemoryTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/Query/NorthwindFunctionsQueryInMemoryTest.cs @@ -14,4 +14,56 @@ public class NorthwindFunctionsQueryInMemoryTest : NorthwindFunctionsQueryTestBa { //TestLoggerFactory.TestOutputHelper = testOutputHelper; } + + public override Task Byte_Parse_Non_Numeric_Bad_Format(bool async) + => Assert.ThrowsAsync( + () => base.Byte_Parse_Non_Numeric_Bad_Format(async)); + + public override Task Byte_Parse_Greater_Than_Max_Value_Overflows(bool async) + => Assert.ThrowsAsync( + () => base.Byte_Parse_Greater_Than_Max_Value_Overflows(async)); + + public override Task Byte_Parse_Negative_Overflows(bool async) + => Assert.ThrowsAsync( + () => base.Byte_Parse_Negative_Overflows(async)); + + public override Task Byte_Parse_Decimal_Bad_Format(bool async) + => Assert.ThrowsAsync( + () => base.Byte_Parse_Decimal_Bad_Format(async)); + + public override Task Decimal_Parse_Non_Numeric_Bad_Format(bool async) + => Assert.ThrowsAsync( + () => base.Decimal_Parse_Non_Numeric_Bad_Format(async)); + + public override Task Double_Parse_Non_Numeric_Bad_Format(bool async) + => Assert.ThrowsAsync( + () => base.Double_Parse_Non_Numeric_Bad_Format(async)); + + public override Task Short_Parse_Non_Numeric_Bad_Format(bool async) + => Assert.ThrowsAsync( + () => base.Short_Parse_Non_Numeric_Bad_Format(async)); + + public override Task Short_Parse_Greater_Than_Max_Value_Overflows(bool async) + => Assert.ThrowsAsync( + () => base.Short_Parse_Greater_Than_Max_Value_Overflows(async)); + + public override Task Short_Parse_Decimal_Bad_Format(bool async) + => Assert.ThrowsAsync( + () => base.Short_Parse_Decimal_Bad_Format(async)); + + public override Task Int_Parse_Non_Numeric_Bad_Format(bool async) + => Assert.ThrowsAsync( + () => base.Int_Parse_Non_Numeric_Bad_Format(async)); + + public override Task Int_Parse_Decimal_Bad_Format(bool async) + => Assert.ThrowsAsync( + () => base.Int_Parse_Decimal_Bad_Format(async)); + + public override Task Long_Parse_Non_Numeric_Bad_Format(bool async) + => Assert.ThrowsAsync( + () => base.Long_Parse_Non_Numeric_Bad_Format(async)); + + public override Task Long_Parse_Decimal_Bad_Format(bool async) + => Assert.ThrowsAsync( + () => base.Long_Parse_Decimal_Bad_Format(async)); } diff --git a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs index f5858064f75..43a66ad167f 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs @@ -1488,8 +1488,50 @@ public virtual async Task Byte_Parse(bool async) ss => ss.Set().Where(o => o.CustomerID == "ALFKI") .Where(o => byte.Parse(Convert.ToString(o.OrderID % 1)) >= 0), entryCount: 6); + + await AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID == "ALFKI") + .Where(c => byte.Parse(c.Phone.Substring(0, 3)) == 30), + entryCount: 1); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Byte_Parse_Non_Numeric_Bad_Format(bool async) + => AssertQueryScalar( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "ALFKI") + .Select(c => byte.Parse(c.CustomerID))); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Byte_Parse_Greater_Than_Max_Value_Overflows(bool async) + => AssertQueryScalar( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "ALFKI") + .Select(c => byte.Parse(c.PostalCode))); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Byte_Parse_Negative_Overflows(bool async) + => AssertQueryScalar( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "ALFKI") + .Select(c => byte.Parse(c.Phone.Substring(3, 4)))); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Byte_Parse_Decimal_Bad_Format(bool async) + => AssertQueryScalar( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "BLONP") + .Select(c => byte.Parse(c.Phone.Substring(0, 4)))); + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task Decimal_Parse(bool async) @@ -1499,8 +1541,35 @@ public virtual async Task Decimal_Parse(bool async) ss => ss.Set().Where(o => o.CustomerID == "ALFKI") .Where(o => decimal.Parse(Convert.ToString(o.OrderID % 1)) >= 0), entryCount: 6); + + await AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID == "ALFKI") + .Where(c => decimal.Parse(c.PostalCode) == 12209m), + entryCount: 1); + + await AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID == "BLONP") + .Where(c => decimal.Parse(c.Phone.Substring(0, 4)) == 88.6m), + entryCount: 1); + + await AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID == "ALFKI") + .Where(c => decimal.Parse(c.Phone.Substring(3, 4)) == -7m), + entryCount: 1); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Decimal_Parse_Non_Numeric_Bad_Format(bool async) + => AssertQueryScalar( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "ALFKI") + .Select(c => decimal.Parse(c.CustomerID))); + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task Double_Parse(bool async) @@ -1510,8 +1579,35 @@ public virtual async Task Double_Parse(bool async) ss => ss.Set().Where(o => o.CustomerID == "ALFKI") .Where(o => double.Parse(Convert.ToString(o.OrderID % 1)) >= 0), entryCount: 6); + + await AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID == "ALFKI") + .Where(c => double.Parse(c.PostalCode) == 12209d), + entryCount: 1); + + await AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID == "BLONP") + .Where(c => double.Parse(c.Phone.Substring(0, 4)) == 88.6d), + entryCount: 1); + + await AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID == "ALFKI") + .Where(c => double.Parse(c.Phone.Substring(3, 4)) == -7d), + entryCount: 1); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Double_Parse_Non_Numeric_Bad_Format(bool async) + => AssertQueryScalar( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "ALFKI") + .Select(c => double.Parse(c.CustomerID))); + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task Short_Parse(bool async) @@ -1521,8 +1617,47 @@ public virtual async Task Short_Parse(bool async) ss => ss.Set().Where(o => o.CustomerID == "ALFKI") .Where(o => short.Parse(Convert.ToString(o.OrderID % 1)) >= 0), entryCount: 6); + + await AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID == "ALFKI") + .Where(c => short.Parse(c.PostalCode) == 12209), + entryCount: 1); + + await AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID == "ALFKI") + .Where(c => short.Parse(c.Phone.Substring(3, 4)) == -7), + entryCount: 1); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Short_Parse_Non_Numeric_Bad_Format(bool async) + => AssertQueryScalar( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "ALFKI") + .Select(c => short.Parse(c.CustomerID))); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Short_Parse_Greater_Than_Max_Value_Overflows(bool async) + => AssertQueryScalar( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "BLAUS") + .Select(c => short.Parse(c.PostalCode))); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Short_Parse_Decimal_Bad_Format(bool async) + => AssertQueryScalar( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "BLONP") + .Select(c => short.Parse(c.Phone.Substring(0, 4)))); + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task Int_Parse(bool async) @@ -1532,8 +1667,38 @@ public virtual async Task Int_Parse(bool async) ss => ss.Set().Where(o => o.CustomerID == "ALFKI") .Where(o => int.Parse(Convert.ToString(o.OrderID % 1)) >= 0), entryCount: 6); + + await AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID == "ALFKI") + .Where(c => int.Parse(c.PostalCode) == 12209), + entryCount: 1); + + await AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID == "ALFKI") + .Where(c => int.Parse(c.Phone.Substring(3, 4)) == -7), + entryCount: 1); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Int_Parse_Non_Numeric_Bad_Format(bool async) + => AssertQueryScalar( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "ALFKI") + .Select(c => int.Parse(c.CustomerID))); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Int_Parse_Decimal_Bad_Format(bool async) + => AssertQueryScalar( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "BLONP") + .Select(c => int.Parse(c.Phone.Substring(0, 4)))); + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual async Task Long_Parse(bool async) @@ -1543,8 +1708,38 @@ public virtual async Task Long_Parse(bool async) ss => ss.Set().Where(o => o.CustomerID == "ALFKI") .Where(o => long.Parse(Convert.ToString(o.OrderID % 1)) >= 0), entryCount: 6); + + await AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID == "ALFKI") + .Where(c => long.Parse(c.PostalCode) == 12209L), + entryCount: 1); + + await AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID == "ALFKI") + .Where(c => long.Parse(c.Phone.Substring(3, 4)) == -7L), + entryCount: 1); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Long_Parse_Non_Numeric_Bad_Format(bool async) + => AssertQueryScalar( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "ALFKI") + .Select(c => long.Parse(c.CustomerID))); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Long_Parse_Decimal_Bad_Format(bool async) + => AssertQueryScalar( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "BLONP") + .Select(c => long.Parse(c.Phone.Substring(0, 4)))); + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Indexof_with_emptystring(bool async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs index fb699b05cb7..8d0e06c63c1 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore.TestModels.Northwind; namespace Microsoft.EntityFrameworkCore.Query; @@ -1625,7 +1626,43 @@ public override async Task Byte_Parse(bool async) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(tinyint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS tinyint)"); +WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(tinyint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS tinyint)", + // + @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM [Customers] AS [c] +WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(tinyint, SUBSTRING([c].[Phone], 0 + 1, 3)) = CAST(30 AS tinyint)"); + } + + public override async Task Byte_Parse_Non_Numeric_Bad_Format(bool async) + { + var exception = await Assert.ThrowsAsync( + () => base.Byte_Parse_Non_Numeric_Bad_Format(async)); + + Assert.Equal(245, exception.Number); //245 is a database engine error for failed conversion because of unsuitable data type + } + + public override async Task Byte_Parse_Greater_Than_Max_Value_Overflows(bool async) + { + var exception = await Assert.ThrowsAsync( + () => base.Byte_Parse_Greater_Than_Max_Value_Overflows(async)); + + Assert.Equal(244, exception.Number); //244 is a database engine error for failed conversion because of overflow + } + + public override async Task Byte_Parse_Negative_Overflows(bool async) + { + var exception = await Assert.ThrowsAsync( + () => base.Byte_Parse_Negative_Overflows(async)); + + Assert.Equal(244, exception.Number); //244 is a database engine error for failed conversion because of overflow + } + + public override async Task Byte_Parse_Decimal_Bad_Format(bool async) + { + var exception = await Assert.ThrowsAsync( + () => base.Byte_Parse_Decimal_Bad_Format(async)); + + Assert.Equal(245, exception.Number); //245 is a database engine error for failed conversion because of unsuitable data type } public override async Task Decimal_Parse(bool async) @@ -1635,7 +1672,27 @@ public override async Task Decimal_Parse(bool async) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(decimal(18, 2), CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0.0"); +WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(decimal(18, 2), CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0.0", + // + @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM [Customers] AS [c] +WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(decimal(18, 2), [c].[PostalCode]) = 12209.0", + // + @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM [Customers] AS [c] +WHERE [c].[CustomerID] = N'BLONP' AND CONVERT(decimal(18, 2), SUBSTRING([c].[Phone], 0 + 1, 4)) = 88.6", + // + @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM [Customers] AS [c] +WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(decimal(18, 2), SUBSTRING([c].[Phone], 3 + 1, 4)) = -7.0"); + } + + public override async Task Decimal_Parse_Non_Numeric_Bad_Format(bool async) + { + var exception = await Assert.ThrowsAsync( + () => base.Decimal_Parse_Non_Numeric_Bad_Format(async)); + + Assert.Equal(8114, exception.Number); //8114 is a database engine error for failed conversion because of unsuitable data type } public override async Task Double_Parse(bool async) @@ -1645,7 +1702,27 @@ public override async Task Double_Parse(bool async) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(float, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0.0E0"); +WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(float, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0.0E0", + // + @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM [Customers] AS [c] +WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(float, [c].[PostalCode]) = 12209.0E0", + // + @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM [Customers] AS [c] +WHERE [c].[CustomerID] = N'BLONP' AND CONVERT(float, SUBSTRING([c].[Phone], 0 + 1, 4)) = 88.599999999999994E0", + // + @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM [Customers] AS [c] +WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(float, SUBSTRING([c].[Phone], 3 + 1, 4)) = -7.0E0"); + } + + public override async Task Double_Parse_Non_Numeric_Bad_Format(bool async) + { + var exception = await Assert.ThrowsAsync( + () => base.Double_Parse_Non_Numeric_Bad_Format(async)); + + Assert.Equal(8114, exception.Number); //8114 is a database engine error for failed conversion because of unsuitable data type } public override async Task Short_Parse(bool async) @@ -1655,7 +1732,39 @@ public override async Task Short_Parse(bool async) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(smallint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS smallint)"); +WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(smallint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS smallint)", + // + @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM [Customers] AS [c] +WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(smallint, [c].[PostalCode]) = CAST(12209 AS smallint)", + // + @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM [Customers] AS [c] +WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(smallint, SUBSTRING([c].[Phone], 3 + 1, 4)) = CAST(-7 AS smallint)"); + } + + public override async Task Short_Parse_Non_Numeric_Bad_Format(bool async) + { + var exception = await Assert.ThrowsAsync( + () => base.Short_Parse_Non_Numeric_Bad_Format(async)); + + Assert.Equal(245, exception.Number); //245 is a database engine error for failed conversion because of unsuitable data type + } + + public override async Task Short_Parse_Greater_Than_Max_Value_Overflows(bool async) + { + var exception = await Assert.ThrowsAsync( + () => base.Short_Parse_Greater_Than_Max_Value_Overflows(async)); + + Assert.Equal(244, exception.Number); //244 is a database engine error for failed conversion because of overflow + } + + public override async Task Short_Parse_Decimal_Bad_Format(bool async) + { + var exception = await Assert.ThrowsAsync( + () => base.Short_Parse_Decimal_Bad_Format(async)); + + Assert.Equal(245, exception.Number); //245 is a database engine error for failed conversion because of unsuitable data type } public override async Task Int_Parse(bool async) @@ -1665,7 +1774,31 @@ public override async Task Int_Parse(bool async) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(int, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0"); +WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(int, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0", + // + @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM [Customers] AS [c] +WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(int, [c].[PostalCode]) = 12209", + // + @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM [Customers] AS [c] +WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(int, SUBSTRING([c].[Phone], 3 + 1, 4)) = -7"); + } + + public override async Task Int_Parse_Non_Numeric_Bad_Format(bool async) + { + var exception = await Assert.ThrowsAsync( + () => base.Int_Parse_Non_Numeric_Bad_Format(async)); + + Assert.Equal(245, exception.Number); //245 is a database engine error for failed conversion because of unsuitable data type + } + + public override async Task Int_Parse_Decimal_Bad_Format(bool async) + { + var exception = await Assert.ThrowsAsync( + () => base.Int_Parse_Decimal_Bad_Format(async)); + + Assert.Equal(245, exception.Number); //245 is a database engine error for failed conversion because of unsuitable data type } public override async Task Long_Parse(bool async) @@ -1675,7 +1808,31 @@ public override async Task Long_Parse(bool async) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(bigint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS bigint)"); +WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(bigint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS bigint)", + // + @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM [Customers] AS [c] +WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(bigint, [c].[PostalCode]) = CAST(12209 AS bigint)", + // + @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM [Customers] AS [c] +WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(bigint, SUBSTRING([c].[Phone], 3 + 1, 4)) = CAST(-7 AS bigint)"); + } + + public override async Task Long_Parse_Non_Numeric_Bad_Format(bool async) + { + var exception = await Assert.ThrowsAsync( + () => base.Long_Parse_Non_Numeric_Bad_Format(async)); + + Assert.Equal(8114, exception.Number); //8114 is a database engine error for failed conversion because of unsuitable data type + } + + public override async Task Long_Parse_Decimal_Bad_Format(bool async) + { + var exception = await Assert.ThrowsAsync( + () => base.Long_Parse_Decimal_Bad_Format(async)); + + Assert.Equal(8114, exception.Number); //8114 is a database engine error for failed conversion because of unsuitable data type } public override async Task Indexof_with_emptystring(bool async) diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs index eba0dd4acc2..bf0e27c57c6 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs @@ -40,23 +40,62 @@ public override Task Convert_ToString(bool async) => AssertTranslationFailed(() => base.Convert_ToString(async)); public override Task Byte_Parse(bool async) - => AssertTranslationFailed(() => base.Byte_Parse(async)); + => AssertTranslationFailed(() => base.Byte_Parse(async)); + + public override Task Byte_Parse_Non_Numeric_Bad_Format(bool async) + => Assert.ThrowsAsync(() => base.Byte_Parse_Non_Numeric_Bad_Format(async)); + + public override Task Byte_Parse_Greater_Than_Max_Value_Overflows(bool async) + => Assert.ThrowsAsync(() => base.Byte_Parse_Greater_Than_Max_Value_Overflows(async)); + + public override Task Byte_Parse_Negative_Overflows(bool async) + => Assert.ThrowsAsync(() => base.Byte_Parse_Negative_Overflows(async)); + + public override Task Byte_Parse_Decimal_Bad_Format(bool async) + => Assert.ThrowsAsync(() => base.Byte_Parse_Decimal_Bad_Format(async)); public override Task Decimal_Parse(bool async) => AssertTranslationFailed(() => base.Decimal_Parse(async)); + public override Task Decimal_Parse_Non_Numeric_Bad_Format(bool async) + => Assert.ThrowsAsync(() => base.Decimal_Parse_Non_Numeric_Bad_Format(async)); + public override Task Double_Parse(bool async) => AssertTranslationFailed(() => base.Double_Parse(async)); + public override Task Double_Parse_Non_Numeric_Bad_Format(bool async) + => Assert.ThrowsAsync(() => base.Double_Parse_Non_Numeric_Bad_Format(async)); + public override Task Short_Parse(bool async) => AssertTranslationFailed(() => base.Short_Parse(async)); + public override Task Short_Parse_Non_Numeric_Bad_Format(bool async) + => Assert.ThrowsAsync(() => base.Short_Parse_Non_Numeric_Bad_Format(async)); + + public override Task Short_Parse_Greater_Than_Max_Value_Overflows(bool async) + => Assert.ThrowsAsync(() => base.Short_Parse_Greater_Than_Max_Value_Overflows(async)); + + public override Task Short_Parse_Decimal_Bad_Format(bool async) + => Assert.ThrowsAsync(() => base.Short_Parse_Decimal_Bad_Format(async)); + public override Task Int_Parse(bool async) => AssertTranslationFailed(() => base.Int_Parse(async)); + public override Task Int_Parse_Non_Numeric_Bad_Format(bool async) + => Assert.ThrowsAsync(() => base.Int_Parse_Non_Numeric_Bad_Format(async)); + + public override Task Int_Parse_Decimal_Bad_Format(bool async) + => Assert.ThrowsAsync(() => base.Int_Parse_Decimal_Bad_Format(async)); + public override Task Long_Parse(bool async) => AssertTranslationFailed(() => base.Long_Parse(async)); + public override Task Long_Parse_Non_Numeric_Bad_Format(bool async) + => Assert.ThrowsAsync(() => base.Long_Parse_Non_Numeric_Bad_Format(async)); + + public override Task Long_Parse_Decimal_Bad_Format(bool async) + => Assert.ThrowsAsync(() => base.Long_Parse_Decimal_Bad_Format(async)); + public override Task Projecting_Math_Truncate_and_ordering_by_it_twice(bool async) => AssertTranslationFailed(() => base.Projecting_Math_Truncate_and_ordering_by_it_twice(async)); From 3a7e6a5796ad78856bac153b507b0e99424a92d6 Mon Sep 17 00:00:00 2001 From: MaRK0960 Date: Mon, 11 Jul 2022 13:05:41 +0200 Subject: [PATCH 07/11] Write cleaner code. nameof instead of string. Merge the Where clauses. --- .../Internal/SqlServerParseTranslator.cs | 2 +- .../Query/NorthwindFunctionsQueryTestBase.cs | 76 +++++++++---------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs index fa8eb1b8ada..ca0c042da7a 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs @@ -28,7 +28,7 @@ public class SqlServerParseTranslator : IMethodCallTranslator private static readonly IEnumerable SupportedMethods = ClrTypeToStoreTypeMap.Keys .SelectMany( - t => t.GetTypeInfo().GetDeclaredMethods("Parse") + t => t.GetTypeInfo().GetDeclaredMethods(nameof(int.Parse)) .Where( m => m.GetParameters().Length == 1 && m.GetParameters().First().ParameterType == typeof(string))); diff --git a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs index 43a66ad167f..55eb15a978d 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs @@ -1485,14 +1485,14 @@ public virtual async Task Byte_Parse(bool async) { await AssertQuery( async, - ss => ss.Set().Where(o => o.CustomerID == "ALFKI") - .Where(o => byte.Parse(Convert.ToString(o.OrderID % 1)) >= 0), + ss => ss.Set().Where(o => o.CustomerID == "ALFKI" && + byte.Parse(Convert.ToString(o.OrderID % 1)) >= 0), entryCount: 6); await AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "ALFKI") - .Where(c => byte.Parse(c.Phone.Substring(0, 3)) == 30), + ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && + byte.Parse(c.Phone.Substring(0, 3)) == 30), entryCount: 1); } @@ -1538,26 +1538,26 @@ public virtual async Task Decimal_Parse(bool async) { await AssertQuery( async, - ss => ss.Set().Where(o => o.CustomerID == "ALFKI") - .Where(o => decimal.Parse(Convert.ToString(o.OrderID % 1)) >= 0), + ss => ss.Set().Where(o => o.CustomerID == "ALFKI" && + decimal.Parse(Convert.ToString(o.OrderID % 1)) >= 0), entryCount: 6); await AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "ALFKI") - .Where(c => decimal.Parse(c.PostalCode) == 12209m), + ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && + decimal.Parse(c.PostalCode) == 12209m), entryCount: 1); await AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "BLONP") - .Where(c => decimal.Parse(c.Phone.Substring(0, 4)) == 88.6m), + ss => ss.Set().Where(c => c.CustomerID == "BLONP" && + decimal.Parse(c.Phone.Substring(0, 4)) == 88.6m), entryCount: 1); await AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "ALFKI") - .Where(c => decimal.Parse(c.Phone.Substring(3, 4)) == -7m), + ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && + decimal.Parse(c.Phone.Substring(3, 4)) == -7m), entryCount: 1); } @@ -1576,26 +1576,26 @@ public virtual async Task Double_Parse(bool async) { await AssertQuery( async, - ss => ss.Set().Where(o => o.CustomerID == "ALFKI") - .Where(o => double.Parse(Convert.ToString(o.OrderID % 1)) >= 0), + ss => ss.Set().Where(o => o.CustomerID == "ALFKI" && + double.Parse(Convert.ToString(o.OrderID % 1)) >= 0), entryCount: 6); await AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "ALFKI") - .Where(c => double.Parse(c.PostalCode) == 12209d), + ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && + double.Parse(c.PostalCode) == 12209d), entryCount: 1); await AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "BLONP") - .Where(c => double.Parse(c.Phone.Substring(0, 4)) == 88.6d), + ss => ss.Set().Where(c => c.CustomerID == "BLONP" && + double.Parse(c.Phone.Substring(0, 4)) == 88.6d), entryCount: 1); await AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "ALFKI") - .Where(c => double.Parse(c.Phone.Substring(3, 4)) == -7d), + ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && + double.Parse(c.Phone.Substring(3, 4)) == -7d), entryCount: 1); } @@ -1614,20 +1614,20 @@ public virtual async Task Short_Parse(bool async) { await AssertQuery( async, - ss => ss.Set().Where(o => o.CustomerID == "ALFKI") - .Where(o => short.Parse(Convert.ToString(o.OrderID % 1)) >= 0), + ss => ss.Set().Where(o => o.CustomerID == "ALFKI" && + short.Parse(Convert.ToString(o.OrderID % 1)) >= 0), entryCount: 6); await AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "ALFKI") - .Where(c => short.Parse(c.PostalCode) == 12209), + ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && + short.Parse(c.PostalCode) == 12209), entryCount: 1); await AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "ALFKI") - .Where(c => short.Parse(c.Phone.Substring(3, 4)) == -7), + ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && + short.Parse(c.Phone.Substring(3, 4)) == -7), entryCount: 1); } @@ -1664,20 +1664,20 @@ public virtual async Task Int_Parse(bool async) { await AssertQuery( async, - ss => ss.Set().Where(o => o.CustomerID == "ALFKI") - .Where(o => int.Parse(Convert.ToString(o.OrderID % 1)) >= 0), + ss => ss.Set().Where(o => o.CustomerID == "ALFKI" && + int.Parse(Convert.ToString(o.OrderID % 1)) >= 0), entryCount: 6); await AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "ALFKI") - .Where(c => int.Parse(c.PostalCode) == 12209), + ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && + int.Parse(c.PostalCode) == 12209), entryCount: 1); await AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "ALFKI") - .Where(c => int.Parse(c.Phone.Substring(3, 4)) == -7), + ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && + int.Parse(c.Phone.Substring(3, 4)) == -7), entryCount: 1); } @@ -1705,20 +1705,20 @@ public virtual async Task Long_Parse(bool async) { await AssertQuery( async, - ss => ss.Set().Where(o => o.CustomerID == "ALFKI") - .Where(o => long.Parse(Convert.ToString(o.OrderID % 1)) >= 0), + ss => ss.Set().Where(o => o.CustomerID == "ALFKI" && + long.Parse(Convert.ToString(o.OrderID % 1)) >= 0), entryCount: 6); await AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "ALFKI") - .Where(c => long.Parse(c.PostalCode) == 12209L), + ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && + long.Parse(c.PostalCode) == 12209L), entryCount: 1); await AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "ALFKI") - .Where(c => long.Parse(c.Phone.Substring(3, 4)) == -7L), + ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && + long.Parse(c.Phone.Substring(3, 4)) == -7L), entryCount: 1); } From 3f10651197075a206fff070e408efb60e835228d Mon Sep 17 00:00:00 2001 From: MaRK0960 Date: Mon, 11 Jul 2022 13:39:23 +0200 Subject: [PATCH 08/11] Remove redundant tests. --- .../Query/NorthwindFunctionsQueryTestBase.cs | 42 +------------------ .../NorthwindFunctionsQuerySqlServerTest.cs | 24 ----------- 2 files changed, 2 insertions(+), 64 deletions(-) diff --git a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs index 55eb15a978d..8236e52e668 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs @@ -1481,20 +1481,12 @@ public virtual async Task Convert_ToString(bool async) [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual async Task Byte_Parse(bool async) - { - await AssertQuery( - async, - ss => ss.Set().Where(o => o.CustomerID == "ALFKI" && - byte.Parse(Convert.ToString(o.OrderID % 1)) >= 0), - entryCount: 6); - - await AssertQuery( + public virtual Task Byte_Parse(bool async) + => AssertQuery( async, ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && byte.Parse(c.Phone.Substring(0, 3)) == 30), entryCount: 1); - } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] @@ -1536,12 +1528,6 @@ public virtual Task Byte_Parse_Decimal_Bad_Format(bool async) [MemberData(nameof(IsAsyncData))] public virtual async Task Decimal_Parse(bool async) { - await AssertQuery( - async, - ss => ss.Set().Where(o => o.CustomerID == "ALFKI" && - decimal.Parse(Convert.ToString(o.OrderID % 1)) >= 0), - entryCount: 6); - await AssertQuery( async, ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && @@ -1574,12 +1560,6 @@ public virtual Task Decimal_Parse_Non_Numeric_Bad_Format(bool async) [MemberData(nameof(IsAsyncData))] public virtual async Task Double_Parse(bool async) { - await AssertQuery( - async, - ss => ss.Set().Where(o => o.CustomerID == "ALFKI" && - double.Parse(Convert.ToString(o.OrderID % 1)) >= 0), - entryCount: 6); - await AssertQuery( async, ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && @@ -1612,12 +1592,6 @@ public virtual Task Double_Parse_Non_Numeric_Bad_Format(bool async) [MemberData(nameof(IsAsyncData))] public virtual async Task Short_Parse(bool async) { - await AssertQuery( - async, - ss => ss.Set().Where(o => o.CustomerID == "ALFKI" && - short.Parse(Convert.ToString(o.OrderID % 1)) >= 0), - entryCount: 6); - await AssertQuery( async, ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && @@ -1662,12 +1636,6 @@ public virtual Task Short_Parse_Decimal_Bad_Format(bool async) [MemberData(nameof(IsAsyncData))] public virtual async Task Int_Parse(bool async) { - await AssertQuery( - async, - ss => ss.Set().Where(o => o.CustomerID == "ALFKI" && - int.Parse(Convert.ToString(o.OrderID % 1)) >= 0), - entryCount: 6); - await AssertQuery( async, ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && @@ -1703,12 +1671,6 @@ public virtual Task Int_Parse_Decimal_Bad_Format(bool async) [MemberData(nameof(IsAsyncData))] public virtual async Task Long_Parse(bool async) { - await AssertQuery( - async, - ss => ss.Set().Where(o => o.CustomerID == "ALFKI" && - long.Parse(Convert.ToString(o.OrderID % 1)) >= 0), - entryCount: 6); - await AssertQuery( async, ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs index 8d0e06c63c1..8255d1587fb 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs @@ -1624,10 +1624,6 @@ public override async Task Byte_Parse(bool async) await base.Byte_Parse(async); AssertSql( - @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] -FROM [Orders] AS [o] -WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(tinyint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS tinyint)", - // @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(tinyint, SUBSTRING([c].[Phone], 0 + 1, 3)) = CAST(30 AS tinyint)"); @@ -1670,10 +1666,6 @@ public override async Task Decimal_Parse(bool async) await base.Decimal_Parse(async); AssertSql( - @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] -FROM [Orders] AS [o] -WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(decimal(18, 2), CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0.0", - // @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(decimal(18, 2), [c].[PostalCode]) = 12209.0", @@ -1700,10 +1692,6 @@ public override async Task Double_Parse(bool async) await base.Double_Parse(async); AssertSql( - @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] -FROM [Orders] AS [o] -WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(float, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0.0E0", - // @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(float, [c].[PostalCode]) = 12209.0E0", @@ -1730,10 +1718,6 @@ public override async Task Short_Parse(bool async) await base.Short_Parse(async); AssertSql( - @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] -FROM [Orders] AS [o] -WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(smallint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS smallint)", - // @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(smallint, [c].[PostalCode]) = CAST(12209 AS smallint)", @@ -1772,10 +1756,6 @@ public override async Task Int_Parse(bool async) await base.Int_Parse(async); AssertSql( - @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] -FROM [Orders] AS [o] -WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(int, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0", - // @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(int, [c].[PostalCode]) = 12209", @@ -1806,10 +1786,6 @@ public override async Task Long_Parse(bool async) await base.Long_Parse(async); AssertSql( - @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] -FROM [Orders] AS [o] -WHERE [o].[CustomerID] = N'ALFKI' AND CONVERT(bigint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS bigint)", - // @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(bigint, [c].[PostalCode]) = CAST(12209 AS bigint)", From cf0f4ae841709ecafe0e1f2283c7b02e5cfa122c Mon Sep 17 00:00:00 2001 From: MaRK0960 Date: Tue, 25 Apr 2023 14:55:28 +0200 Subject: [PATCH 09/11] Parse and Convert are not implemented in Sqlite, so exceptions thrown will be from client. --- .../NorthwindFunctionsQuerySqliteTest.cs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs index bf0e27c57c6..6d6b4465523 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs @@ -43,58 +43,58 @@ public override Task Byte_Parse(bool async) => AssertTranslationFailed(() => base.Byte_Parse(async)); public override Task Byte_Parse_Non_Numeric_Bad_Format(bool async) - => Assert.ThrowsAsync(() => base.Byte_Parse_Non_Numeric_Bad_Format(async)); + => AssertTranslationFailed(() => base.Byte_Parse_Non_Numeric_Bad_Format(async)); public override Task Byte_Parse_Greater_Than_Max_Value_Overflows(bool async) - => Assert.ThrowsAsync(() => base.Byte_Parse_Greater_Than_Max_Value_Overflows(async)); + => AssertTranslationFailed(() => base.Byte_Parse_Greater_Than_Max_Value_Overflows(async)); public override Task Byte_Parse_Negative_Overflows(bool async) - => Assert.ThrowsAsync(() => base.Byte_Parse_Negative_Overflows(async)); + => AssertTranslationFailed(() => base.Byte_Parse_Negative_Overflows(async)); public override Task Byte_Parse_Decimal_Bad_Format(bool async) - => Assert.ThrowsAsync(() => base.Byte_Parse_Decimal_Bad_Format(async)); + => AssertTranslationFailed(() => base.Byte_Parse_Decimal_Bad_Format(async)); public override Task Decimal_Parse(bool async) => AssertTranslationFailed(() => base.Decimal_Parse(async)); public override Task Decimal_Parse_Non_Numeric_Bad_Format(bool async) - => Assert.ThrowsAsync(() => base.Decimal_Parse_Non_Numeric_Bad_Format(async)); + => AssertTranslationFailed(() => base.Decimal_Parse_Non_Numeric_Bad_Format(async)); public override Task Double_Parse(bool async) => AssertTranslationFailed(() => base.Double_Parse(async)); public override Task Double_Parse_Non_Numeric_Bad_Format(bool async) - => Assert.ThrowsAsync(() => base.Double_Parse_Non_Numeric_Bad_Format(async)); + => AssertTranslationFailed(() => base.Double_Parse_Non_Numeric_Bad_Format(async)); public override Task Short_Parse(bool async) => AssertTranslationFailed(() => base.Short_Parse(async)); public override Task Short_Parse_Non_Numeric_Bad_Format(bool async) - => Assert.ThrowsAsync(() => base.Short_Parse_Non_Numeric_Bad_Format(async)); + => AssertTranslationFailed(() => base.Short_Parse_Non_Numeric_Bad_Format(async)); public override Task Short_Parse_Greater_Than_Max_Value_Overflows(bool async) - => Assert.ThrowsAsync(() => base.Short_Parse_Greater_Than_Max_Value_Overflows(async)); + => AssertTranslationFailed(() => base.Short_Parse_Greater_Than_Max_Value_Overflows(async)); public override Task Short_Parse_Decimal_Bad_Format(bool async) - => Assert.ThrowsAsync(() => base.Short_Parse_Decimal_Bad_Format(async)); + => AssertTranslationFailed(() => base.Short_Parse_Decimal_Bad_Format(async)); public override Task Int_Parse(bool async) => AssertTranslationFailed(() => base.Int_Parse(async)); public override Task Int_Parse_Non_Numeric_Bad_Format(bool async) - => Assert.ThrowsAsync(() => base.Int_Parse_Non_Numeric_Bad_Format(async)); + => AssertTranslationFailed(() => base.Int_Parse_Non_Numeric_Bad_Format(async)); public override Task Int_Parse_Decimal_Bad_Format(bool async) - => Assert.ThrowsAsync(() => base.Int_Parse_Decimal_Bad_Format(async)); + => AssertTranslationFailed(() => base.Int_Parse_Decimal_Bad_Format(async)); public override Task Long_Parse(bool async) => AssertTranslationFailed(() => base.Long_Parse(async)); public override Task Long_Parse_Non_Numeric_Bad_Format(bool async) - => Assert.ThrowsAsync(() => base.Long_Parse_Non_Numeric_Bad_Format(async)); + => AssertTranslationFailed(() => base.Long_Parse_Non_Numeric_Bad_Format(async)); public override Task Long_Parse_Decimal_Bad_Format(bool async) - => Assert.ThrowsAsync(() => base.Long_Parse_Decimal_Bad_Format(async)); + => AssertTranslationFailed(() => base.Long_Parse_Decimal_Bad_Format(async)); public override Task Projecting_Math_Truncate_and_ordering_by_it_twice(bool async) => AssertTranslationFailed(() => base.Projecting_Math_Truncate_and_ordering_by_it_twice(async)); From d9447cb4435ea8c75a439d9c304c2460773c08ff Mon Sep 17 00:00:00 2001 From: MaRK0960 Date: Tue, 25 Apr 2023 15:08:32 +0200 Subject: [PATCH 10/11] The tested invocation should be in the Where clause --- .../Query/NorthwindFunctionsQueryTestBase.cs | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs index 8236e52e668..0c053707f40 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs @@ -1491,38 +1491,38 @@ public virtual Task Byte_Parse(bool async) [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Byte_Parse_Non_Numeric_Bad_Format(bool async) - => AssertQueryScalar( + => AssertQuery( async, ss => ss.Set() - .Where(c => c.CustomerID == "ALFKI") - .Select(c => byte.Parse(c.CustomerID))); + .Where(c => c.CustomerID == "ALFKI" && + byte.Parse(c.CustomerID) == 0)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Byte_Parse_Greater_Than_Max_Value_Overflows(bool async) - => AssertQueryScalar( + => AssertQuery( async, ss => ss.Set() - .Where(c => c.CustomerID == "ALFKI") - .Select(c => byte.Parse(c.PostalCode))); + .Where(c => c.CustomerID == "ALFKI" && + byte.Parse(c.PostalCode) == 0)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Byte_Parse_Negative_Overflows(bool async) - => AssertQueryScalar( + => AssertQuery( async, ss => ss.Set() - .Where(c => c.CustomerID == "ALFKI") - .Select(c => byte.Parse(c.Phone.Substring(3, 4)))); + .Where(c => c.CustomerID == "ALFKI" && + byte.Parse(c.Phone.Substring(3, 4)) == 0)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Byte_Parse_Decimal_Bad_Format(bool async) - => AssertQueryScalar( + => AssertQuery( async, ss => ss.Set() - .Where(c => c.CustomerID == "BLONP") - .Select(c => byte.Parse(c.Phone.Substring(0, 4)))); + .Where(c => c.CustomerID == "BLONP" && + byte.Parse(c.Phone.Substring(0, 4)) == 0)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] @@ -1550,11 +1550,11 @@ public virtual async Task Decimal_Parse(bool async) [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Decimal_Parse_Non_Numeric_Bad_Format(bool async) - => AssertQueryScalar( + => AssertQuery( async, ss => ss.Set() - .Where(c => c.CustomerID == "ALFKI") - .Select(c => decimal.Parse(c.CustomerID))); + .Where(c => c.CustomerID == "ALFKI" && + decimal.Parse(c.CustomerID) == 0)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] @@ -1582,11 +1582,11 @@ public virtual async Task Double_Parse(bool async) [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Double_Parse_Non_Numeric_Bad_Format(bool async) - => AssertQueryScalar( + => AssertQuery( async, ss => ss.Set() - .Where(c => c.CustomerID == "ALFKI") - .Select(c => double.Parse(c.CustomerID))); + .Where(c => c.CustomerID == "ALFKI" && + double.Parse(c.CustomerID) == 0)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] @@ -1608,29 +1608,29 @@ public virtual async Task Short_Parse(bool async) [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Short_Parse_Non_Numeric_Bad_Format(bool async) - => AssertQueryScalar( + => AssertQuery( async, ss => ss.Set() - .Where(c => c.CustomerID == "ALFKI") - .Select(c => short.Parse(c.CustomerID))); + .Where(c => c.CustomerID == "ALFKI" && + short.Parse(c.CustomerID) == 0)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Short_Parse_Greater_Than_Max_Value_Overflows(bool async) - => AssertQueryScalar( + => AssertQuery( async, ss => ss.Set() - .Where(c => c.CustomerID == "BLAUS") - .Select(c => short.Parse(c.PostalCode))); + .Where(c => c.CustomerID == "BLAUS" && + short.Parse(c.PostalCode) == 0)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Short_Parse_Decimal_Bad_Format(bool async) - => AssertQueryScalar( + => AssertQuery( async, ss => ss.Set() - .Where(c => c.CustomerID == "BLONP") - .Select(c => short.Parse(c.Phone.Substring(0, 4)))); + .Where(c => c.CustomerID == "BLONP" && + short.Parse(c.Phone.Substring(0, 4)) == 0)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] @@ -1652,20 +1652,20 @@ public virtual async Task Int_Parse(bool async) [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Int_Parse_Non_Numeric_Bad_Format(bool async) - => AssertQueryScalar( + => AssertQuery( async, ss => ss.Set() - .Where(c => c.CustomerID == "ALFKI") - .Select(c => int.Parse(c.CustomerID))); + .Where(c => c.CustomerID == "ALFKI" && + int.Parse(c.CustomerID) == 0)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Int_Parse_Decimal_Bad_Format(bool async) - => AssertQueryScalar( + => AssertQuery( async, ss => ss.Set() - .Where(c => c.CustomerID == "BLONP") - .Select(c => int.Parse(c.Phone.Substring(0, 4)))); + .Where(c => c.CustomerID == "BLONP" && + int.Parse(c.Phone.Substring(0, 4)) == 0)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] @@ -1687,20 +1687,20 @@ public virtual async Task Long_Parse(bool async) [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Long_Parse_Non_Numeric_Bad_Format(bool async) - => AssertQueryScalar( + => AssertQuery( async, ss => ss.Set() - .Where(c => c.CustomerID == "ALFKI") - .Select(c => long.Parse(c.CustomerID))); + .Where(c => c.CustomerID == "ALFKI" && + long.Parse(c.CustomerID) == 0)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Long_Parse_Decimal_Bad_Format(bool async) - => AssertQueryScalar( + => AssertQuery( async, ss => ss.Set() - .Where(c => c.CustomerID == "BLONP") - .Select(c => long.Parse(c.Phone.Substring(0, 4)))); + .Where(c => c.CustomerID == "BLONP" && + long.Parse(c.Phone.Substring(0, 4)) == 0)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] From 2706a0582553642b180c84963d53762a0a7abbec Mon Sep 17 00:00:00 2001 From: MaRK0960 Date: Thu, 4 May 2023 21:05:44 +0300 Subject: [PATCH 11/11] Use type inference instead of fixed type --- .../Internal/SqlServerParseTranslator.cs | 27 +++++++++---------- .../NorthwindFunctionsQuerySqlServerTest.cs | 26 +++++++++--------- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs index ca0c042da7a..7f593c88f5c 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs @@ -13,20 +13,20 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal; /// public class SqlServerParseTranslator : IMethodCallTranslator { - private static readonly Dictionary ClrTypeToStoreTypeMap = new() + private static readonly Type[] SupportedClrTypes = new Type[] { - [typeof(bool)] = "bit", - [typeof(byte)] = "tinyint", - [typeof(decimal)] = "decimal(18, 2)", - [typeof(double)] = "float", - [typeof(float)] = "float", - [typeof(short)] = "smallint", - [typeof(int)] = "int", - [typeof(long)] = "bigint" + typeof(bool), // bit + typeof(byte), // tinyint + typeof(decimal), // decimal(18, 2) + typeof(double), // float + typeof(float), // float + typeof(short), // smallint + typeof(int), // int + typeof(long) // bigint }; private static readonly IEnumerable SupportedMethods - = ClrTypeToStoreTypeMap.Keys + = SupportedClrTypes .SelectMany( t => t.GetTypeInfo().GetDeclaredMethods(nameof(int.Parse)) .Where( @@ -58,11 +58,8 @@ public SqlServerParseTranslator(ISqlExpressionFactory sqlExpressionFactory) IReadOnlyList arguments, IDiagnosticsLogger logger) => SupportedMethods.Contains(method) - ? _sqlExpressionFactory.Function( - "CONVERT", - new[] { _sqlExpressionFactory.Fragment(ClrTypeToStoreTypeMap[method.DeclaringType!]), arguments[0] }, - nullable: true, - argumentsPropagateNullability: new[] { false, true }, + ? _sqlExpressionFactory.Convert( + arguments[0], method.ReturnType) : null; } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs index 8255d1587fb..8186699adae 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs @@ -1626,7 +1626,7 @@ public override async Task Byte_Parse(bool async) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(tinyint, SUBSTRING([c].[Phone], 0 + 1, 3)) = CAST(30 AS tinyint)"); +WHERE [c].[CustomerID] = N'ALFKI' AND CAST(SUBSTRING([c].[Phone], 0 + 1, 3) AS tinyint) = CAST(30 AS tinyint)"); } public override async Task Byte_Parse_Non_Numeric_Bad_Format(bool async) @@ -1668,15 +1668,15 @@ public override async Task Decimal_Parse(bool async) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(decimal(18, 2), [c].[PostalCode]) = 12209.0", +WHERE [c].[CustomerID] = N'ALFKI' AND CAST([c].[PostalCode] AS decimal(18,2)) = 12209.0", // @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] = N'BLONP' AND CONVERT(decimal(18, 2), SUBSTRING([c].[Phone], 0 + 1, 4)) = 88.6", +WHERE [c].[CustomerID] = N'BLONP' AND CAST(SUBSTRING([c].[Phone], 0 + 1, 4) AS decimal(18,2)) = 88.6", // @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(decimal(18, 2), SUBSTRING([c].[Phone], 3 + 1, 4)) = -7.0"); +WHERE [c].[CustomerID] = N'ALFKI' AND CAST(SUBSTRING([c].[Phone], 3 + 1, 4) AS decimal(18,2)) = -7.0"); } public override async Task Decimal_Parse_Non_Numeric_Bad_Format(bool async) @@ -1694,15 +1694,15 @@ public override async Task Double_Parse(bool async) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(float, [c].[PostalCode]) = 12209.0E0", +WHERE [c].[CustomerID] = N'ALFKI' AND CAST([c].[PostalCode] AS float) = 12209.0E0", // @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] = N'BLONP' AND CONVERT(float, SUBSTRING([c].[Phone], 0 + 1, 4)) = 88.599999999999994E0", +WHERE [c].[CustomerID] = N'BLONP' AND CAST(SUBSTRING([c].[Phone], 0 + 1, 4) AS float) = 88.599999999999994E0", // @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(float, SUBSTRING([c].[Phone], 3 + 1, 4)) = -7.0E0"); +WHERE [c].[CustomerID] = N'ALFKI' AND CAST(SUBSTRING([c].[Phone], 3 + 1, 4) AS float) = -7.0E0"); } public override async Task Double_Parse_Non_Numeric_Bad_Format(bool async) @@ -1720,11 +1720,11 @@ public override async Task Short_Parse(bool async) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(smallint, [c].[PostalCode]) = CAST(12209 AS smallint)", +WHERE [c].[CustomerID] = N'ALFKI' AND CAST([c].[PostalCode] AS smallint) = CAST(12209 AS smallint)", // @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(smallint, SUBSTRING([c].[Phone], 3 + 1, 4)) = CAST(-7 AS smallint)"); +WHERE [c].[CustomerID] = N'ALFKI' AND CAST(SUBSTRING([c].[Phone], 3 + 1, 4) AS smallint) = CAST(-7 AS smallint)"); } public override async Task Short_Parse_Non_Numeric_Bad_Format(bool async) @@ -1758,11 +1758,11 @@ public override async Task Int_Parse(bool async) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(int, [c].[PostalCode]) = 12209", +WHERE [c].[CustomerID] = N'ALFKI' AND CAST([c].[PostalCode] AS int) = 12209", // @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(int, SUBSTRING([c].[Phone], 3 + 1, 4)) = -7"); +WHERE [c].[CustomerID] = N'ALFKI' AND CAST(SUBSTRING([c].[Phone], 3 + 1, 4) AS int) = -7"); } public override async Task Int_Parse_Non_Numeric_Bad_Format(bool async) @@ -1788,11 +1788,11 @@ public override async Task Long_Parse(bool async) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(bigint, [c].[PostalCode]) = CAST(12209 AS bigint)", +WHERE [c].[CustomerID] = N'ALFKI' AND CAST([c].[PostalCode] AS bigint) = CAST(12209 AS bigint)", // @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] = N'ALFKI' AND CONVERT(bigint, SUBSTRING([c].[Phone], 3 + 1, 4)) = CAST(-7 AS bigint)"); +WHERE [c].[CustomerID] = N'ALFKI' AND CAST(SUBSTRING([c].[Phone], 3 + 1, 4) AS bigint) = CAST(-7 AS bigint)"); } public override async Task Long_Parse_Non_Numeric_Bad_Format(bool async)