Skip to content

Commit c54f51d

Browse files
authored
Process Coalesce-simplified Convert node properly in funcletizer (#35657)
Fixes #35656
1 parent 37ba291 commit c54f51d

File tree

7 files changed

+98
-2
lines changed

7 files changed

+98
-2
lines changed

Diff for: src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2179,8 +2179,8 @@ static Expression RemoveConvert(Expression expression)
21792179
}
21802180
}
21812181

2182-
private static Expression ConvertIfNeeded(Expression expression, Type type)
2183-
=> expression.Type == type ? expression : Convert(expression, type);
2182+
private Expression ConvertIfNeeded(Expression expression, Type type)
2183+
=> expression.Type == type ? expression : Visit(Convert(expression, type));
21842184

21852185
private bool IsGenerallyEvaluatable(Expression expression)
21862186
=> _evaluatableExpressionFilter.IsEvaluatableExpression(expression, _model)

Diff for: test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs

+17
Original file line numberDiff line numberDiff line change
@@ -6013,6 +6013,23 @@ public virtual Task Constant_enum_with_same_underlying_value_as_previously_param
60136013
// .Where(w => w.SynergyWith != null && types.Contains(w.SynergyWith.AmmunitionType)));
60146014
// }
60156015

6016+
[ConditionalTheory] // #35656
6017+
[MemberData(nameof(IsAsyncData))]
6018+
public virtual Task Coalesce_with_non_root_evaluatable_Convert(bool async)
6019+
{
6020+
MilitaryRank? rank = MilitaryRank.Private;
6021+
6022+
// The coalesce is simplified away in the funcletizer (since rank is non-null), but a Convert node is added
6023+
// to convert from MilitaryRank? (the type of rank) to the type of the coalesce expression (non-nullable
6024+
// MilitaryRank).
6025+
// This resulting Convert node isn't evaluatable as root (enum convert), and so the NotEvaluatableAsRootHandler
6026+
// is invoked.
6027+
return AssertQuery(
6028+
async,
6029+
// ReSharper disable once ConstantNullCoalescingCondition
6030+
ss => ss.Set<Gear>().Where(g => (rank ?? g.Rank) == g.Rank));
6031+
}
6032+
60166033
[ConditionalTheory]
60176034
[MemberData(nameof(IsAsyncData))]
60186035
public virtual async Task Client_eval_followed_by_aggregate_operation(bool async)

Diff for: test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs

+14
Original file line numberDiff line numberDiff line change
@@ -7381,6 +7381,20 @@ ORDER BY [g].[Nickname]
73817381
// """);
73827382
// }
73837383

7384+
public override async Task Coalesce_with_non_root_evaluatable_Convert(bool async)
7385+
{
7386+
await base.Coalesce_with_non_root_evaluatable_Convert(async);
7387+
7388+
AssertSql(
7389+
"""
7390+
@rank='1' (Nullable = true)
7391+
7392+
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank]
7393+
FROM [Gears] AS [g]
7394+
WHERE @rank = [g].[Rank]
7395+
""");
7396+
}
7397+
73847398
[ConditionalTheory]
73857399
[MemberData(nameof(IsAsyncData))]
73867400
public async Task DataLength_function_for_string_parameter(bool async)

Diff for: test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs

+20
Original file line numberDiff line numberDiff line change
@@ -9913,6 +9913,26 @@ ORDER BY [u].[Nickname]
99139913
// """);
99149914
// }
99159915

