diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerMethodCallTranslatorProvider.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerMethodCallTranslatorProvider.cs index 6abb498a288..0964b0368f1 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerMethodCallTranslatorProvider.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerMethodCallTranslatorProvider.cs @@ -38,6 +38,7 @@ public SqlServerMethodCallTranslatorProvider(RelationalMethodCallTranslatorProvi new SqlServerMathTranslator(sqlExpressionFactory), new SqlServerNewGuidTranslator(sqlExpressionFactory), new SqlServerObjectToStringTranslator(sqlExpressionFactory), + new SqlServerParseTranslator(sqlExpressionFactory), new SqlServerStringMethodTranslator(sqlExpressionFactory), new SqlServerTimeOnlyMethodTranslator(sqlExpressionFactory) }); diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs new file mode 100644 index 00000000000..7f593c88f5c --- /dev/null +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerParseTranslator.cs @@ -0,0 +1,65 @@ +// 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 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 + }; + + private static readonly IEnumerable SupportedMethods + = SupportedClrTypes + .SelectMany( + t => t.GetTypeInfo().GetDeclaredMethods(nameof(int.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.Convert( + arguments[0], + method.ReturnType) + : null; +} diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs index 17c7cc3b7c6..26832bce839 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs @@ -901,6 +901,158 @@ 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 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. + await AssertTranslationFailed(() => base.Decimal_Parse(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. + await AssertTranslationFailed(() => base.Double_Parse(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. + await AssertTranslationFailed(() => base.Short_Parse(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. + await AssertTranslationFailed(() => base.Int_Parse(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. + await AssertTranslationFailed(() => base.Long_Parse(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 879031ceef8..cce61fd3d0c 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs @@ -1556,6 +1556,229 @@ public virtual async Task Convert_ToString(bool async) } } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + 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))] + public virtual Task Byte_Parse_Non_Numeric_Bad_Format(bool async) + => AssertQuery( + async, + ss => ss.Set() + .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) + => AssertQuery( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "ALFKI" && + byte.Parse(c.PostalCode) == 0)); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Byte_Parse_Negative_Overflows(bool async) + => AssertQuery( + async, + ss => ss.Set() + .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) + => AssertQuery( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "BLONP" && + byte.Parse(c.Phone.Substring(0, 4)) == 0)); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Decimal_Parse(bool async) + { + await AssertQuery( + async, + 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" && + decimal.Parse(c.Phone.Substring(0, 4)) == 88.6m), + entryCount: 1); + + await AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && + 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) + => AssertQuery( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "ALFKI" && + decimal.Parse(c.CustomerID) == 0)); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Double_Parse(bool async) + { + await AssertQuery( + async, + 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" && + double.Parse(c.Phone.Substring(0, 4)) == 88.6d), + entryCount: 1); + + await AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID == "ALFKI" && + 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) + => AssertQuery( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "ALFKI" && + double.Parse(c.CustomerID) == 0)); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Short_Parse(bool async) + { + await AssertQuery( + async, + 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" && + 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) + => AssertQuery( + async, + ss => ss.Set() + .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) + => AssertQuery( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "BLAUS" && + short.Parse(c.PostalCode) == 0)); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Short_Parse_Decimal_Bad_Format(bool async) + => AssertQuery( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "BLONP" && + short.Parse(c.Phone.Substring(0, 4)) == 0)); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Int_Parse(bool async) + { + await AssertQuery( + async, + 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" && + 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) + => AssertQuery( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "ALFKI" && + int.Parse(c.CustomerID) == 0)); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Int_Parse_Decimal_Bad_Format(bool async) + => AssertQuery( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "BLONP" && + int.Parse(c.Phone.Substring(0, 4)) == 0)); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Long_Parse(bool async) + { + await AssertQuery( + async, + 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" && + 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) + => AssertQuery( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "ALFKI" && + long.Parse(c.CustomerID) == 0)); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Long_Parse_Decimal_Bad_Format(bool async) + => AssertQuery( + async, + ss => ss.Set() + .Where(c => c.CustomerID == "BLONP" && + long.Parse(c.Phone.Substring(0, 4)) == 0)); + [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 d8aa23243aa..d3a714ae69e 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; @@ -2129,6 +2130,198 @@ public override async Task Convert_ToString(bool async) """); } + public override async Task Byte_Parse(bool async) + { + await base.Byte_Parse(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 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) + { + 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) + { + await base.Decimal_Parse(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 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 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 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) + { + 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) + { + await base.Double_Parse(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 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 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 CAST(SUBSTRING([c].[Phone], 3 + 1, 4) AS float) = -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) + { + await base.Short_Parse(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 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 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) + { + 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) + { + await base.Int_Parse(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 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 CAST(SUBSTRING([c].[Phone], 3 + 1, 4) AS int) = -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) + { + await base.Long_Parse(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 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 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) + { + 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) { 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 75b71e662be..39710184afb 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs @@ -42,6 +42,63 @@ 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 Byte_Parse_Non_Numeric_Bad_Format(bool async) + => AssertTranslationFailed(() => base.Byte_Parse_Non_Numeric_Bad_Format(async)); + + public override Task Byte_Parse_Greater_Than_Max_Value_Overflows(bool async) + => AssertTranslationFailed(() => base.Byte_Parse_Greater_Than_Max_Value_Overflows(async)); + + public override Task Byte_Parse_Negative_Overflows(bool async) + => AssertTranslationFailed(() => base.Byte_Parse_Negative_Overflows(async)); + + public override Task Byte_Parse_Decimal_Bad_Format(bool 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) + => 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) + => 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) + => AssertTranslationFailed(() => base.Short_Parse_Non_Numeric_Bad_Format(async)); + + public override Task Short_Parse_Greater_Than_Max_Value_Overflows(bool async) + => AssertTranslationFailed(() => base.Short_Parse_Greater_Than_Max_Value_Overflows(async)); + + public override Task Short_Parse_Decimal_Bad_Format(bool 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) + => AssertTranslationFailed(() => base.Int_Parse_Non_Numeric_Bad_Format(async)); + + public override Task Int_Parse_Decimal_Bad_Format(bool 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) + => AssertTranslationFailed(() => base.Long_Parse_Non_Numeric_Bad_Format(async)); + + public override Task Long_Parse_Decimal_Bad_Format(bool 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));