Skip to content

Commit d9e73f6

Browse files
committed
Fix TPC equality check inside subquery predicate
Fixes #35118
1 parent 8935072 commit d9e73f6

File tree

4 files changed

+47
-19
lines changed

4 files changed

+47
-19
lines changed

src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Diagnostics.CodeAnalysis;
45
using System.Runtime.CompilerServices;
56
using Microsoft.EntityFrameworkCore.Metadata.Internal;
67
using Microsoft.EntityFrameworkCore.Query.Internal;
@@ -1573,7 +1574,7 @@ public void ApplyPredicate(SqlExpression sqlExpression)
15731574
Left: ColumnExpression leftColumn,
15741575
Right: SqlConstantExpression { Value: string s1 }
15751576
}
1576-
when GetTable(leftColumn) is TpcTablesExpression
1577+
when TryGetTable(leftColumn, out var table, out _) && table is TpcTablesExpression
15771578
{
15781579
DiscriminatorColumn: var discriminatorColumn,
15791580
DiscriminatorValues: var discriminatorValues
@@ -1596,7 +1597,7 @@ when GetTable(leftColumn) is TpcTablesExpression
15961597
Left: SqlConstantExpression { Value: string s2 },
15971598
Right: ColumnExpression rightColumn
15981599
}
1599-
when GetTable(rightColumn) is TpcTablesExpression
1600+
when TryGetTable(rightColumn, out var table, out _) && table is TpcTablesExpression
16001601
{
16011602
DiscriminatorColumn: var discriminatorColumn,
16021603
DiscriminatorValues: var discriminatorValues
@@ -1620,7 +1621,7 @@ when GetTable(rightColumn) is TpcTablesExpression
16201621
Item: ColumnExpression itemColumn,
16211622
Values: IReadOnlyList<SqlExpression> valueExpressions
16221623
}
1623-
when GetTable(itemColumn) is TpcTablesExpression
1624+
when TryGetTable(itemColumn, out var table, out _) && table is TpcTablesExpression
16241625
{
16251626
DiscriminatorColumn: var discriminatorColumn,
16261627
DiscriminatorValues: var discriminatorValues
@@ -2733,31 +2734,28 @@ public TableExpressionBase GetTable(ColumnExpression column)
27332734
/// <see cref="SelectExpression" /> based on its alias.
27342735
/// </summary>
27352736
public TableExpressionBase GetTable(ColumnExpression column, out int tableIndex)
2736-
{
2737-
for (var i = 0; i < _tables.Count; i++)
2738-
{
2739-
var table = _tables[i];
2740-
if (table.UnwrapJoin().Alias == column.TableAlias)
2741-
{
2742-
tableIndex = i;
2743-
return table;
2744-
}
2745-
}
2746-
2747-
throw new InvalidOperationException($"Table not found with alias '{column.TableAlias}'");
2748-
}
2737+
=> TryGetTable(column, out var table, out tableIndex)
2738+
? table
2739+
: throw new InvalidOperationException($"Table not found with alias '{column.TableAlias}'");
27492740

27502741
private bool ContainsReferencedTable(ColumnExpression column)
2742+
=> TryGetTable(column, out _, out _);
2743+
2744+
private bool TryGetTable(ColumnExpression column, [NotNullWhen(true)] out TableExpressionBase? table, out int tableIndex)
27512745
{
2752-
foreach (var table in Tables)
2746+
for (var i = 0; i < _tables.Count; i++)
27532747
{
2754-
var unwrappedTable = table.UnwrapJoin();
2755-
if (unwrappedTable.Alias == column.TableAlias)
2748+
var t = _tables[i];
2749+
if (t.UnwrapJoin().Alias == column.TableAlias)
27562750
{
2751+
table = t;
2752+
tableIndex = i;
27572753
return true;
27582754
}
27592755
}
27602756

2757+
table = null;
2758+
tableIndex = 0;
27612759
return false;
27622760
}
27632761

test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5317,6 +5317,14 @@ public override async Task Ternary_Null_StartsWith(bool async)
53175317
AssertSql();
53185318
}
53195319

5320+
public override async Task Column_access_inside_subquery_predicate(bool async)
5321+
{
5322+
// Uncorrelated subquery, not supported by Cosmos
5323+
await AssertTranslationFailed(() => base.Column_access_inside_subquery_predicate(async));
5324+
5325+
AssertSql();
5326+
}
5327+
53205328
private void AssertSql(params string[] expected)
53215329
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
53225330

test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5890,4 +5890,11 @@ public virtual Task Ternary_Null_StartsWith(bool async)
58905890
async,
58915891
ss => ss.Set<Order>().OrderBy(x => x.OrderID).Select(x => x == null ? null : x.OrderID + ""),
58925892
x => x.StartsWith("1"));
5893+
5894+
[ConditionalTheory] // #35118
5895+
[MemberData(nameof(IsAsyncData))]
5896+
public virtual Task Column_access_inside_subquery_predicate(bool async)
5897+
=> AssertQuery(
5898+
async,
5899+
ss => ss.Set<Customer>().Where(c => ss.Set<Order>().Where(o => c.CustomerID == "ALFKI").Any()));
58935900
}

test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7516,6 +7516,21 @@ ORDER BY [o].[OrderID]
75167516
""");
75177517
}
75187518

7519+
public override async Task Column_access_inside_subquery_predicate(bool async)
7520+
{
7521+
await base.Column_access_inside_subquery_predicate(async);
7522+
7523+
AssertSql(
7524+
"""
7525+
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
7526+
FROM [Customers] AS [c]
7527+
WHERE EXISTS (
7528+
SELECT 1
7529+
FROM [Orders] AS [o]
7530+
WHERE [c].[CustomerID] = N'ALFKI')
7531+
""");
7532+
}
7533+
75197534
private void AssertSql(params string[] expected)
75207535
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
75217536

0 commit comments

Comments
 (0)