9916+
public override async Task Coalesce_with_non_root_evaluatable_Convert(bool async)
9917+
{
9918+
await base.Coalesce_with_non_root_evaluatable_Convert(async);
9919+
9920+
AssertSql(
9921+
"""
9922+
@rank='1' (Nullable = true)
9923+
9924+
SELECT [u].[Nickname], [u].[SquadId], [u].[AssignedCityName], [u].[CityOfBirthName], [u].[FullName], [u].[HasSoulPatch], [u].[LeaderNickname], [u].[LeaderSquadId], [u].[Rank], [u].[Discriminator]
9925+
FROM (
9926+
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], N'Gear' AS [Discriminator]
9927+
FROM [Gears] AS [g]
9928+
UNION ALL
9929+
SELECT [o].[Nickname], [o].[SquadId], [o].[AssignedCityName], [o].[CityOfBirthName], [o].[FullName], [o].[HasSoulPatch], [o].[LeaderNickname], [o].[LeaderSquadId], [o].[Rank], N'Officer' AS [Discriminator]
9930+
FROM [Officers] AS [o]
9931+
) AS [u]
9932+
WHERE @rank = [u].[Rank]
9933+
""");
9934+
}
9935+
99169936
[ConditionalTheory]
99179937
[MemberData(nameof(IsAsyncData))]
99189938
public async Task DataLength_function_for_string_parameter(bool async)

Diff for: test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs

+17
Original file line numberDiff line numberDiff line change
@@ -8376,6 +8376,23 @@ ORDER BY [g].[Nickname]
83768376
// """);
83778377
// }
83788378

8379+
public override async Task Coalesce_with_non_root_evaluatable_Convert(bool async)
8380+
{
8381+
await base.Coalesce_with_non_root_evaluatable_Convert(async);
8382+
8383+
AssertSql(
8384+
"""
8385+
@rank='1' (Nullable = true)
8386+
8387+
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], CASE
8388+
WHEN [o].[Nickname] IS NOT NULL THEN N'Officer'
8389+
END AS [Discriminator]
8390+
FROM [Gears] AS [g]
8391+
LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId]
8392+
WHERE @rank = [g].[Rank]
8393+
""");
8394+
}
8395+
83798396
[ConditionalTheory]
83808397
[MemberData(nameof(IsAsyncData))]
83818398
public async Task DataLength_function_for_string_parameter(bool async)

Diff for: test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs

+14
Original file line numberDiff line numberDiff line change
@@ -6092,6 +6092,20 @@ ORDER BY [g].[Nickname]
60926092
""");
60936093
}
60946094

6095+
public override async Task Coalesce_with_non_root_evaluatable_Convert(bool async)
6096+
{
6097+
await base.Coalesce_with_non_root_evaluatable_Convert(async);
6098+
6099+
AssertSql(
6100+
"""
6101+
@rank='1' (Nullable = true)
6102+
6103+
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[PeriodEnd], [g].[PeriodStart], [g].[Rank]
6104+
FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g]
6105+
WHERE @rank = [g].[Rank]
6106+
""");
6107+
}
6108+
60956109
public override async Task Comparison_with_value_converted_subclass(bool async)
60966110
{
60976111
await base.Comparison_with_value_converted_subclass(async);

Diff for: test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs

+14
Original file line numberDiff line numberDiff line change
@@ -5454,6 +5454,20 @@ LIMIT @p
54545454
""");
54555455
}
54565456

5457+
public override async Task Coalesce_with_non_root_evaluatable_Convert(bool async)
5458+
{
5459+
await base.Coalesce_with_non_root_evaluatable_Convert(async);
5460+
5461+
AssertSql(
5462+
"""
5463+
@rank='1' (Nullable = true)
5464+
5465+
SELECT "g"."Nickname", "g"."SquadId", "g"."AssignedCityName", "g"."CityOfBirthName", "g"."Discriminator", "g"."FullName", "g"."HasSoulPatch", "g"."LeaderNickname", "g"."LeaderSquadId", "g"."Rank"
5466+
FROM "Gears" AS "g"
5467+
WHERE @rank = "g"."Rank"
5468+
""");
5469+
}
5470+
54575471
public override async Task Correlated_collections_with_Take(bool async)
54585472
{
54595473
await base.Correlated_collections_with_Take(async);

0 commit comments

Comments
 (0)