Skip to content

Commit

Permalink
Fix to #15778 - Query: null semantics visitor incorrectly classifies …
Browse files Browse the repository at this point in the history
…subquery returning single scalar value as non-nullable

Problem was that when we compared scalar subquery to null, we would assume the subquery is never null so we would never return any results. Scalar subqueries can be null when using entities.Where(e => false).Select(e => e.Name).FirstOrDefault() pattern.

Fix is to always assume SubSelectExpression is nullable.
  • Loading branch information
maumar committed May 24, 2019
1 parent 10e553a commit ca37ebe
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ protected override Expression VisitExtension(Expression extensionExpression)
case LeftJoinExpression leftJoinExpression:
return VisitLeftJoinExpression(leftJoinExpression);

case SubSelectExpression subSelectExpression:
var result = base.VisitExtension(subSelectExpression);
_isNullable = true;

return result;

default:
return base.VisitExtension(extensionExpression);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6256,7 +6256,7 @@ orderby l4.Id
}
}

[ConditionalTheory]
[ConditionalTheory(Skip = "issue #15798")]
[MemberData(nameof(IsAsyncData))]
public virtual Task Member_pushdown_with_multiple_collections(bool isAsync)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4598,7 +4598,7 @@ public override void Member_pushdown_chain_3_levels_deep()
AssertSql(
@"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id]
FROM [LevelOne] AS [l]
WHERE (
WHERE ((
SELECT TOP(1) (
SELECT TOP(1) (
SELECT TOP(1) [l0].[Name]
Expand All @@ -4609,10 +4609,21 @@ FROM [LevelThree] AS [l1]
WHERE [l1].[Level2_Required_Id] = [l2].[Id]
ORDER BY [l1].[Id])
FROM [LevelTwo] AS [l2]
WHERE [l2].[Level1_Optional_Id] = [l].[Id]
ORDER BY [l2].[Id]) <> N'Foo'
WHERE ([l2].[Level1_Optional_Id] = [l].[Id]) AND [l2].[Level1_Optional_Id] IS NOT NULL
ORDER BY [l2].[Id]) <> N'Foo') OR (
SELECT TOP(1) (
SELECT TOP(1) (
SELECT TOP(1) [l0].[Name]
FROM [LevelFour] AS [l0]
WHERE [l0].[Level3_Required_Id] = [l1].[Id]
ORDER BY [l0].[Id])
FROM [LevelThree] AS [l1]
WHERE [l1].[Level2_Required_Id] = [l2].[Id]
ORDER BY [l1].[Id])
FROM [LevelTwo] AS [l2]
WHERE ([l2].[Level1_Optional_Id] = [l].[Id]) AND [l2].[Level1_Optional_Id] IS NOT NULL
ORDER BY [l2].[Id]) IS NULL
ORDER BY [l].[Id]");

}

public override void Member_pushdown_with_collection_navigation_in_the_middle()
Expand All @@ -4628,7 +4639,7 @@ FROM [LevelFour] AS [l]
WHERE [l].[Level3_Required_Id] = [l0].[Id]
ORDER BY [l].[Id])
FROM [LevelThree] AS [l0]
WHERE [l1].[Id] = [l0].[OneToMany_Optional_Inverse3Id])
WHERE ([l1].[Id] = [l0].[OneToMany_Optional_Inverse3Id]) AND [l0].[OneToMany_Optional_Inverse3Id] IS NOT NULL)
FROM [LevelTwo] AS [l1]
WHERE [l1].[Level1_Required_Id] = [l2].[Id]
ORDER BY [l1].[Id])
Expand All @@ -4641,16 +4652,7 @@ public override async Task Member_pushdown_with_multiple_collections(bool isAsyn
await base.Member_pushdown_with_multiple_collections(isAsync);

AssertSql(
@"SELECT (
SELECT TOP(1) [l].[Name]
FROM [LevelThree] AS [l]
WHERE [l].[OneToMany_Optional_Inverse3Id] = (
SELECT TOP(1) [l0].[Id]
FROM [LevelTwo] AS [l0]
WHERE [l1].[Id] = [l0].[OneToMany_Optional_Inverse2Id]
ORDER BY [l0].[Id])
ORDER BY [l].[Id])
FROM [LevelOne] AS [l1]");
@"");
}

private void AssertSql(params string[] expected)
Expand Down

0 comments on commit ca37ebe

Please sign in to comment.