-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Contains translates to correlated query when the item is nullable #32574
Comments
Reopening to consider servicing. |
Fixes dotnet#32574 (cherry picked from commit 7b712f8)
Fixes dotnet#32574 (cherry picked from commit 7b712f8)
Fixes dotnet#32574 (cherry picked from commit 7b712f8)
The expressions can evaluate to different results in 3 valued logic https://dbfiddle.uk/Jt--BJyX but the
|
@asos-martinsmith yes, I'm aware of the 3-value logic behavior of IN and EXISTS. However, EXISTS allows customizing the predicate. For example, consider translating LINQ The way EF handles this at the moment, is to use EXISTS instead, and compensate for 3-value logic in the predicate; so instead of The fix in #32575 if for EF to do parameter preprocessing, for the case where Negation indeed introduces some further complications; you're welcome to take a look at #32575 which does this work, and I'm otherwise happy to continue exchanging around this! |
We usually translate Contains to an uncorrelated IN subquery, e.g.
WHERE x.Item IN (SELECT value FROM OPENJSON(@p))
. However, when the item is nullable, we translate to a correlated EXISTS subquery instead:WHERE EXISTS (SELECT value FROM OPENJSON(..) WHERE value = x.Item
.The problem is that during translation of primitive collections, we cannot examine parameter contents, and so we must assume that there are possible nulls in the collection (unless we're dealing with a non-nullable value). Later, in SqlNullabilityProcessor, when processing the InExpression we see that both sides (item and subquery) are nullable, meaning that we can't use SQL IN for that (impossible to distinguish between a NULL result that indicates that the item wasn't found, and a NULL result that indicates that NULL was found). As a result, we currently transform the IN to an EXISTS, to make sure results are accurate.
The fix here would be to look into the parameterized collection in SqlNullabilityProcessor (where we can access parameters), and rewrite it to remove any null values, compensating with an additional OR clause. Once nulls are cleared out, we can keep the uncorrelated IN translation, rather than switching to correlated EXISTS. Note that this would be the first time we rewrite parameters in the 2nd part of the query pipeline; it also means we can't cache the resulting SQL, since the parameter rewriting must happen again for each query.
(/cc @ajcvickers regarding value converters and null: since the query pipeline cares about nulls vs. non-nulls, if value converters support converting between nulls and non-nulls, that has to happen early, otherwise we'll get incorrect results)
Note that any other type of IN+subquery will continue to be translated as before, i.e. transforming IN to correlated EXISTS when both sides are nullable. This isn't a regression from previous releases.
The text was updated successfully, but these errors were encountered: