diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerStringMethodTranslator.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerStringMethodTranslator.cs index 01d3c238fe0..e1549339a51 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerStringMethodTranslator.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerStringMethodTranslator.cs @@ -443,7 +443,10 @@ private SqlExpression TranslateIndexOf( if (startIndex is not null) { - charIndexArguments.Add(_sqlExpressionFactory.Add(startIndex, _sqlExpressionFactory.Constant(1))); + charIndexArguments.Add( + startIndex is SqlConstantExpression { Value : int constantStartIndex } + ? _sqlExpressionFactory.Constant(constantStartIndex + 1, typeof(int)) + : _sqlExpressionFactory.Add(startIndex, _sqlExpressionFactory.Constant(1))); } var argumentsPropagateNullability = Enumerable.Repeat(true, charIndexArguments.Count); @@ -474,6 +477,15 @@ private SqlExpression TranslateIndexOf( charIndexExpression = _sqlExpressionFactory.Subtract(charIndexExpression, _sqlExpressionFactory.Constant(1)); + // If the pattern is an empty string, we need to special case to always return 0 (since CHARINDEX return 0, which we'd subtract to + // -1). Handle separately for constant and non-constant patterns. + if (searchExpression is SqlConstantExpression { Value : string constantSearchPattern }) + { + return constantSearchPattern == string.Empty + ? _sqlExpressionFactory.Constant(0, typeof(int)) + : charIndexExpression; + } + return _sqlExpressionFactory.Case( new[] { diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs index 8fdf80c9cc7..e8fdcdbfa5f 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs @@ -807,19 +807,53 @@ public override async Task Indexof_with_emptystring(bool async) await base.Indexof_with_emptystring(async); AssertSql( - @"SELECT INDEX_OF(c[""ContactName""], """") AS c + @"SELECT c FROM root c -WHERE ((c[""Discriminator""] = ""Customer"") AND (c[""CustomerID""] = ""ALFKI""))"); +WHERE ((c[""Discriminator""] = ""Customer"") AND (INDEX_OF(c[""ContactName""], """") = 0))"); } - public override async Task Indexof_with_starting_position(bool async) + public override async Task Indexof_with_one_constant_arg(bool async) { - await base.Indexof_with_starting_position(async); + await base.Indexof_with_one_constant_arg(async); AssertSql( - @"SELECT INDEX_OF(c[""ContactName""], ""a"", 3) AS c + @"SELECT c FROM root c -WHERE ((c[""Discriminator""] = ""Customer"") AND (c[""CustomerID""] = ""ALFKI""))"); +WHERE ((c[""Discriminator""] = ""Customer"") AND (INDEX_OF(c[""ContactName""], ""a"") = 1))"); + } + + public override async Task Indexof_with_one_parameter_arg(bool async) + { + await base.Indexof_with_one_parameter_arg(async); + + AssertSql( + @"@__pattern_0='a' + +SELECT c +FROM root c +WHERE ((c[""Discriminator""] = ""Customer"") AND (INDEX_OF(c[""ContactName""], @__pattern_0) = 1))"); + } + + public override async Task Indexof_with_constant_starting_position(bool async) + { + await base.Indexof_with_constant_starting_position(async); + + AssertSql( + @"SELECT c +FROM root c +WHERE ((c[""Discriminator""] = ""Customer"") AND (INDEX_OF(c[""ContactName""], ""a"", 2) = 4))"); + } + + public override async Task Indexof_with_parameter_starting_position(bool async) + { + await base.Indexof_with_parameter_starting_position(async); + + AssertSql( + @"@__start_0='2' + +SELECT c +FROM root c +WHERE ((c[""Discriminator""] = ""Customer"") AND (INDEX_OF(c[""ContactName""], ""a"", @__start_0) = 4))"); } public override async Task Replace_with_emptystring(bool async) @@ -827,9 +861,9 @@ public override async Task Replace_with_emptystring(bool async) await base.Replace_with_emptystring(async); AssertSql( - @"SELECT REPLACE(c[""ContactName""], ""ari"", """") AS c + @"SELECT c FROM root c -WHERE ((c[""Discriminator""] = ""Customer"") AND (c[""CustomerID""] = ""ALFKI""))"); +WHERE ((c[""Discriminator""] = ""Customer"") AND (REPLACE(c[""ContactName""], ""ia"", """") = ""Mar Anders""))"); } public override async Task Replace_using_property_arguments(bool async) @@ -837,9 +871,9 @@ public override async Task Replace_using_property_arguments(bool async) await base.Replace_using_property_arguments(async); AssertSql( - @"SELECT REPLACE(c[""ContactName""], c[""ContactName""], c[""CustomerID""]) AS c + @"SELECT c FROM root c -WHERE ((c[""Discriminator""] = ""Customer"") AND (c[""CustomerID""] = ""ALFKI""))"); +WHERE ((c[""Discriminator""] = ""Customer"") AND (REPLACE(c[""ContactName""], c[""ContactName""], c[""CustomerID""]) = c[""CustomerID""]))"); } public override async Task Substring_with_one_arg_with_zero_startindex(bool async) @@ -1292,16 +1326,6 @@ FROM root c WHERE ((c[""Discriminator""] = ""OrderDetail"") AND (c[""Quantity""] < 5))"); } - public override async Task Indexof_with_one_arg(bool async) - { - await base.Indexof_with_one_arg(async); - - AssertSql( - @"SELECT INDEX_OF(c[""ContactName""], ""a"") AS c -FROM root c -WHERE ((c[""Discriminator""] = ""Customer"") AND (c[""CustomerID""] = ""ALFKI""))"); - } - private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs index 27e9c25b958..7af49885b8c 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs @@ -1406,38 +1406,66 @@ await AssertQuery( [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Indexof_with_emptystring(bool async) - => AssertQueryScalar( + => AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "ALFKI").Select(c => c.ContactName.IndexOf(string.Empty))); + ss => ss.Set().Where(c => c.ContactName.IndexOf(string.Empty) == 0), + entryCount: 91); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Indexof_with_one_arg(bool async) - => AssertQueryScalar( + public virtual Task Indexof_with_one_constant_arg(bool async) + => AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "ALFKI").Select(c => c.ContactName.IndexOf("a"))); + ss => ss.Set().Where(c => c.ContactName.IndexOf("a") == 1), + entryCount: 32); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Indexof_with_starting_position(bool async) - => AssertQueryScalar( + public virtual Task Indexof_with_one_parameter_arg(bool async) + { + var pattern = "a"; + + return AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "ALFKI").Select(c => c.ContactName.IndexOf("a", 3))); + ss => ss.Set().Where(c => c.ContactName.IndexOf(pattern) == 1), + entryCount: 32); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Indexof_with_constant_starting_position(bool async) + => AssertQuery( + async, + ss => ss.Set().Where(c => c.ContactName.IndexOf("a", 2) == 4), + entryCount: 15); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Indexof_with_parameter_starting_position(bool async) + { + var start = 2; + + return AssertQuery( + async, + ss => ss.Set().Where(c => c.ContactName.IndexOf("a", start) == 4), + entryCount: 15); + } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Replace_with_emptystring(bool async) => AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "ALFKI").Select(c => c.ContactName.Replace("ari", string.Empty))); + ss => ss.Set().Where(c => c.ContactName.Replace("ia", string.Empty) == "Mar Anders"), + entryCount: 1); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Replace_using_property_arguments(bool async) => AssertQuery( async, - ss => ss.Set().Where(c => c.CustomerID == "ALFKI") - .Select(c => c.ContactName.Replace(c.ContactName, c.CustomerID))); + ss => ss.Set().Where(c => c.ContactName.Replace(c.ContactName, c.CustomerID) == c.CustomerID), + entryCount: 91); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] diff --git a/test/EFCore.SqlServer.FunctionalTests/BuiltInDataTypesSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/BuiltInDataTypesSqlServerTest.cs index 29bb00abd3c..e6e7827e39c 100644 --- a/test/EFCore.SqlServer.FunctionalTests/BuiltInDataTypesSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/BuiltInDataTypesSqlServerTest.cs @@ -83,10 +83,7 @@ public void String_indexOf_over_varchar_max() Assert.Equal(-1, Assert.Single(results)); AssertSql( - @"SELECT CASE - WHEN 'a' = '' THEN 0 - ELSE CAST(CHARINDEX('a', [m].[StringAsVarcharMax]) AS int) - 1 -END + @"SELECT CAST(CHARINDEX('a', [m].[StringAsVarcharMax]) AS int) - 1 FROM [MappedNullableDataTypes] AS [m] WHERE [m].[Int] = 81"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs index 0e5029fdd65..cba7f3a57ca 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs @@ -1571,35 +1571,55 @@ public override async Task Indexof_with_emptystring(bool async) await base.Indexof_with_emptystring(async); AssertSql( - @"SELECT 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]"); + } + + public override async Task Indexof_with_one_constant_arg(bool async) + { + await base.Indexof_with_one_constant_arg(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'"); +WHERE (CAST(CHARINDEX(N'a', [c].[ContactName]) AS int) - 1) = 1"); } - public override async Task Indexof_with_one_arg(bool async) + public override async Task Indexof_with_one_parameter_arg(bool async) { - await base.Indexof_with_one_arg(async); + await base.Indexof_with_one_parameter_arg(async); AssertSql( - @"SELECT CASE - WHEN N'a' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'a', [c].[ContactName]) AS int) - 1 -END + @"@__pattern_0='a' (Size = 4000) + +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'"); +WHERE CASE + WHEN @__pattern_0 = N'' THEN 0 + ELSE CAST(CHARINDEX(@__pattern_0, [c].[ContactName]) AS int) - 1 +END = 1"); + } + + public override async Task Indexof_with_constant_starting_position(bool async) + { + await base.Indexof_with_constant_starting_position(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 (CAST(CHARINDEX(N'a', [c].[ContactName], 3) AS int) - 1) = 4"); } - public override async Task Indexof_with_starting_position(bool async) + public override async Task Indexof_with_parameter_starting_position(bool async) { - await base.Indexof_with_starting_position(async); + await base.Indexof_with_parameter_starting_position(async); AssertSql( - @"SELECT CASE - WHEN N'a' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'a', [c].[ContactName], 3 + 1) AS int) - 1 -END + @"@__start_0='2' + +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'"); +WHERE (CAST(CHARINDEX(N'a', [c].[ContactName], @__start_0 + 1) AS int) - 1) = 4"); } public override async Task Replace_with_emptystring(bool async) @@ -1607,9 +1627,9 @@ public override async Task Replace_with_emptystring(bool async) await base.Replace_with_emptystring(async); AssertSql( - @"SELECT REPLACE([c].[ContactName], N'ari', N'') + @"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'"); +WHERE REPLACE([c].[ContactName], N'ia', N'') = N'Mar Anders'"); } public override async Task Replace_using_property_arguments(bool async) @@ -1617,9 +1637,9 @@ public override async Task Replace_using_property_arguments(bool async) await base.Replace_using_property_arguments(async); AssertSql( - @"SELECT REPLACE([c].[ContactName], [c].[ContactName], [c].[CustomerID]) + @"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'"); +WHERE REPLACE([c].[ContactName], [c].[ContactName], [c].[CustomerID]) = [c].[CustomerID]"); } public override async Task Substring_with_one_arg_with_zero_startindex(bool async) @@ -1701,10 +1721,7 @@ public override async Task Substring_with_two_args_with_Index_of(bool async) await base.Substring_with_two_args_with_Index_of(async); AssertSql( - @"SELECT SUBSTRING([c].[ContactName], CASE - WHEN N'a' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'a', [c].[ContactName]) AS int) - 1 -END + 1, 3) + @"SELECT SUBSTRING([c].[ContactName], (CAST(CHARINDEX(N'a', [c].[ContactName]) AS int) - 1) + 1, 3) FROM [Customers] AS [c] WHERE [c].[CustomerID] = N'ALFKI'"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs index c320a7d8dda..84b98380309 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs @@ -674,13 +674,7 @@ public override async Task Where_string_indexof(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 CASE - WHEN N'Sea' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'Sea', [c].[City]) AS int) - 1 -END <> -1 OR CASE - WHEN N'Sea' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'Sea', [c].[City]) AS int) - 1 -END IS NULL"); +WHERE (CAST(CHARINDEX(N'Sea', [c].[City]) AS int) - 1) <> -1 OR [c].[City] IS NULL"); } public override async Task Where_string_replace(bool async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs index 022e8d78ec8..717e349abd8 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs @@ -1248,36 +1248,15 @@ public override async Task Null_semantics_applied_when_comparing_function_with_n AssertSql( @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE CASE - WHEN N'oo' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1 -END = [e].[NullableIntA] OR (CASE - WHEN N'oo' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1 -END IS NULL AND [e].[NullableIntA] IS NULL)", +WHERE (CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1) = [e].[NullableIntA] OR ([e].[NullableStringA] IS NULL AND [e].[NullableIntA] IS NULL)", // @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE CASE - WHEN N'ar' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'ar', [e].[NullableStringA]) AS int) - 1 -END = [e].[NullableIntA] OR (CASE - WHEN N'ar' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'ar', [e].[NullableStringA]) AS int) - 1 -END IS NULL AND [e].[NullableIntA] IS NULL)", +WHERE (CAST(CHARINDEX(N'ar', [e].[NullableStringA]) AS int) - 1) = [e].[NullableIntA] OR ([e].[NullableStringA] IS NULL AND [e].[NullableIntA] IS NULL)", // @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE (CASE - WHEN N'oo' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1 -END <> [e].[NullableIntB] OR CASE - WHEN N'oo' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1 -END IS NULL OR [e].[NullableIntB] IS NULL) AND (CASE - WHEN N'oo' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1 -END IS NOT NULL OR [e].[NullableIntB] IS NOT NULL)"); +WHERE ((CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1) <> [e].[NullableIntB] OR [e].[NullableStringA] IS NULL OR [e].[NullableIntB] IS NULL) AND ([e].[NullableStringA] IS NOT NULL OR [e].[NullableIntB] IS NOT NULL)"); } public override async Task Where_IndexOf_empty(bool async) @@ -1293,10 +1272,7 @@ public override async Task Select_IndexOf(bool async) await base.Select_IndexOf(async); AssertSql( - @"SELECT CASE - WHEN N'oo' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1 -END + @"SELECT CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1 FROM [Entities1] AS [e] ORDER BY [e].[Id]"); } @@ -1308,63 +1284,15 @@ public override async Task Null_semantics_applied_when_comparing_two_functions_w AssertSql( @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE CASE - WHEN N'oo' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1 -END = CASE - WHEN N'ar' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'ar', [e].[NullableStringB]) AS int) - 1 -END OR (CASE - WHEN N'oo' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1 -END IS NULL AND CASE - WHEN N'ar' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'ar', [e].[NullableStringB]) AS int) - 1 -END IS NULL)", +WHERE (CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1) = (CAST(CHARINDEX(N'ar', [e].[NullableStringB]) AS int) - 1) OR ([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL)", // @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE (CASE - WHEN N'oo' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1 -END <> CASE - WHEN N'ar' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'ar', [e].[NullableStringB]) AS int) - 1 -END OR CASE - WHEN N'oo' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1 -END IS NULL OR CASE - WHEN N'ar' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'ar', [e].[NullableStringB]) AS int) - 1 -END IS NULL) AND (CASE - WHEN N'oo' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1 -END IS NOT NULL OR CASE - WHEN N'ar' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'ar', [e].[NullableStringB]) AS int) - 1 -END IS NOT NULL)", - // - @"SELECT [e].[Id] -FROM [Entities1] AS [e] -WHERE (CASE - WHEN N'oo' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1 -END <> CASE - WHEN N'ar' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'ar', [e].[NullableStringA]) AS int) - 1 -END OR CASE - WHEN N'oo' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1 -END IS NULL OR CASE - WHEN N'ar' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'ar', [e].[NullableStringA]) AS int) - 1 -END IS NULL) AND (CASE - WHEN N'oo' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1 -END IS NOT NULL OR CASE - WHEN N'ar' = N'' THEN 0 - ELSE CAST(CHARINDEX(N'ar', [e].[NullableStringA]) AS int) - 1 -END IS NOT NULL)"); +WHERE ((CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1) <> (CAST(CHARINDEX(N'ar', [e].[NullableStringB]) AS int) - 1) OR [e].[NullableStringA] IS NULL OR [e].[NullableStringB] IS NULL) AND ([e].[NullableStringA] IS NOT NULL OR [e].[NullableStringB] IS NOT NULL)", + // + @"SELECT [e].[Id] +FROM [Entities1] AS [e] +WHERE ((CAST(CHARINDEX(N'oo', [e].[NullableStringA]) AS int) - 1) <> (CAST(CHARINDEX(N'ar', [e].[NullableStringA]) AS int) - 1) OR [e].[NullableStringA] IS NULL) AND [e].[NullableStringA] IS NOT NULL"); } public override async Task Null_semantics_applied_when_comparing_two_functions_with_multiple_nullable_arguments(bool async) diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs index 91f725a9846..8fd38b98d5c 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs @@ -327,19 +327,57 @@ public override async Task Indexof_with_emptystring(bool async) await base.Indexof_with_emptystring(async); AssertSql( - @"SELECT instr(""c"".""ContactName"", '') - 1 + @"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"" = 'ALFKI'"); +WHERE (instr(""c"".""ContactName"", '') - 1) = 0"); + } + + public override async Task Indexof_with_one_constant_arg(bool async) + { + await base.Indexof_with_one_constant_arg(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 (instr(""c"".""ContactName"", 'a') - 1) = 1"); } + public override async Task Indexof_with_one_parameter_arg(bool async) + { + await base.Indexof_with_one_parameter_arg(async); + + AssertSql( + @"@__pattern_0='a' (Size = 1) + +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 (instr(""c"".""ContactName"", @__pattern_0) - 1) = 1"); + } + + public override Task Indexof_with_constant_starting_position(bool async) + => AssertTranslationFailed(() => base.Indexof_with_constant_starting_position(async)); + + public override Task Indexof_with_parameter_starting_position(bool async) + => AssertTranslationFailed(() => base.Indexof_with_parameter_starting_position(async)); + public override async Task Replace_with_emptystring(bool async) { await base.Replace_with_emptystring(async); AssertSql( - @"SELECT replace(""c"".""ContactName"", 'ari', '') + @"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"" = 'ALFKI'"); +WHERE replace(""c"".""ContactName"", 'ia', '') = 'Mar Anders'"); + } + + public override async Task Replace_using_property_arguments(bool async) + { + await base.Replace_using_property_arguments(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 replace(""c"".""ContactName"", ""c"".""ContactName"", ""c"".""CustomerID"") = ""c"".""CustomerID"""); } public override async Task Substring_with_one_arg_with_zero_startindex(bool async)