[release/6.0] Query: Convert single result subquery comparison to null to Any operation #27284
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Resolves #26744
A better fix for #18476
Initial fix for #18476 (in 6.0) assumed that whenever we have single result operation compared to null, it will only be true if the result of single result is default when sequence is empty. This was correct for the query in the issue tracker which had anonymous type projection.
Anonymous type is never null as long as there is data, it can be only null value when default is invoked i.e. empty sequence. Hence we added optimization for that but it didn't restrict to just anonymous type.
For entity type projection when entity is not nullable, the same logic holds true. This helped us translate queries which wouldn't work with entity equality due to composite key from a subquery. But optimization was incorrect for the result which can be null (nullable scalar or nullable entity) as an non-empty sequence can have first result to be null which can match.
The improved fix avoids doing the unrestricted optimization during preprocessing phase. Instead we moved the logic to translation phase where we can evaluate the shape of the projection coming out subquery. Now we only apply optimization for non-nullable entity and anonymous type. Scalar comparison will work by comparing to null and nullable entity will work if entity equality covers it. It will start throwing error if composite key though earlier version possibly generated wrong results for it.
Description
A faulty optimization in EF Core converts a subquery comparison to null to any operation making it sequence check. In case when the sequence can return null value as element, the optimization is incorrect.
Customer impact
Users running a query where this optimization would incorrectly kick in, will get incorrect results.
How found
Customer reported on 6.0
Regression
Yes. From 5.0 The regression was caused by faulty optimization added in 6.0 as enhancement.
Testing
There are existing test verifying the optimization (in correct scenario), Added additional tests for user scenario where optimization was incorrect. Some tests have different SQL now as optimization was incorrect but due to the data, it was still giving correct results.
Risk
Low risk. Optimization is applied accurately in the cases where it is correct. This has potential to break some queries though they are supposed to be giving incorrect results. Also added quirk to revert to earlier behavior.