From d7f8d7b8d3874c8b00b25c6b5f84e540e40ac694 Mon Sep 17 00:00:00 2001 From: Nikhil Bansal Date: Sat, 17 Aug 2024 22:37:24 +0530 Subject: [PATCH 1/4] Added Support for translating byte[].IndexOf methods for SqlServer --- .../SqlServerByteArrayMethodTranslator.cs | 122 ++++++++++++++--- .../Query/GearsOfWarQueryTestBase.cs | 98 ++++++++++++++ .../TestModels/GearsOfWarModel/Squad.cs | 2 +- .../Query/GearsOfWarQuerySqlServerTest.cs | 124 +++++++++++++++++- 4 files changed, 318 insertions(+), 28 deletions(-) diff --git a/src/EFCore.SqlServer/Query/Internal/Translators/SqlServerByteArrayMethodTranslator.cs b/src/EFCore.SqlServer/Query/Internal/Translators/SqlServerByteArrayMethodTranslator.cs index bf414d83d7d..c317e54eb08 100644 --- a/src/EFCore.SqlServer/Query/Internal/Translators/SqlServerByteArrayMethodTranslator.cs +++ b/src/EFCore.SqlServer/Query/Internal/Translators/SqlServerByteArrayMethodTranslator.cs @@ -16,6 +16,21 @@ public class SqlServerByteArrayMethodTranslator : IMethodCallTranslator { private readonly ISqlExpressionFactory _sqlExpressionFactory; + // NOTE: Might want to move these to a shared file, similar to EnumerableMethods + private static readonly MethodInfo IndexOfMethodInfo + = typeof(Array) + .GetGenericMethod(nameof(Array.IndexOf), 1, BindingFlags.Public | BindingFlags.Static, (_, t) => + { + return [t[0].MakeArrayType(), t[0]]; + })!; + + private static readonly MethodInfo IndexOfWithStartingPositionMethodInfo + = typeof(Array) + .GetGenericMethod(nameof(Array.IndexOf), 1, BindingFlags.Public | BindingFlags.Static, (_, t) => + { + return [t[0].MakeArrayType(), t[0], typeof(int)]; + })!; + /// /// 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 @@ -40,31 +55,33 @@ public SqlServerByteArrayMethodTranslator(ISqlExpressionFactory sqlExpressionFac IDiagnosticsLogger logger) { if (method.IsGenericMethod - && method.GetGenericMethodDefinition().Equals(EnumerableMethods.Contains) + && arguments.Count >= 1 && arguments[0].Type == typeof(byte[])) { - var source = arguments[0]; - var sourceTypeMapping = source.TypeMapping; + var methodDefinition = method.GetGenericMethodDefinition(); + if (methodDefinition.Equals(EnumerableMethods.Contains)) + { + // NOTE: Should this be refactored to use the TranslateIndexOf method?? Everything is same expect one check + var source = arguments[0]; + var sourceTypeMapping = source.TypeMapping; - var value = arguments[1] is SqlConstantExpression constantValue - ? _sqlExpressionFactory.Constant(new[] { (byte)constantValue.Value! }, sourceTypeMapping) - : _sqlExpressionFactory.Convert(arguments[1], typeof(byte[]), sourceTypeMapping); + var value = arguments[1] is SqlConstantExpression constantValue + ? _sqlExpressionFactory.Constant(new[] { (byte)constantValue.Value! }, sourceTypeMapping) + : _sqlExpressionFactory.Convert(arguments[1], typeof(byte[]), sourceTypeMapping); - return _sqlExpressionFactory.GreaterThan( - _sqlExpressionFactory.Function( - "CHARINDEX", - [value, source], - nullable: true, - argumentsPropagateNullability: [true, true], - typeof(int)), - _sqlExpressionFactory.Constant(0)); - } + return _sqlExpressionFactory.GreaterThan( + _sqlExpressionFactory.Function( + "CHARINDEX", + [value, source], + nullable: true, + argumentsPropagateNullability: [true, true], + typeof(int)), + _sqlExpressionFactory.Constant(0)); + } - if (method.IsGenericMethod - && method.GetGenericMethodDefinition().Equals(EnumerableMethods.FirstWithoutPredicate) - && arguments[0].Type == typeof(byte[])) - { - return _sqlExpressionFactory.Convert( + if (methodDefinition.Equals(EnumerableMethods.FirstWithoutPredicate)) + { + return _sqlExpressionFactory.Convert( _sqlExpressionFactory.Function( "SUBSTRING", [arguments[0], _sqlExpressionFactory.Constant(1), _sqlExpressionFactory.Constant(1)], @@ -72,8 +89,73 @@ public SqlServerByteArrayMethodTranslator(ISqlExpressionFactory sqlExpressionFac argumentsPropagateNullability: [true, true, true], typeof(byte[])), method.ReturnType); + } + + if (methodDefinition.Equals(IndexOfMethodInfo)) + { + return TranslateIndexOf(method, arguments[0], arguments[1], null); + } + + if (methodDefinition.Equals(IndexOfWithStartingPositionMethodInfo)) + { + return TranslateIndexOf(method, arguments[0], arguments[1], arguments[2]); + } } return null; } + + private SqlExpression TranslateIndexOf( + MethodInfo method, + SqlExpression source, + SqlExpression valueToSearch, + SqlExpression? startIndex + ) + { + var sourceTypeMapping = source.TypeMapping; + var sqlArguments = new List + { + valueToSearch is SqlConstantExpression { Value: byte constantValue } + ? _sqlExpressionFactory.Constant(new byte[] { constantValue }, sourceTypeMapping) + : _sqlExpressionFactory.Convert(valueToSearch, typeof(byte[]), sourceTypeMapping), + source + }; + + if (startIndex is not null) + { + sqlArguments.Add( + startIndex is SqlConstantExpression { Value : int index } + ? _sqlExpressionFactory.Constant(index + 1, typeof(int)) + : _sqlExpressionFactory.Add(startIndex, _sqlExpressionFactory.Constant(1)) + ); + } + + var argumentsPropagateNullability = Enumerable.Repeat(true, sqlArguments.Count); + + SqlExpression charIndexExpr; + var storeType = sourceTypeMapping?.StoreType; + if (storeType == "varbinary(max)") + { + charIndexExpr = _sqlExpressionFactory.Function( + "CHARINDEX", + sqlArguments, + nullable: true, + argumentsPropagateNullability: argumentsPropagateNullability, + typeof(long)); + + charIndexExpr = _sqlExpressionFactory.Convert(charIndexExpr, typeof(int)); + } + else + { + charIndexExpr = _sqlExpressionFactory.Function( + "CHARINDEX", + sqlArguments, + nullable: true, + argumentsPropagateNullability: argumentsPropagateNullability, + method.ReturnType); + } + + + return _sqlExpressionFactory.Subtract(charIndexExpr, _sqlExpressionFactory.Constant(1)); + } } diff --git a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs index fb245ad579c..c0304cffe59 100644 --- a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs @@ -6259,6 +6259,104 @@ public virtual Task Byte_array_filter_by_length_parameter(bool async) ss => ss.Set().Where(w => w.Banner != null && w.Banner.Length == someByteArr.Length)); } + #region Byte Array IndexOf + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Where(w => Array.IndexOf(w.Banner, (byte)1) == 1), + ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner, (byte)1) == 1) + ); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(bool async) + { + byte b = 0; + return AssertQuery( + async, + ss => ss.Set().Where(w => Array.IndexOf(w.Banner, b) == 0), + ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner, b) == 0) + ); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Where(w => Array.IndexOf(w.Banner5, (byte)5) == 1), + ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner5, (byte)5) == 1) + ); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(bool async) + { + byte b = 4; + return AssertQuery( + async, + ss => ss.Set().Where(w => Array.IndexOf(w.Banner5, b) == 0), + ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner5, b) == 0) + ); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Where(w => Array.IndexOf(w.Banner, (byte)1, 1) == 1), + ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner, (byte)1, 1) == 1) + ); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(bool async) + { + byte b = 0; + int startPos = 0; + return AssertQuery( + async, + ss => ss.Set().Where(w => Array.IndexOf(w.Banner, b, startPos) == 0), + ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner, b, startPos) == 0) + ); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Where(w => Array.IndexOf(w.Banner5, (byte)5, 1) == 1), + ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner5, (byte)5, 1) == 1) + ); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(bool async) + { + byte b = 4; + int startPos = 0; + return AssertQuery( + async, + ss => ss.Set().Where(w => Array.IndexOf(w.Banner5, b, startPos) == 0), + ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner5, b, startPos) == 0) + ); + } + + #endregion + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task OrderBy_bool_coming_from_optional_navigation(bool async) diff --git a/test/EFCore.Specification.Tests/TestModels/GearsOfWarModel/Squad.cs b/test/EFCore.Specification.Tests/TestModels/GearsOfWarModel/Squad.cs index e00a81bf681..e3321a178b6 100644 --- a/test/EFCore.Specification.Tests/TestModels/GearsOfWarModel/Squad.cs +++ b/test/EFCore.Specification.Tests/TestModels/GearsOfWarModel/Squad.cs @@ -9,7 +9,7 @@ public class Squad { public Squad() { - Members = new List(); + Members = []; } // non-auto generated key diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index ee1bf84c519..f7370739a85 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -7610,6 +7610,20 @@ WHERE CHARINDEX(0x01, [s].[Banner]) > 0 """); } + public override async Task Byte_array_contains_parameter(bool async) + { + await base.Byte_array_contains_parameter(async); + + AssertSql( + """ +@__someByte_0='1' (Size = 1) + +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CHARINDEX(CAST(@__someByte_0 AS varbinary(max)), [s].[Banner]) > 0 +"""); + } + public override async Task Byte_array_filter_by_length_literal(bool async) { await base.Byte_array_filter_by_length_literal(async); @@ -7650,32 +7664,128 @@ WHERE CAST(DATALENGTH([s].[Banner]) AS int) = CAST(DATALENGTH(@__byteArrayParam) """); } - public override async Task Byte_array_contains_parameter(bool async) + public override async Task Byte_array_filter_by_length_literal_does_not_cast_on_varbinary_n(bool async) { - await base.Byte_array_contains_parameter(async); + await base.Byte_array_filter_by_length_literal_does_not_cast_on_varbinary_n(async); AssertSql( """ -@__someByte_0='1' (Size = 1) +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE DATALENGTH([s].[Banner5]) = 5 +"""); + } + + #region Byte Array IndexOf Translation + + public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(bool async) + { + await base.Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(async); + AssertSql( + """ SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] FROM [Squads] AS [s] -WHERE CHARINDEX(CAST(@__someByte_0 AS varbinary(max)), [s].[Banner]) > 0 +WHERE CAST(CHARINDEX(0x01, [s].[Banner]) AS int) - 1 = 1 """); } - public override async Task Byte_array_filter_by_length_literal_does_not_cast_on_varbinary_n(bool async) + public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(bool async) { - await base.Byte_array_filter_by_length_literal_does_not_cast_on_varbinary_n(async); + await base.Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(async); AssertSql( """ +@__b_0='0' (Size = 1) + SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] FROM [Squads] AS [s] -WHERE DATALENGTH([s].[Banner5]) = 5 +WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner]) AS int) - 1 = 0 +"""); + } + + public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(bool async) + { + await base.Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(async); + + AssertSql( + """ +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CHARINDEX(0x05, [s].[Banner5]) - 1 = 1 +"""); + } + + public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(bool async) + { + await base.Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(async); + + AssertSql( + """ +@__b_0='4' (Size = 1) + +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CHARINDEX(CAST(@__b_0 AS varbinary(5)), [s].[Banner5]) - 1 = 0 +"""); + } + + public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(bool async) + { + await base.Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(async); + + AssertSql( + """ +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CAST(CHARINDEX(0x01, [s].[Banner], 2) AS int) - 1 = 1 +"""); + } + + public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(bool async) + { + await base.Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(async); + + AssertSql( + """ +@__b_0='0' (Size = 1) +@__startPos_1='0' + +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner], @__startPos_1 + 1) AS int) - 1 = 0 +"""); + } + + public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(bool async) + { + await base.Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(async); + + AssertSql( + """ +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CHARINDEX(0x05, [s].[Banner5], 2) - 1 = 1 """); } + public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(bool async) + { + await base.Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(async); + + AssertSql( + """ +@__b_0='4' (Size = 1) +@__startPos_1='0' + +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CHARINDEX(CAST(@__b_0 AS varbinary(5)), [s].[Banner5], @__startPos_1 + 1) - 1 = 0 +"""); + } + + #endregion + public override async Task Conditional_expression_with_test_being_simplified_to_constant_simple(bool isAsync) { await base.Conditional_expression_with_test_being_simplified_to_constant_simple(isAsync); From d81a857fa236dfc996e0b765e517baf85fc6ff7b Mon Sep 17 00:00:00 2001 From: Nikhil Bansal Date: Sun, 18 Aug 2024 00:03:16 +0530 Subject: [PATCH 2/4] Fixed SqlServer & Sqlite Functional Tests --- .../Query/TPCGearsOfWarQuerySqlServerTest.cs | 110 ++++++++++++++++++ .../Query/TPTGearsOfWarQuerySqlServerTest.cs | 110 ++++++++++++++++++ .../TemporalGearsOfWarQuerySqlServerTest.cs | 110 ++++++++++++++++++ .../Query/GearsOfWarQuerySqliteTest.cs | 46 ++++++++ .../Query/TPCGearsOfWarQuerySqliteTest.cs | 46 ++++++++ .../Query/TPTGearsOfWarQuerySqliteTest.cs | 46 ++++++++ 6 files changed, 468 insertions(+) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs index 5f691f3504a..8f12ed4fa79 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs @@ -10220,6 +10220,116 @@ WHERE DATALENGTH([s].[Banner5]) = 5 """); } + #region Byte Array IndexOf Translation + + public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(bool async) + { + await base.Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(async); + + AssertSql( + """ +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CAST(CHARINDEX(0x01, [s].[Banner]) AS int) - 1 = 1 +"""); + } + + public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(bool async) + { + await base.Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(async); + + AssertSql( + """ +@__b_0='0' (Size = 1) + +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner]) AS int) - 1 = 0 +"""); + } + + public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(bool async) + { + await base.Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(async); + + AssertSql( + """ +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CHARINDEX(0x05, [s].[Banner5]) - 1 = 1 +"""); + } + + public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(bool async) + { + await base.Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(async); + + AssertSql( + """ +@__b_0='4' (Size = 1) + +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CHARINDEX(CAST(@__b_0 AS varbinary(5)), [s].[Banner5]) - 1 = 0 +"""); + } + + public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(bool async) + { + await base.Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(async); + + AssertSql( + """ +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CAST(CHARINDEX(0x01, [s].[Banner], 2) AS int) - 1 = 1 +"""); + } + + public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(bool async) + { + await base.Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(async); + + AssertSql( + """ +@__b_0='0' (Size = 1) +@__startPos_1='0' + +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner], @__startPos_1 + 1) AS int) - 1 = 0 +"""); + } + + public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(bool async) + { + await base.Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(async); + + AssertSql( + """ +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CHARINDEX(0x05, [s].[Banner5], 2) - 1 = 1 +"""); + } + + public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(bool async) + { + await base.Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(async); + + AssertSql( + """ +@__b_0='4' (Size = 1) +@__startPos_1='0' + +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CHARINDEX(CAST(@__b_0 AS varbinary(5)), [s].[Banner5], @__startPos_1 + 1) - 1 = 0 +"""); + } + + #endregion + public override async Task Conditional_expression_with_test_being_simplified_to_constant_simple(bool isAsync) { await base.Conditional_expression_with_test_being_simplified_to_constant_simple(isAsync); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs index 060ffae67ed..e898569764e 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs @@ -8686,6 +8686,116 @@ WHERE DATALENGTH([s].[Banner5]) = 5 """); } + #region Byte Array IndexOf Translation + + public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(bool async) + { + await base.Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(async); + + AssertSql( + """ +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CAST(CHARINDEX(0x01, [s].[Banner]) AS int) - 1 = 1 +"""); + } + + public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(bool async) + { + await base.Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(async); + + AssertSql( + """ +@__b_0='0' (Size = 1) + +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner]) AS int) - 1 = 0 +"""); + } + + public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(bool async) + { + await base.Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(async); + + AssertSql( + """ +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CHARINDEX(0x05, [s].[Banner5]) - 1 = 1 +"""); + } + + public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(bool async) + { + await base.Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(async); + + AssertSql( + """ +@__b_0='4' (Size = 1) + +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CHARINDEX(CAST(@__b_0 AS varbinary(5)), [s].[Banner5]) - 1 = 0 +"""); + } + + public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(bool async) + { + await base.Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(async); + + AssertSql( + """ +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CAST(CHARINDEX(0x01, [s].[Banner], 2) AS int) - 1 = 1 +"""); + } + + public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(bool async) + { + await base.Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(async); + + AssertSql( + """ +@__b_0='0' (Size = 1) +@__startPos_1='0' + +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner], @__startPos_1 + 1) AS int) - 1 = 0 +"""); + } + + public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(bool async) + { + await base.Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(async); + + AssertSql( + """ +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CHARINDEX(0x05, [s].[Banner5], 2) - 1 = 1 +"""); + } + + public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(bool async) + { + await base.Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(async); + + AssertSql( + """ +@__b_0='4' (Size = 1) +@__startPos_1='0' + +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] +FROM [Squads] AS [s] +WHERE CHARINDEX(CAST(@__b_0 AS varbinary(5)), [s].[Banner5], @__startPos_1 + 1) - 1 = 0 +"""); + } + + #endregion + public override async Task Conditional_expression_with_test_being_simplified_to_constant_simple(bool isAsync) { await base.Conditional_expression_with_test_being_simplified_to_constant_simple(isAsync); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs index e9372707817..45441c6807b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs @@ -3262,6 +3262,116 @@ WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] """); } + #region Byte Array IndexOf Translation + + public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(bool async) + { + await base.Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(async); + + AssertSql( + """ +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name], [s].[PeriodEnd], [s].[PeriodStart] +FROM [Squads] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [s] +WHERE CAST(CHARINDEX(0x01, [s].[Banner]) AS int) - 1 = 1 +"""); + } + + public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(bool async) + { + await base.Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(async); + + AssertSql( + """ +@__b_0='0' (Size = 1) + +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name], [s].[PeriodEnd], [s].[PeriodStart] +FROM [Squads] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [s] +WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner]) AS int) - 1 = 0 +"""); + } + + public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(bool async) + { + await base.Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(async); + + AssertSql( + """ +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name], [s].[PeriodEnd], [s].[PeriodStart] +FROM [Squads] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [s] +WHERE CHARINDEX(0x05, [s].[Banner5]) - 1 = 1 +"""); + } + + public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(bool async) + { + await base.Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(async); + + AssertSql( + """ +@__b_0='4' (Size = 1) + +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name], [s].[PeriodEnd], [s].[PeriodStart] +FROM [Squads] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [s] +WHERE CHARINDEX(CAST(@__b_0 AS varbinary(5)), [s].[Banner5]) - 1 = 0 +"""); + } + + public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(bool async) + { + await base.Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(async); + + AssertSql( + """ +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name], [s].[PeriodEnd], [s].[PeriodStart] +FROM [Squads] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [s] +WHERE CAST(CHARINDEX(0x01, [s].[Banner], 2) AS int) - 1 = 1 +"""); + } + + public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(bool async) + { + await base.Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(async); + + AssertSql( + """ +@__b_0='0' (Size = 1) +@__startPos_1='0' + +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name], [s].[PeriodEnd], [s].[PeriodStart] +FROM [Squads] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [s] +WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner], @__startPos_1 + 1) AS int) - 1 = 0 +"""); + } + + public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(bool async) + { + await base.Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(async); + + AssertSql( + """ +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name], [s].[PeriodEnd], [s].[PeriodStart] +FROM [Squads] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [s] +WHERE CHARINDEX(0x05, [s].[Banner5], 2) - 1 = 1 +"""); + } + + public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(bool async) + { + await base.Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(async); + + AssertSql( + """ +@__b_0='4' (Size = 1) +@__startPos_1='0' + +SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name], [s].[PeriodEnd], [s].[PeriodStart] +FROM [Squads] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [s] +WHERE CHARINDEX(CAST(@__b_0 AS varbinary(5)), [s].[Banner5], @__startPos_1 + 1) - 1 = 0 +"""); + } + + #endregion + public override async Task Byte_array_filter_by_length_literal_does_not_cast_on_varbinary_n(bool async) { await base.Byte_array_filter_by_length_literal_does_not_cast_on_varbinary_n(async); diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs index 0c822d8e003..b6a8aef4253 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs @@ -436,6 +436,52 @@ WHERE length("s"."Banner") = length(@__byteArrayParam) """); } + #region Byte Array IndexOf Translation + + // TODO: These tests need to be updated when the translation for IndexOf has been added + + public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(bool async) + { + return Task.CompletedTask; + } + + #endregion + public override async Task Byte_array_filter_by_SequenceEqual(bool async) { await base.Byte_array_filter_by_SequenceEqual(async); diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/TPCGearsOfWarQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/TPCGearsOfWarQuerySqliteTest.cs index 9fe95d394df..b536c518efd 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/TPCGearsOfWarQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/TPCGearsOfWarQuerySqliteTest.cs @@ -301,6 +301,52 @@ public override async Task Byte_array_filter_by_SequenceEqual(bool async) """); } + #region Byte Array IndexOf Translation + + // TODO: These tests need to be updated when the translation for IndexOf has been added + + public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(bool async) + { + return Task.CompletedTask; + } + + #endregion + public override Task Where_TimeSpan_Hours(bool async) // TimeSpan. Issue #18844. => AssertTranslationFailed(() => base.Where_TimeSpan_Hours(async)); diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/TPTGearsOfWarQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/TPTGearsOfWarQuerySqliteTest.cs index 3b05ecd09e3..c4bac47a2a2 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/TPTGearsOfWarQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/TPTGearsOfWarQuerySqliteTest.cs @@ -301,6 +301,52 @@ public override async Task Byte_array_filter_by_SequenceEqual(bool async) """); } + #region Byte Array IndexOf Translation + + // TODO: These tests need to be updated when the translation for IndexOf has been added + + public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(bool async) + { + return Task.CompletedTask; + } + + public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(bool async) + { + return Task.CompletedTask; + } + + #endregion + public override Task Where_TimeSpan_Hours(bool async) // TimeSpan. Issue #18844. => AssertTranslationFailed(() => base.Where_TimeSpan_Hours(async)); From ec0b63d486aa31a501fe2ca72d7eb16287d815d5 Mon Sep 17 00:00:00 2001 From: Nikhil Bansal Date: Sun, 18 Aug 2024 15:36:32 +0530 Subject: [PATCH 3/4] Added Support for Translating ByteArray.IndexOf for SQLite Fixes #19287 --- .../SqlServerByteArrayMethodTranslator.cs | 20 +---- .../SqliteByteArrayMethodTranslator.cs | 57 +++++++++----- src/Shared/ArrayMethods.cs | 36 +++++++++ .../Query/GearsOfWarQueryTestBase.cs | 36 ++++----- .../Query/GearsOfWarQuerySqlServerTest.cs | 32 ++++---- .../Query/TPCGearsOfWarQuerySqlServerTest.cs | 32 ++++---- .../Query/TPTGearsOfWarQuerySqlServerTest.cs | 32 ++++---- .../TemporalGearsOfWarQuerySqlServerTest.cs | 32 ++++---- .../Query/GearsOfWarQuerySqliteTest.cs | 74 ++++++++++++------- .../Query/TPCGearsOfWarQuerySqliteTest.cs | 74 ++++++++++++------- .../Query/TPTGearsOfWarQuerySqliteTest.cs | 74 ++++++++++++------- 11 files changed, 299 insertions(+), 200 deletions(-) create mode 100644 src/Shared/ArrayMethods.cs diff --git a/src/EFCore.SqlServer/Query/Internal/Translators/SqlServerByteArrayMethodTranslator.cs b/src/EFCore.SqlServer/Query/Internal/Translators/SqlServerByteArrayMethodTranslator.cs index c317e54eb08..e39444e3fd5 100644 --- a/src/EFCore.SqlServer/Query/Internal/Translators/SqlServerByteArrayMethodTranslator.cs +++ b/src/EFCore.SqlServer/Query/Internal/Translators/SqlServerByteArrayMethodTranslator.cs @@ -16,21 +16,6 @@ public class SqlServerByteArrayMethodTranslator : IMethodCallTranslator { private readonly ISqlExpressionFactory _sqlExpressionFactory; - // NOTE: Might want to move these to a shared file, similar to EnumerableMethods - private static readonly MethodInfo IndexOfMethodInfo - = typeof(Array) - .GetGenericMethod(nameof(Array.IndexOf), 1, BindingFlags.Public | BindingFlags.Static, (_, t) => - { - return [t[0].MakeArrayType(), t[0]]; - })!; - - private static readonly MethodInfo IndexOfWithStartingPositionMethodInfo - = typeof(Array) - .GetGenericMethod(nameof(Array.IndexOf), 1, BindingFlags.Public | BindingFlags.Static, (_, t) => - { - return [t[0].MakeArrayType(), t[0], typeof(int)]; - })!; - /// /// 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 @@ -61,7 +46,6 @@ public SqlServerByteArrayMethodTranslator(ISqlExpressionFactory sqlExpressionFac var methodDefinition = method.GetGenericMethodDefinition(); if (methodDefinition.Equals(EnumerableMethods.Contains)) { - // NOTE: Should this be refactored to use the TranslateIndexOf method?? Everything is same expect one check var source = arguments[0]; var sourceTypeMapping = source.TypeMapping; @@ -91,12 +75,12 @@ public SqlServerByteArrayMethodTranslator(ISqlExpressionFactory sqlExpressionFac method.ReturnType); } - if (methodDefinition.Equals(IndexOfMethodInfo)) + if (methodDefinition.Equals(ArrayMethods.IndexOf)) { return TranslateIndexOf(method, arguments[0], arguments[1], null); } - if (methodDefinition.Equals(IndexOfWithStartingPositionMethodInfo)) + if (methodDefinition.Equals(ArrayMethods.IndexOfWithStartingPosition)) { return TranslateIndexOf(method, arguments[0], arguments[1], arguments[2]); } diff --git a/src/EFCore.Sqlite.Core/Query/Internal/Translators/SqliteByteArrayMethodTranslator.cs b/src/EFCore.Sqlite.Core/Query/Internal/Translators/SqliteByteArrayMethodTranslator.cs index d4e67d23a7c..5a7215a2b8d 100644 --- a/src/EFCore.Sqlite.Core/Query/Internal/Translators/SqliteByteArrayMethodTranslator.cs +++ b/src/EFCore.Sqlite.Core/Query/Internal/Translators/SqliteByteArrayMethodTranslator.cs @@ -40,28 +40,30 @@ public SqliteByteArrayMethodTranslator(ISqlExpressionFactory sqlExpressionFactor IDiagnosticsLogger logger) { if (method.IsGenericMethod - && method.GetGenericMethodDefinition().Equals(EnumerableMethods.Contains) + && arguments.Count >= 1 && arguments[0].Type == typeof(byte[])) { - var source = arguments[0]; + var genericMethodDefinition = method.GetGenericMethodDefinition(); + if (genericMethodDefinition.Equals(EnumerableMethods.Contains)) + { + return _sqlExpressionFactory.GreaterThan( + GetInStrSqlFunctionExpression(arguments[0], arguments[1]), + _sqlExpressionFactory.Constant(0)); - var value = arguments[1] is SqlConstantExpression constantValue - ? (SqlExpression)_sqlExpressionFactory.Constant(new[] { (byte)constantValue.Value! }, source.TypeMapping) - : _sqlExpressionFactory.Function( - "char", - new[] { arguments[1] }, - nullable: false, - argumentsPropagateNullability: new[] { false }, - typeof(string)); + } - return _sqlExpressionFactory.GreaterThan( - _sqlExpressionFactory.Function( - "instr", - new[] { source, value }, - nullable: true, - argumentsPropagateNullability: new[] { true, true }, - typeof(int)), - _sqlExpressionFactory.Constant(0)); + if (genericMethodDefinition.Equals(ArrayMethods.IndexOf)) + { + return _sqlExpressionFactory.Subtract( + GetInStrSqlFunctionExpression(arguments[0], arguments[1]), + _sqlExpressionFactory.Constant(1)); + } + + if (genericMethodDefinition.Equals(ArrayMethods.IndexOfWithStartingPosition)) + { + // NOTE: IndexOf Method with a starting position is not supported by SQLite + return null; + } } // See issue#16428 @@ -92,4 +94,23 @@ public SqliteByteArrayMethodTranslator(ISqlExpressionFactory sqlExpressionFactor return null; } + + private SqlExpression GetInStrSqlFunctionExpression(SqlExpression source, SqlExpression valueToSearch) + { + var value = valueToSearch is SqlConstantExpression { Value: byte constantValue } + ? _sqlExpressionFactory.Constant(new byte[] { constantValue }, source.TypeMapping) + : _sqlExpressionFactory.Function( + "char", + [valueToSearch], + nullable: false, + argumentsPropagateNullability: [false], + typeof(string)); + + return _sqlExpressionFactory.Function( + "instr", + [source, value], + nullable: true, + argumentsPropagateNullability: [true, true], + typeof(int)); + } } diff --git a/src/Shared/ArrayMethods.cs b/src/Shared/ArrayMethods.cs new file mode 100644 index 00000000000..220481c7679 --- /dev/null +++ b/src/Shared/ArrayMethods.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore; + +internal static class ArrayMethods +{ + public static MethodInfo IndexOf { get; } + + public static MethodInfo IndexOfWithStartingPosition { get; } + + static ArrayMethods() + { + var arrayGenericMethods = typeof(Array) + .GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly) + .Where(m => m.IsGenericMethod) + .GroupBy(m => m.Name) + .ToDictionary(m => m.Key, l => l.ToList()); + + IndexOf = GetMethod(nameof(Array.IndexOf), 1, (t) => + { + return [t[0].MakeArrayType(), t[0]]; + }); + + IndexOfWithStartingPosition = GetMethod(nameof(Array.IndexOf), 1, (t) => + { + return [t[0].MakeArrayType(), t[0], typeof(int)]; + }); + + MethodInfo GetMethod(string name, int genericParameterCount, Func parameterGenerator) + => arrayGenericMethods[name].Single( + mi => mi.IsGenericMethod && mi.GetGenericArguments().Length == genericParameterCount + && mi.GetParameters().Select(e => e.ParameterType).SequenceEqual( + parameterGenerator(mi.IsGenericMethod ? mi.GetGenericArguments() : []))); + } +} diff --git a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs index c0304cffe59..45d1eaf997e 100644 --- a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs @@ -6263,18 +6263,16 @@ public virtual Task Byte_array_filter_by_length_parameter(bool async) [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(bool async) - { - return AssertQuery( + public virtual Task Byte_array_with_max_possible_length_filter_by_index_of_literal(bool async) + => AssertQuery( async, ss => ss.Set().Where(w => Array.IndexOf(w.Banner, (byte)1) == 1), ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner, (byte)1) == 1) ); - } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(bool async) + public virtual Task Byte_array_with_max_possible_length_filter_by_index_of_parameter(bool async) { byte b = 0; return AssertQuery( @@ -6286,18 +6284,16 @@ public virtual Task Byte_array_of_type_varbinary_max_filter_by_index_of_paramete [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(bool async) - { - return AssertQuery( + public virtual Task Byte_array_with_length_n_filter_by_index_of_literal(bool async) + => AssertQuery( async, ss => ss.Set().Where(w => Array.IndexOf(w.Banner5, (byte)5) == 1), ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner5, (byte)5) == 1) ); - } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(bool async) + public virtual Task Byte_array_with_lenght_n_filter_by_index_of_parameter(bool async) { byte b = 4; return AssertQuery( @@ -6309,21 +6305,19 @@ public virtual Task Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_ [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(bool async) - { - return AssertQuery( + public virtual Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(bool async) + => AssertQuery( async, ss => ss.Set().Where(w => Array.IndexOf(w.Banner, (byte)1, 1) == 1), ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner, (byte)1, 1) == 1) ); - } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(bool async) + public virtual Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(bool async) { byte b = 0; - int startPos = 0; + var startPos = 0; return AssertQuery( async, ss => ss.Set().Where(w => Array.IndexOf(w.Banner, b, startPos) == 0), @@ -6333,21 +6327,19 @@ public virtual Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_sta [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(bool async) - { - return AssertQuery( + public virtual Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(bool async) + => AssertQuery( async, ss => ss.Set().Where(w => Array.IndexOf(w.Banner5, (byte)5, 1) == 1), ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner5, (byte)5, 1) == 1) ); - } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(bool async) + public virtual Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(bool async) { byte b = 4; - int startPos = 0; + var startPos = 0; return AssertQuery( async, ss => ss.Set().Where(w => Array.IndexOf(w.Banner5, b, startPos) == 0), diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index f7370739a85..f490b9a2adc 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -7678,9 +7678,9 @@ WHERE DATALENGTH([s].[Banner5]) = 5 #region Byte Array IndexOf Translation - public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_literal(bool async) { - await base.Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(async); + await base.Byte_array_with_max_possible_length_filter_by_index_of_literal(async); AssertSql( """ @@ -7690,9 +7690,9 @@ WHERE CAST(CHARINDEX(0x01, [s].[Banner]) AS int) - 1 = 1 """); } - public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_parameter(bool async) { - await base.Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(async); + await base.Byte_array_with_max_possible_length_filter_by_index_of_parameter(async); AssertSql( """ @@ -7704,9 +7704,9 @@ WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner]) AS int) - 1 = """); } - public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(bool async) + public override async Task Byte_array_with_length_n_filter_by_index_of_literal(bool async) { - await base.Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(async); + await base.Byte_array_with_length_n_filter_by_index_of_literal(async); AssertSql( """ @@ -7716,9 +7716,9 @@ WHERE CHARINDEX(0x05, [s].[Banner5]) - 1 = 1 """); } - public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(bool async) + public override async Task Byte_array_with_lenght_n_filter_by_index_of_parameter(bool async) { - await base.Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(async); + await base.Byte_array_with_lenght_n_filter_by_index_of_parameter(async); AssertSql( """ @@ -7730,9 +7730,9 @@ WHERE CHARINDEX(CAST(@__b_0 AS varbinary(5)), [s].[Banner5]) - 1 = 0 """); } - public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(bool async) { - await base.Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(async); + await base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(async); AssertSql( """ @@ -7742,9 +7742,9 @@ WHERE CAST(CHARINDEX(0x01, [s].[Banner], 2) AS int) - 1 = 1 """); } - public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(bool async) { - await base.Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(async); + await base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(async); AssertSql( """ @@ -7757,9 +7757,9 @@ WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner], @__startPos_1 """); } - public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(bool async) + public override async Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(bool async) { - await base.Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(async); + await base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(async); AssertSql( """ @@ -7769,9 +7769,9 @@ WHERE CHARINDEX(0x05, [s].[Banner5], 2) - 1 = 1 """); } - public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(bool async) + public override async Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(bool async) { - await base.Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(async); + await base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(async); AssertSql( """ diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs index 8f12ed4fa79..bfc654dd4d2 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs @@ -10222,9 +10222,9 @@ WHERE DATALENGTH([s].[Banner5]) = 5 #region Byte Array IndexOf Translation - public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_literal(bool async) { - await base.Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(async); + await base.Byte_array_with_max_possible_length_filter_by_index_of_literal(async); AssertSql( """ @@ -10234,9 +10234,9 @@ WHERE CAST(CHARINDEX(0x01, [s].[Banner]) AS int) - 1 = 1 """); } - public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_parameter(bool async) { - await base.Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(async); + await base.Byte_array_with_max_possible_length_filter_by_index_of_parameter(async); AssertSql( """ @@ -10248,9 +10248,9 @@ WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner]) AS int) - 1 = """); } - public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(bool async) + public override async Task Byte_array_with_length_n_filter_by_index_of_literal(bool async) { - await base.Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(async); + await base.Byte_array_with_length_n_filter_by_index_of_literal(async); AssertSql( """ @@ -10260,9 +10260,9 @@ WHERE CHARINDEX(0x05, [s].[Banner5]) - 1 = 1 """); } - public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(bool async) + public override async Task Byte_array_with_lenght_n_filter_by_index_of_parameter(bool async) { - await base.Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(async); + await base.Byte_array_with_lenght_n_filter_by_index_of_parameter(async); AssertSql( """ @@ -10274,9 +10274,9 @@ WHERE CHARINDEX(CAST(@__b_0 AS varbinary(5)), [s].[Banner5]) - 1 = 0 """); } - public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(bool async) { - await base.Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(async); + await base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(async); AssertSql( """ @@ -10286,9 +10286,9 @@ WHERE CAST(CHARINDEX(0x01, [s].[Banner], 2) AS int) - 1 = 1 """); } - public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(bool async) { - await base.Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(async); + await base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(async); AssertSql( """ @@ -10301,9 +10301,9 @@ WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner], @__startPos_1 """); } - public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(bool async) + public override async Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(bool async) { - await base.Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(async); + await base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(async); AssertSql( """ @@ -10313,9 +10313,9 @@ WHERE CHARINDEX(0x05, [s].[Banner5], 2) - 1 = 1 """); } - public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(bool async) + public override async Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(bool async) { - await base.Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(async); + await base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(async); AssertSql( """ diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs index e898569764e..59fe339674c 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs @@ -8688,9 +8688,9 @@ WHERE DATALENGTH([s].[Banner5]) = 5 #region Byte Array IndexOf Translation - public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_literal(bool async) { - await base.Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(async); + await base.Byte_array_with_max_possible_length_filter_by_index_of_literal(async); AssertSql( """ @@ -8700,9 +8700,9 @@ WHERE CAST(CHARINDEX(0x01, [s].[Banner]) AS int) - 1 = 1 """); } - public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_parameter(bool async) { - await base.Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(async); + await base.Byte_array_with_max_possible_length_filter_by_index_of_parameter(async); AssertSql( """ @@ -8714,9 +8714,9 @@ WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner]) AS int) - 1 = """); } - public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(bool async) + public override async Task Byte_array_with_length_n_filter_by_index_of_literal(bool async) { - await base.Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(async); + await base.Byte_array_with_length_n_filter_by_index_of_literal(async); AssertSql( """ @@ -8726,9 +8726,9 @@ WHERE CHARINDEX(0x05, [s].[Banner5]) - 1 = 1 """); } - public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(bool async) + public override async Task Byte_array_with_lenght_n_filter_by_index_of_parameter(bool async) { - await base.Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(async); + await base.Byte_array_with_lenght_n_filter_by_index_of_parameter(async); AssertSql( """ @@ -8740,9 +8740,9 @@ WHERE CHARINDEX(CAST(@__b_0 AS varbinary(5)), [s].[Banner5]) - 1 = 0 """); } - public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(bool async) { - await base.Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(async); + await base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(async); AssertSql( """ @@ -8752,9 +8752,9 @@ WHERE CAST(CHARINDEX(0x01, [s].[Banner], 2) AS int) - 1 = 1 """); } - public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(bool async) { - await base.Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(async); + await base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(async); AssertSql( """ @@ -8767,9 +8767,9 @@ WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner], @__startPos_1 """); } - public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(bool async) + public override async Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(bool async) { - await base.Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(async); + await base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(async); AssertSql( """ @@ -8779,9 +8779,9 @@ WHERE CHARINDEX(0x05, [s].[Banner5], 2) - 1 = 1 """); } - public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(bool async) + public override async Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(bool async) { - await base.Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(async); + await base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(async); AssertSql( """ diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs index 45441c6807b..7f7d8789fc8 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs @@ -3264,9 +3264,9 @@ WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] #region Byte Array IndexOf Translation - public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_literal(bool async) { - await base.Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(async); + await base.Byte_array_with_max_possible_length_filter_by_index_of_literal(async); AssertSql( """ @@ -3276,9 +3276,9 @@ WHERE CAST(CHARINDEX(0x01, [s].[Banner]) AS int) - 1 = 1 """); } - public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_parameter(bool async) { - await base.Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(async); + await base.Byte_array_with_max_possible_length_filter_by_index_of_parameter(async); AssertSql( """ @@ -3290,9 +3290,9 @@ WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner]) AS int) - 1 = """); } - public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(bool async) + public override async Task Byte_array_with_length_n_filter_by_index_of_literal(bool async) { - await base.Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(async); + await base.Byte_array_with_length_n_filter_by_index_of_literal(async); AssertSql( """ @@ -3302,9 +3302,9 @@ WHERE CHARINDEX(0x05, [s].[Banner5]) - 1 = 1 """); } - public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(bool async) + public override async Task Byte_array_with_lenght_n_filter_by_index_of_parameter(bool async) { - await base.Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(async); + await base.Byte_array_with_lenght_n_filter_by_index_of_parameter(async); AssertSql( """ @@ -3316,9 +3316,9 @@ WHERE CHARINDEX(CAST(@__b_0 AS varbinary(5)), [s].[Banner5]) - 1 = 0 """); } - public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(bool async) { - await base.Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(async); + await base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(async); AssertSql( """ @@ -3328,9 +3328,9 @@ WHERE CAST(CHARINDEX(0x01, [s].[Banner], 2) AS int) - 1 = 1 """); } - public override async Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(bool async) { - await base.Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(async); + await base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(async); AssertSql( """ @@ -3343,9 +3343,9 @@ WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner], @__startPos_1 """); } - public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(bool async) + public override async Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(bool async) { - await base.Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(async); + await base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(async); AssertSql( """ @@ -3355,9 +3355,9 @@ WHERE CHARINDEX(0x05, [s].[Banner5], 2) - 1 = 1 """); } - public override async Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(bool async) + public override async Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(bool async) { - await base.Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(async); + await base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(async); AssertSql( """ diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs index b6a8aef4253..a2422a2dfeb 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs @@ -438,48 +438,70 @@ WHERE length("s"."Banner") = length(@__byteArrayParam) #region Byte Array IndexOf Translation - // TODO: These tests need to be updated when the translation for IndexOf has been added - - public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_literal(bool async) { - return Task.CompletedTask; - } + await base.Byte_array_with_max_possible_length_filter_by_index_of_literal(async); - public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(bool async) - { - return Task.CompletedTask; + AssertSql( + """ +SELECT "s"."Id", "s"."Banner", "s"."Banner5", "s"."InternalNumber", "s"."Name" +FROM "Squads" AS "s" +WHERE instr("s"."Banner", X'01') - 1 = 1 +"""); } - public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_parameter(bool async) { - return Task.CompletedTask; - } + await base.Byte_array_with_max_possible_length_filter_by_index_of_parameter(async); - public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(bool async) - { - return Task.CompletedTask; - } + AssertSql( + """ +@__b_0='0' - public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(bool async) - { - return Task.CompletedTask; +SELECT "s"."Id", "s"."Banner", "s"."Banner5", "s"."InternalNumber", "s"."Name" +FROM "Squads" AS "s" +WHERE instr("s"."Banner", char(@__b_0)) - 1 = 0 +"""); } - public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(bool async) + public override async Task Byte_array_with_length_n_filter_by_index_of_literal(bool async) { - return Task.CompletedTask; - } + await base.Byte_array_with_length_n_filter_by_index_of_literal(async); - public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(bool async) - { - return Task.CompletedTask; + AssertSql( + """ +SELECT "s"."Id", "s"."Banner", "s"."Banner5", "s"."InternalNumber", "s"."Name" +FROM "Squads" AS "s" +WHERE instr("s"."Banner5", X'05') - 1 = 1 +"""); } - public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(bool async) + public override async Task Byte_array_with_lenght_n_filter_by_index_of_parameter(bool async) { - return Task.CompletedTask; + await base.Byte_array_with_lenght_n_filter_by_index_of_parameter(async); + + AssertSql( + """ +@__b_0='4' + +SELECT "s"."Id", "s"."Banner", "s"."Banner5", "s"."InternalNumber", "s"."Name" +FROM "Squads" AS "s" +WHERE instr("s"."Banner5", char(@__b_0)) - 1 = 0 +"""); } + public override Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(async)); + + public override Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(async)); + + public override Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(async)); + + public override Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(async)); + #endregion public override async Task Byte_array_filter_by_SequenceEqual(bool async) diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/TPCGearsOfWarQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/TPCGearsOfWarQuerySqliteTest.cs index b536c518efd..75200b370b4 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/TPCGearsOfWarQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/TPCGearsOfWarQuerySqliteTest.cs @@ -303,48 +303,70 @@ public override async Task Byte_array_filter_by_SequenceEqual(bool async) #region Byte Array IndexOf Translation - // TODO: These tests need to be updated when the translation for IndexOf has been added - - public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_literal(bool async) { - return Task.CompletedTask; - } + await base.Byte_array_with_max_possible_length_filter_by_index_of_literal(async); - public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(bool async) - { - return Task.CompletedTask; + AssertSql( + """ +SELECT "s"."Id", "s"."Banner", "s"."Banner5", "s"."InternalNumber", "s"."Name" +FROM "Squads" AS "s" +WHERE instr("s"."Banner", X'01') - 1 = 1 +"""); } - public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_parameter(bool async) { - return Task.CompletedTask; - } + await base.Byte_array_with_max_possible_length_filter_by_index_of_parameter(async); - public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(bool async) - { - return Task.CompletedTask; - } + AssertSql( + """ +@__b_0='0' - public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(bool async) - { - return Task.CompletedTask; +SELECT "s"."Id", "s"."Banner", "s"."Banner5", "s"."InternalNumber", "s"."Name" +FROM "Squads" AS "s" +WHERE instr("s"."Banner", char(@__b_0)) - 1 = 0 +"""); } - public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(bool async) + public override async Task Byte_array_with_length_n_filter_by_index_of_literal(bool async) { - return Task.CompletedTask; - } + await base.Byte_array_with_length_n_filter_by_index_of_literal(async); - public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(bool async) - { - return Task.CompletedTask; + AssertSql( + """ +SELECT "s"."Id", "s"."Banner", "s"."Banner5", "s"."InternalNumber", "s"."Name" +FROM "Squads" AS "s" +WHERE instr("s"."Banner5", X'05') - 1 = 1 +"""); } - public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(bool async) + public override async Task Byte_array_with_lenght_n_filter_by_index_of_parameter(bool async) { - return Task.CompletedTask; + await base.Byte_array_with_lenght_n_filter_by_index_of_parameter(async); + + AssertSql( + """ +@__b_0='4' + +SELECT "s"."Id", "s"."Banner", "s"."Banner5", "s"."InternalNumber", "s"."Name" +FROM "Squads" AS "s" +WHERE instr("s"."Banner5", char(@__b_0)) - 1 = 0 +"""); } + public override Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(async)); + + public override Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(async)); + + public override Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(async)); + + public override Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(async)); + #endregion public override Task Where_TimeSpan_Hours(bool async) diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/TPTGearsOfWarQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/TPTGearsOfWarQuerySqliteTest.cs index c4bac47a2a2..641aee7f7db 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/TPTGearsOfWarQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/TPTGearsOfWarQuerySqliteTest.cs @@ -303,48 +303,70 @@ public override async Task Byte_array_filter_by_SequenceEqual(bool async) #region Byte Array IndexOf Translation - // TODO: These tests need to be updated when the translation for IndexOf has been added - - public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_literal_casts_to_int(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_literal(bool async) { - return Task.CompletedTask; - } + await base.Byte_array_with_max_possible_length_filter_by_index_of_literal(async); - public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_parameter_casts_to_int(bool async) - { - return Task.CompletedTask; + AssertSql( + """ +SELECT "s"."Id", "s"."Banner", "s"."Banner5", "s"."InternalNumber", "s"."Name" +FROM "Squads" AS "s" +WHERE instr("s"."Banner", X'01') - 1 = 1 +"""); } - public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_literal_does_not_cast(bool async) + public override async Task Byte_array_with_max_possible_length_filter_by_index_of_parameter(bool async) { - return Task.CompletedTask; - } + await base.Byte_array_with_max_possible_length_filter_by_index_of_parameter(async); - public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_parameter_does_not_cast(bool async) - { - return Task.CompletedTask; - } + AssertSql( + """ +@__b_0='0' - public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_literal_casts_to_int(bool async) - { - return Task.CompletedTask; +SELECT "s"."Id", "s"."Banner", "s"."Banner5", "s"."InternalNumber", "s"."Name" +FROM "Squads" AS "s" +WHERE instr("s"."Banner", char(@__b_0)) - 1 = 0 +"""); } - public override Task Byte_array_of_type_varbinary_max_filter_by_index_of_with_starting_position_parameter_casts_to_int(bool async) + public override async Task Byte_array_with_length_n_filter_by_index_of_literal(bool async) { - return Task.CompletedTask; - } + await base.Byte_array_with_length_n_filter_by_index_of_literal(async); - public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_literal_does_not_cast(bool async) - { - return Task.CompletedTask; + AssertSql( + """ +SELECT "s"."Id", "s"."Banner", "s"."Banner5", "s"."InternalNumber", "s"."Name" +FROM "Squads" AS "s" +WHERE instr("s"."Banner5", X'05') - 1 = 1 +"""); } - public override Task Byte_array_of_type_varbinary_n_filter_by_index_of_with_starting_position_parameter_does_not_cast(bool async) + public override async Task Byte_array_with_lenght_n_filter_by_index_of_parameter(bool async) { - return Task.CompletedTask; + await base.Byte_array_with_lenght_n_filter_by_index_of_parameter(async); + + AssertSql( + """ +@__b_0='4' + +SELECT "s"."Id", "s"."Banner", "s"."Banner5", "s"."InternalNumber", "s"."Name" +FROM "Squads" AS "s" +WHERE instr("s"."Banner5", char(@__b_0)) - 1 = 0 +"""); } + public override Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(async)); + + public override Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(async)); + + public override Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(async)); + + public override Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(async)); + #endregion public override Task Where_TimeSpan_Hours(bool async) From 5a2d7ff5124d00d3204893f7f871e3d346097196 Mon Sep 17 00:00:00 2001 From: Nikhil Bansal Date: Mon, 19 Aug 2024 19:30:38 +0530 Subject: [PATCH 4/4] Removed ArrayMethods class and refactoring --- .../SqlServerByteArrayMethodTranslator.cs | 50 ++++++++++--------- .../SqliteByteArrayMethodTranslator.cs | 35 +++++++------ src/Shared/ArrayMethods.cs | 36 ------------- .../Query/GearsOfWarQueryTestBase.cs | 40 ++++++--------- .../Query/GearsOfWarQuerySqlServerTest.cs | 32 ++++++------ .../Query/TPCGearsOfWarQuerySqlServerTest.cs | 32 ++++++------ .../Query/TPTGearsOfWarQuerySqlServerTest.cs | 32 ++++++------ .../TemporalGearsOfWarQuerySqlServerTest.cs | 32 ++++++------ .../Query/GearsOfWarQuerySqliteTest.cs | 32 ++++++------ .../Query/TPCGearsOfWarQuerySqliteTest.cs | 32 ++++++------ .../Query/TPTGearsOfWarQuerySqliteTest.cs | 32 ++++++------ 11 files changed, 171 insertions(+), 214 deletions(-) delete mode 100644 src/Shared/ArrayMethods.cs diff --git a/src/EFCore.SqlServer/Query/Internal/Translators/SqlServerByteArrayMethodTranslator.cs b/src/EFCore.SqlServer/Query/Internal/Translators/SqlServerByteArrayMethodTranslator.cs index e39444e3fd5..e480d23cf09 100644 --- a/src/EFCore.SqlServer/Query/Internal/Translators/SqlServerByteArrayMethodTranslator.cs +++ b/src/EFCore.SqlServer/Query/Internal/Translators/SqlServerByteArrayMethodTranslator.cs @@ -14,6 +14,12 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal; /// public class SqlServerByteArrayMethodTranslator : IMethodCallTranslator { + private static readonly MethodInfo ArrayIndexOf + = typeof(Array).GetMethod(nameof(Array.IndexOf), 1, BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly, null, CallingConventions.Any, [Type.MakeGenericMethodParameter(0).MakeArrayType(), Type.MakeGenericMethodParameter(0)], null)!; + + private static readonly MethodInfo ArrayIndexOfWithStartIndex + = typeof(Array).GetMethod(nameof(Array.IndexOf), 1, BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly, null, CallingConventions.Any, [Type.MakeGenericMethodParameter(0).MakeArrayType(), Type.MakeGenericMethodParameter(0), typeof(int)], null)!; + private readonly ISqlExpressionFactory _sqlExpressionFactory; /// @@ -75,33 +81,32 @@ public SqlServerByteArrayMethodTranslator(ISqlExpressionFactory sqlExpressionFac method.ReturnType); } - if (methodDefinition.Equals(ArrayMethods.IndexOf)) + if (methodDefinition.Equals(ArrayIndexOf)) { - return TranslateIndexOf(method, arguments[0], arguments[1], null); + return TranslateByteArrayIndexOf(method, arguments[0], arguments[1], null); } - if (methodDefinition.Equals(ArrayMethods.IndexOfWithStartingPosition)) + if (methodDefinition.Equals(ArrayIndexOfWithStartIndex)) { - return TranslateIndexOf(method, arguments[0], arguments[1], arguments[2]); + return TranslateByteArrayIndexOf(method, arguments[0], arguments[1], arguments[2]); } } return null; } - private SqlExpression TranslateIndexOf( + private SqlExpression TranslateByteArrayIndexOf( MethodInfo method, SqlExpression source, SqlExpression valueToSearch, - SqlExpression? startIndex - ) + SqlExpression? startIndex) { var sourceTypeMapping = source.TypeMapping; var sqlArguments = new List { valueToSearch is SqlConstantExpression { Value: byte constantValue } - ? _sqlExpressionFactory.Constant(new byte[] { constantValue }, sourceTypeMapping) - : _sqlExpressionFactory.Convert(valueToSearch, typeof(byte[]), sourceTypeMapping), + ? _sqlExpressionFactory.Constant(new byte[] { constantValue }, sourceTypeMapping) + : _sqlExpressionFactory.Convert(valueToSearch, typeof(byte[]), sourceTypeMapping), source }; @@ -109,9 +114,8 @@ private SqlExpression TranslateIndexOf( { sqlArguments.Add( startIndex is SqlConstantExpression { Value : int index } - ? _sqlExpressionFactory.Constant(index + 1, typeof(int)) - : _sqlExpressionFactory.Add(startIndex, _sqlExpressionFactory.Constant(1)) - ); + ? _sqlExpressionFactory.Constant(index + 1, typeof(int)) + : _sqlExpressionFactory.Add(startIndex, _sqlExpressionFactory.Constant(1))); } var argumentsPropagateNullability = Enumerable.Repeat(true, sqlArguments.Count); @@ -120,26 +124,24 @@ private SqlExpression TranslateIndexOf( var storeType = sourceTypeMapping?.StoreType; if (storeType == "varbinary(max)") { - charIndexExpr = _sqlExpressionFactory.Function( - "CHARINDEX", - sqlArguments, - nullable: true, - argumentsPropagateNullability: argumentsPropagateNullability, - typeof(long)); - + charIndexExpr = GetCharIndexSqlFunctionExpression(sqlArguments, argumentsPropagateNullability, typeof(long)); charIndexExpr = _sqlExpressionFactory.Convert(charIndexExpr, typeof(int)); } else { - charIndexExpr = _sqlExpressionFactory.Function( + charIndexExpr = GetCharIndexSqlFunctionExpression(sqlArguments, argumentsPropagateNullability, method.ReturnType); + } + + return _sqlExpressionFactory.Subtract(charIndexExpr, _sqlExpressionFactory.Constant(1)); + + SqlExpression GetCharIndexSqlFunctionExpression(List sqlArguments, IEnumerable argumentsPropagateNullability, Type returnType) + { + return _sqlExpressionFactory.Function( "CHARINDEX", sqlArguments, nullable: true, argumentsPropagateNullability: argumentsPropagateNullability, - method.ReturnType); + returnType); } - - - return _sqlExpressionFactory.Subtract(charIndexExpr, _sqlExpressionFactory.Constant(1)); } } diff --git a/src/EFCore.Sqlite.Core/Query/Internal/Translators/SqliteByteArrayMethodTranslator.cs b/src/EFCore.Sqlite.Core/Query/Internal/Translators/SqliteByteArrayMethodTranslator.cs index 5a7215a2b8d..ddc1cf44a8d 100644 --- a/src/EFCore.Sqlite.Core/Query/Internal/Translators/SqliteByteArrayMethodTranslator.cs +++ b/src/EFCore.Sqlite.Core/Query/Internal/Translators/SqliteByteArrayMethodTranslator.cs @@ -14,6 +14,9 @@ namespace Microsoft.EntityFrameworkCore.Sqlite.Query.Internal; /// public class SqliteByteArrayMethodTranslator : IMethodCallTranslator { + private static readonly MethodInfo ArrayIndexOf + = typeof(Array).GetMethod(nameof(Array.IndexOf), 1, BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly, null, CallingConventions.Any, [Type.MakeGenericMethodParameter(0).MakeArrayType(), Type.MakeGenericMethodParameter(0)], null)!; + private readonly ISqlExpressionFactory _sqlExpressionFactory; /// @@ -52,18 +55,14 @@ public SqliteByteArrayMethodTranslator(ISqlExpressionFactory sqlExpressionFactor } - if (genericMethodDefinition.Equals(ArrayMethods.IndexOf)) + if (genericMethodDefinition.Equals(ArrayIndexOf)) { return _sqlExpressionFactory.Subtract( GetInStrSqlFunctionExpression(arguments[0], arguments[1]), _sqlExpressionFactory.Constant(1)); } - if (genericMethodDefinition.Equals(ArrayMethods.IndexOfWithStartingPosition)) - { - // NOTE: IndexOf Method with a starting position is not supported by SQLite - return null; - } + // NOTE: IndexOf Method with a starting position is not supported by SQLite } // See issue#16428 @@ -93,24 +92,24 @@ public SqliteByteArrayMethodTranslator(ISqlExpressionFactory sqlExpressionFactor //} return null; - } - private SqlExpression GetInStrSqlFunctionExpression(SqlExpression source, SqlExpression valueToSearch) - { - var value = valueToSearch is SqlConstantExpression { Value: byte constantValue } - ? _sqlExpressionFactory.Constant(new byte[] { constantValue }, source.TypeMapping) - : _sqlExpressionFactory.Function( - "char", - [valueToSearch], - nullable: false, - argumentsPropagateNullability: [false], - typeof(string)); + SqlExpression GetInStrSqlFunctionExpression(SqlExpression source, SqlExpression valueToSearch) + { + var value = valueToSearch is SqlConstantExpression { Value: byte constantValue } + ? _sqlExpressionFactory.Constant(new byte[] { constantValue }, source.TypeMapping) + : _sqlExpressionFactory.Function( + "char", + [valueToSearch], + nullable: false, + argumentsPropagateNullability: [false], + typeof(string)); - return _sqlExpressionFactory.Function( + return _sqlExpressionFactory.Function( "instr", [source, value], nullable: true, argumentsPropagateNullability: [true, true], typeof(int)); + } } } diff --git a/src/Shared/ArrayMethods.cs b/src/Shared/ArrayMethods.cs deleted file mode 100644 index 220481c7679..00000000000 --- a/src/Shared/ArrayMethods.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Microsoft.EntityFrameworkCore; - -internal static class ArrayMethods -{ - public static MethodInfo IndexOf { get; } - - public static MethodInfo IndexOfWithStartingPosition { get; } - - static ArrayMethods() - { - var arrayGenericMethods = typeof(Array) - .GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly) - .Where(m => m.IsGenericMethod) - .GroupBy(m => m.Name) - .ToDictionary(m => m.Key, l => l.ToList()); - - IndexOf = GetMethod(nameof(Array.IndexOf), 1, (t) => - { - return [t[0].MakeArrayType(), t[0]]; - }); - - IndexOfWithStartingPosition = GetMethod(nameof(Array.IndexOf), 1, (t) => - { - return [t[0].MakeArrayType(), t[0], typeof(int)]; - }); - - MethodInfo GetMethod(string name, int genericParameterCount, Func parameterGenerator) - => arrayGenericMethods[name].Single( - mi => mi.IsGenericMethod && mi.GetGenericArguments().Length == genericParameterCount - && mi.GetParameters().Select(e => e.ParameterType).SequenceEqual( - parameterGenerator(mi.IsGenericMethod ? mi.GetGenericArguments() : []))); - } -} diff --git a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs index 45d1eaf997e..84a9b5f76e2 100644 --- a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs @@ -6263,88 +6263,80 @@ public virtual Task Byte_array_filter_by_length_parameter(bool async) [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Byte_array_with_max_possible_length_filter_by_index_of_literal(bool async) + public virtual Task Byte_array_IndexOf_with_literal(bool async) => AssertQuery( async, ss => ss.Set().Where(w => Array.IndexOf(w.Banner, (byte)1) == 1), - ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner, (byte)1) == 1) - ); + ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner, (byte)1) == 1)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Byte_array_with_max_possible_length_filter_by_index_of_parameter(bool async) + public virtual Task Byte_array_IndexOf_with_parameter(bool async) { byte b = 0; return AssertQuery( async, ss => ss.Set().Where(w => Array.IndexOf(w.Banner, b) == 0), - ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner, b) == 0) - ); + ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner, b) == 0)); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Byte_array_with_length_n_filter_by_index_of_literal(bool async) + public virtual Task Byte_array_with_length_IndexOf_with_literal(bool async) => AssertQuery( async, ss => ss.Set().Where(w => Array.IndexOf(w.Banner5, (byte)5) == 1), - ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner5, (byte)5) == 1) - ); + ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner5, (byte)5) == 1)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Byte_array_with_lenght_n_filter_by_index_of_parameter(bool async) + public virtual Task Byte_array_with_length_IndexOf_with_parameter(bool async) { byte b = 4; return AssertQuery( async, ss => ss.Set().Where(w => Array.IndexOf(w.Banner5, b) == 0), - ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner5, b) == 0) - ); + ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner5, b) == 0)); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(bool async) + public virtual Task Byte_array_IndexOf_with_startIndex_with_literals(bool async) => AssertQuery( async, ss => ss.Set().Where(w => Array.IndexOf(w.Banner, (byte)1, 1) == 1), - ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner, (byte)1, 1) == 1) - ); + ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner, (byte)1, 1) == 1)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(bool async) + public virtual Task Byte_array_IndexOf_with_startIndex_with_parameters(bool async) { byte b = 0; var startPos = 0; return AssertQuery( async, ss => ss.Set().Where(w => Array.IndexOf(w.Banner, b, startPos) == 0), - ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner, b, startPos) == 0) - ); + ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner, b, startPos) == 0)); } [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(bool async) + public virtual Task Byte_array_with_length_IndexOf_with_startIndex_with_literals(bool async) => AssertQuery( async, ss => ss.Set().Where(w => Array.IndexOf(w.Banner5, (byte)5, 1) == 1), - ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner5, (byte)5, 1) == 1) - ); + ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner5, (byte)5, 1) == 1)); [ConditionalTheory] [MemberData(nameof(IsAsyncData))] - public virtual Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(bool async) + public virtual Task Byte_array_with_length_IndexOf_with_startIndex_with_parameters(bool async) { byte b = 4; var startPos = 0; return AssertQuery( async, ss => ss.Set().Where(w => Array.IndexOf(w.Banner5, b, startPos) == 0), - ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner5, b, startPos) == 0) - ); + ss => ss.Set().Where(w => w.Banner != null && Array.IndexOf(w.Banner5, b, startPos) == 0)); } #endregion diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index f490b9a2adc..7464770c546 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -7678,9 +7678,9 @@ WHERE DATALENGTH([s].[Banner5]) = 5 #region Byte Array IndexOf Translation - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_literal(bool async) + public override async Task Byte_array_IndexOf_with_literal(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_literal(async); + await base.Byte_array_IndexOf_with_literal(async); AssertSql( """ @@ -7690,9 +7690,9 @@ WHERE CAST(CHARINDEX(0x01, [s].[Banner]) AS int) - 1 = 1 """); } - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_parameter(bool async) + public override async Task Byte_array_IndexOf_with_parameter(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_parameter(async); + await base.Byte_array_IndexOf_with_parameter(async); AssertSql( """ @@ -7704,9 +7704,9 @@ WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner]) AS int) - 1 = """); } - public override async Task Byte_array_with_length_n_filter_by_index_of_literal(bool async) + public override async Task Byte_array_with_length_IndexOf_with_literal(bool async) { - await base.Byte_array_with_length_n_filter_by_index_of_literal(async); + await base.Byte_array_with_length_IndexOf_with_literal(async); AssertSql( """ @@ -7716,9 +7716,9 @@ WHERE CHARINDEX(0x05, [s].[Banner5]) - 1 = 1 """); } - public override async Task Byte_array_with_lenght_n_filter_by_index_of_parameter(bool async) + public override async Task Byte_array_with_length_IndexOf_with_parameter(bool async) { - await base.Byte_array_with_lenght_n_filter_by_index_of_parameter(async); + await base.Byte_array_with_length_IndexOf_with_parameter(async); AssertSql( """ @@ -7730,9 +7730,9 @@ WHERE CHARINDEX(CAST(@__b_0 AS varbinary(5)), [s].[Banner5]) - 1 = 0 """); } - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(bool async) + public override async Task Byte_array_IndexOf_with_startIndex_with_literals(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(async); + await base.Byte_array_IndexOf_with_startIndex_with_literals(async); AssertSql( """ @@ -7742,9 +7742,9 @@ WHERE CAST(CHARINDEX(0x01, [s].[Banner], 2) AS int) - 1 = 1 """); } - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(bool async) + public override async Task Byte_array_IndexOf_with_startIndex_with_parameters(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(async); + await base.Byte_array_IndexOf_with_startIndex_with_parameters(async); AssertSql( """ @@ -7757,9 +7757,9 @@ WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner], @__startPos_1 """); } - public override async Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(bool async) + public override async Task Byte_array_with_length_IndexOf_with_startIndex_with_literals(bool async) { - await base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(async); + await base.Byte_array_with_length_IndexOf_with_startIndex_with_literals(async); AssertSql( """ @@ -7769,9 +7769,9 @@ WHERE CHARINDEX(0x05, [s].[Banner5], 2) - 1 = 1 """); } - public override async Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(bool async) + public override async Task Byte_array_with_length_IndexOf_with_startIndex_with_parameters(bool async) { - await base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(async); + await base.Byte_array_with_length_IndexOf_with_startIndex_with_parameters(async); AssertSql( """ diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs index bfc654dd4d2..a678fe55aca 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs @@ -10222,9 +10222,9 @@ WHERE DATALENGTH([s].[Banner5]) = 5 #region Byte Array IndexOf Translation - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_literal(bool async) + public override async Task Byte_array_IndexOf_with_literal(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_literal(async); + await base.Byte_array_IndexOf_with_literal(async); AssertSql( """ @@ -10234,9 +10234,9 @@ WHERE CAST(CHARINDEX(0x01, [s].[Banner]) AS int) - 1 = 1 """); } - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_parameter(bool async) + public override async Task Byte_array_IndexOf_with_parameter(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_parameter(async); + await base.Byte_array_IndexOf_with_parameter(async); AssertSql( """ @@ -10248,9 +10248,9 @@ WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner]) AS int) - 1 = """); } - public override async Task Byte_array_with_length_n_filter_by_index_of_literal(bool async) + public override async Task Byte_array_with_length_IndexOf_with_literal(bool async) { - await base.Byte_array_with_length_n_filter_by_index_of_literal(async); + await base.Byte_array_with_length_IndexOf_with_literal(async); AssertSql( """ @@ -10260,9 +10260,9 @@ WHERE CHARINDEX(0x05, [s].[Banner5]) - 1 = 1 """); } - public override async Task Byte_array_with_lenght_n_filter_by_index_of_parameter(bool async) + public override async Task Byte_array_with_length_IndexOf_with_parameter(bool async) { - await base.Byte_array_with_lenght_n_filter_by_index_of_parameter(async); + await base.Byte_array_with_length_IndexOf_with_parameter(async); AssertSql( """ @@ -10274,9 +10274,9 @@ WHERE CHARINDEX(CAST(@__b_0 AS varbinary(5)), [s].[Banner5]) - 1 = 0 """); } - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(bool async) + public override async Task Byte_array_IndexOf_with_startIndex_with_literals(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(async); + await base.Byte_array_IndexOf_with_startIndex_with_literals(async); AssertSql( """ @@ -10286,9 +10286,9 @@ WHERE CAST(CHARINDEX(0x01, [s].[Banner], 2) AS int) - 1 = 1 """); } - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(bool async) + public override async Task Byte_array_IndexOf_with_startIndex_with_parameters(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(async); + await base.Byte_array_IndexOf_with_startIndex_with_parameters(async); AssertSql( """ @@ -10301,9 +10301,9 @@ WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner], @__startPos_1 """); } - public override async Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(bool async) + public override async Task Byte_array_with_length_IndexOf_with_startIndex_with_literals(bool async) { - await base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(async); + await base.Byte_array_with_length_IndexOf_with_startIndex_with_literals(async); AssertSql( """ @@ -10313,9 +10313,9 @@ WHERE CHARINDEX(0x05, [s].[Banner5], 2) - 1 = 1 """); } - public override async Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(bool async) + public override async Task Byte_array_with_length_IndexOf_with_startIndex_with_parameters(bool async) { - await base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(async); + await base.Byte_array_with_length_IndexOf_with_startIndex_with_parameters(async); AssertSql( """ diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs index 59fe339674c..d2d16d78995 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs @@ -8688,9 +8688,9 @@ WHERE DATALENGTH([s].[Banner5]) = 5 #region Byte Array IndexOf Translation - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_literal(bool async) + public override async Task Byte_array_IndexOf_with_literal(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_literal(async); + await base.Byte_array_IndexOf_with_literal(async); AssertSql( """ @@ -8700,9 +8700,9 @@ WHERE CAST(CHARINDEX(0x01, [s].[Banner]) AS int) - 1 = 1 """); } - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_parameter(bool async) + public override async Task Byte_array_IndexOf_with_parameter(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_parameter(async); + await base.Byte_array_IndexOf_with_parameter(async); AssertSql( """ @@ -8714,9 +8714,9 @@ WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner]) AS int) - 1 = """); } - public override async Task Byte_array_with_length_n_filter_by_index_of_literal(bool async) + public override async Task Byte_array_with_length_IndexOf_with_literal(bool async) { - await base.Byte_array_with_length_n_filter_by_index_of_literal(async); + await base.Byte_array_with_length_IndexOf_with_literal(async); AssertSql( """ @@ -8726,9 +8726,9 @@ WHERE CHARINDEX(0x05, [s].[Banner5]) - 1 = 1 """); } - public override async Task Byte_array_with_lenght_n_filter_by_index_of_parameter(bool async) + public override async Task Byte_array_with_length_IndexOf_with_parameter(bool async) { - await base.Byte_array_with_lenght_n_filter_by_index_of_parameter(async); + await base.Byte_array_with_length_IndexOf_with_parameter(async); AssertSql( """ @@ -8740,9 +8740,9 @@ WHERE CHARINDEX(CAST(@__b_0 AS varbinary(5)), [s].[Banner5]) - 1 = 0 """); } - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(bool async) + public override async Task Byte_array_IndexOf_with_startIndex_with_literals(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(async); + await base.Byte_array_IndexOf_with_startIndex_with_literals(async); AssertSql( """ @@ -8752,9 +8752,9 @@ WHERE CAST(CHARINDEX(0x01, [s].[Banner], 2) AS int) - 1 = 1 """); } - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(bool async) + public override async Task Byte_array_IndexOf_with_startIndex_with_parameters(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(async); + await base.Byte_array_IndexOf_with_startIndex_with_parameters(async); AssertSql( """ @@ -8767,9 +8767,9 @@ WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner], @__startPos_1 """); } - public override async Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(bool async) + public override async Task Byte_array_with_length_IndexOf_with_startIndex_with_literals(bool async) { - await base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(async); + await base.Byte_array_with_length_IndexOf_with_startIndex_with_literals(async); AssertSql( """ @@ -8779,9 +8779,9 @@ WHERE CHARINDEX(0x05, [s].[Banner5], 2) - 1 = 1 """); } - public override async Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(bool async) + public override async Task Byte_array_with_length_IndexOf_with_startIndex_with_parameters(bool async) { - await base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(async); + await base.Byte_array_with_length_IndexOf_with_startIndex_with_parameters(async); AssertSql( """ diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs index 7f7d8789fc8..874a8c4e651 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs @@ -3264,9 +3264,9 @@ WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] #region Byte Array IndexOf Translation - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_literal(bool async) + public override async Task Byte_array_IndexOf_with_literal(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_literal(async); + await base.Byte_array_IndexOf_with_literal(async); AssertSql( """ @@ -3276,9 +3276,9 @@ WHERE CAST(CHARINDEX(0x01, [s].[Banner]) AS int) - 1 = 1 """); } - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_parameter(bool async) + public override async Task Byte_array_IndexOf_with_parameter(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_parameter(async); + await base.Byte_array_IndexOf_with_parameter(async); AssertSql( """ @@ -3290,9 +3290,9 @@ WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner]) AS int) - 1 = """); } - public override async Task Byte_array_with_length_n_filter_by_index_of_literal(bool async) + public override async Task Byte_array_with_length_IndexOf_with_literal(bool async) { - await base.Byte_array_with_length_n_filter_by_index_of_literal(async); + await base.Byte_array_with_length_IndexOf_with_literal(async); AssertSql( """ @@ -3302,9 +3302,9 @@ WHERE CHARINDEX(0x05, [s].[Banner5]) - 1 = 1 """); } - public override async Task Byte_array_with_lenght_n_filter_by_index_of_parameter(bool async) + public override async Task Byte_array_with_length_IndexOf_with_parameter(bool async) { - await base.Byte_array_with_lenght_n_filter_by_index_of_parameter(async); + await base.Byte_array_with_length_IndexOf_with_parameter(async); AssertSql( """ @@ -3316,9 +3316,9 @@ WHERE CHARINDEX(CAST(@__b_0 AS varbinary(5)), [s].[Banner5]) - 1 = 0 """); } - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(bool async) + public override async Task Byte_array_IndexOf_with_startIndex_with_literals(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(async); + await base.Byte_array_IndexOf_with_startIndex_with_literals(async); AssertSql( """ @@ -3328,9 +3328,9 @@ WHERE CAST(CHARINDEX(0x01, [s].[Banner], 2) AS int) - 1 = 1 """); } - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(bool async) + public override async Task Byte_array_IndexOf_with_startIndex_with_parameters(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(async); + await base.Byte_array_IndexOf_with_startIndex_with_parameters(async); AssertSql( """ @@ -3343,9 +3343,9 @@ WHERE CAST(CHARINDEX(CAST(@__b_0 AS varbinary(max)), [s].[Banner], @__startPos_1 """); } - public override async Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(bool async) + public override async Task Byte_array_with_length_IndexOf_with_startIndex_with_literals(bool async) { - await base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(async); + await base.Byte_array_with_length_IndexOf_with_startIndex_with_literals(async); AssertSql( """ @@ -3355,9 +3355,9 @@ WHERE CHARINDEX(0x05, [s].[Banner5], 2) - 1 = 1 """); } - public override async Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(bool async) + public override async Task Byte_array_with_length_IndexOf_with_startIndex_with_parameters(bool async) { - await base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(async); + await base.Byte_array_with_length_IndexOf_with_startIndex_with_parameters(async); AssertSql( """ diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs index a2422a2dfeb..bc0488fdcad 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs @@ -438,9 +438,9 @@ WHERE length("s"."Banner") = length(@__byteArrayParam) #region Byte Array IndexOf Translation - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_literal(bool async) + public override async Task Byte_array_IndexOf_with_literal(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_literal(async); + await base.Byte_array_IndexOf_with_literal(async); AssertSql( """ @@ -450,9 +450,9 @@ WHERE instr("s"."Banner", X'01') - 1 = 1 """); } - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_parameter(bool async) + public override async Task Byte_array_IndexOf_with_parameter(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_parameter(async); + await base.Byte_array_IndexOf_with_parameter(async); AssertSql( """ @@ -464,9 +464,9 @@ WHERE instr("s"."Banner", char(@__b_0)) - 1 = 0 """); } - public override async Task Byte_array_with_length_n_filter_by_index_of_literal(bool async) + public override async Task Byte_array_with_length_IndexOf_with_literal(bool async) { - await base.Byte_array_with_length_n_filter_by_index_of_literal(async); + await base.Byte_array_with_length_IndexOf_with_literal(async); AssertSql( """ @@ -476,9 +476,9 @@ WHERE instr("s"."Banner5", X'05') - 1 = 1 """); } - public override async Task Byte_array_with_lenght_n_filter_by_index_of_parameter(bool async) + public override async Task Byte_array_with_length_IndexOf_with_parameter(bool async) { - await base.Byte_array_with_lenght_n_filter_by_index_of_parameter(async); + await base.Byte_array_with_length_IndexOf_with_parameter(async); AssertSql( """ @@ -490,17 +490,17 @@ WHERE instr("s"."Banner5", char(@__b_0)) - 1 = 0 """); } - public override Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(bool async) - => AssertTranslationFailed(() => base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(async)); + public override Task Byte_array_IndexOf_with_startIndex_with_literals(bool async) + => AssertTranslationFailed(() => base.Byte_array_IndexOf_with_startIndex_with_literals(async)); - public override Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(bool async) - => AssertTranslationFailed(() => base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(async)); + public override Task Byte_array_IndexOf_with_startIndex_with_parameters(bool async) + => AssertTranslationFailed(() => base.Byte_array_IndexOf_with_startIndex_with_parameters(async)); - public override Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(bool async) - => AssertTranslationFailed(() => base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(async)); + public override Task Byte_array_with_length_IndexOf_with_startIndex_with_literals(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_length_IndexOf_with_startIndex_with_literals(async)); - public override Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(bool async) - => AssertTranslationFailed(() => base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(async)); + public override Task Byte_array_with_length_IndexOf_with_startIndex_with_parameters(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_length_IndexOf_with_startIndex_with_parameters(async)); #endregion diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/TPCGearsOfWarQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/TPCGearsOfWarQuerySqliteTest.cs index 75200b370b4..0bd60186262 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/TPCGearsOfWarQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/TPCGearsOfWarQuerySqliteTest.cs @@ -303,9 +303,9 @@ public override async Task Byte_array_filter_by_SequenceEqual(bool async) #region Byte Array IndexOf Translation - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_literal(bool async) + public override async Task Byte_array_IndexOf_with_literal(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_literal(async); + await base.Byte_array_IndexOf_with_literal(async); AssertSql( """ @@ -315,9 +315,9 @@ WHERE instr("s"."Banner", X'01') - 1 = 1 """); } - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_parameter(bool async) + public override async Task Byte_array_IndexOf_with_parameter(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_parameter(async); + await base.Byte_array_IndexOf_with_parameter(async); AssertSql( """ @@ -329,9 +329,9 @@ WHERE instr("s"."Banner", char(@__b_0)) - 1 = 0 """); } - public override async Task Byte_array_with_length_n_filter_by_index_of_literal(bool async) + public override async Task Byte_array_with_length_IndexOf_with_literal(bool async) { - await base.Byte_array_with_length_n_filter_by_index_of_literal(async); + await base.Byte_array_with_length_IndexOf_with_literal(async); AssertSql( """ @@ -341,9 +341,9 @@ WHERE instr("s"."Banner5", X'05') - 1 = 1 """); } - public override async Task Byte_array_with_lenght_n_filter_by_index_of_parameter(bool async) + public override async Task Byte_array_with_length_IndexOf_with_parameter(bool async) { - await base.Byte_array_with_lenght_n_filter_by_index_of_parameter(async); + await base.Byte_array_with_length_IndexOf_with_parameter(async); AssertSql( """ @@ -355,17 +355,17 @@ WHERE instr("s"."Banner5", char(@__b_0)) - 1 = 0 """); } - public override Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(bool async) - => AssertTranslationFailed(() => base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(async)); + public override Task Byte_array_IndexOf_with_startIndex_with_literals(bool async) + => AssertTranslationFailed(() => base.Byte_array_IndexOf_with_startIndex_with_literals(async)); - public override Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(bool async) - => AssertTranslationFailed(() => base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(async)); + public override Task Byte_array_IndexOf_with_startIndex_with_parameters(bool async) + => AssertTranslationFailed(() => base.Byte_array_IndexOf_with_startIndex_with_parameters(async)); - public override Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(bool async) - => AssertTranslationFailed(() => base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(async)); + public override Task Byte_array_with_length_IndexOf_with_startIndex_with_literals(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_length_IndexOf_with_startIndex_with_literals(async)); - public override Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(bool async) - => AssertTranslationFailed(() => base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(async)); + public override Task Byte_array_with_length_IndexOf_with_startIndex_with_parameters(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_length_IndexOf_with_startIndex_with_parameters(async)); #endregion diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/TPTGearsOfWarQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/TPTGearsOfWarQuerySqliteTest.cs index 641aee7f7db..0e3af50c775 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/TPTGearsOfWarQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/TPTGearsOfWarQuerySqliteTest.cs @@ -303,9 +303,9 @@ public override async Task Byte_array_filter_by_SequenceEqual(bool async) #region Byte Array IndexOf Translation - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_literal(bool async) + public override async Task Byte_array_IndexOf_with_literal(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_literal(async); + await base.Byte_array_IndexOf_with_literal(async); AssertSql( """ @@ -315,9 +315,9 @@ WHERE instr("s"."Banner", X'01') - 1 = 1 """); } - public override async Task Byte_array_with_max_possible_length_filter_by_index_of_parameter(bool async) + public override async Task Byte_array_IndexOf_with_parameter(bool async) { - await base.Byte_array_with_max_possible_length_filter_by_index_of_parameter(async); + await base.Byte_array_IndexOf_with_parameter(async); AssertSql( """ @@ -329,9 +329,9 @@ WHERE instr("s"."Banner", char(@__b_0)) - 1 = 0 """); } - public override async Task Byte_array_with_length_n_filter_by_index_of_literal(bool async) + public override async Task Byte_array_with_length_IndexOf_with_literal(bool async) { - await base.Byte_array_with_length_n_filter_by_index_of_literal(async); + await base.Byte_array_with_length_IndexOf_with_literal(async); AssertSql( """ @@ -341,9 +341,9 @@ WHERE instr("s"."Banner5", X'05') - 1 = 1 """); } - public override async Task Byte_array_with_lenght_n_filter_by_index_of_parameter(bool async) + public override async Task Byte_array_with_length_IndexOf_with_parameter(bool async) { - await base.Byte_array_with_lenght_n_filter_by_index_of_parameter(async); + await base.Byte_array_with_length_IndexOf_with_parameter(async); AssertSql( """ @@ -355,17 +355,17 @@ WHERE instr("s"."Banner5", char(@__b_0)) - 1 = 0 """); } - public override Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(bool async) - => AssertTranslationFailed(() => base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position(async)); + public override Task Byte_array_IndexOf_with_startIndex_with_literals(bool async) + => AssertTranslationFailed(() => base.Byte_array_IndexOf_with_startIndex_with_literals(async)); - public override Task Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(bool async) - => AssertTranslationFailed(() => base.Byte_array_with_max_possible_length_filter_by_index_of_with_starting_position_parameter(async)); + public override Task Byte_array_IndexOf_with_startIndex_with_parameters(bool async) + => AssertTranslationFailed(() => base.Byte_array_IndexOf_with_startIndex_with_parameters(async)); - public override Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(bool async) - => AssertTranslationFailed(() => base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_literal(async)); + public override Task Byte_array_with_length_IndexOf_with_startIndex_with_literals(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_length_IndexOf_with_startIndex_with_literals(async)); - public override Task Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(bool async) - => AssertTranslationFailed(() => base.Byte_array_with_length_n_filter_by_index_of_with_starting_position_parameter(async)); + public override Task Byte_array_with_length_IndexOf_with_startIndex_with_parameters(bool async) + => AssertTranslationFailed(() => base.Byte_array_with_length_IndexOf_with_startIndex_with_parameters(async)); #endregion