-
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
SQL Server: Use XOR to translate some NOT expressions #34080
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a really nice idea @ranma42!
@@ -374,6 +374,18 @@ protected override Expression VisitSqlUnary(SqlUnaryExpression sqlUnaryExpressio | |||
case ExpressionType.Not | |||
when sqlUnaryExpression.Type == typeof(bool): | |||
{ | |||
// when possible, avoid converting to/from predicate form | |||
if (!_isSearchCondition && !(sqlUnaryExpression.Operand is ExistsExpression or InExpression or LikeExpression)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
if (!_isSearchCondition && !(sqlUnaryExpression.Operand is ExistsExpression or InExpression or LikeExpression)) | |
if (!_isSearchCondition && sqlUnaryExpression.Operand is not (ExistsExpression or InExpression or LikeExpression))) |
9b102f7
to
83d10f6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Si funciona adelanet
@ranma42 consider adding a case with nullable bool in projection, something like: [ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Select_inverted_nullable_boolean(bool async)
=> AssertQuery(
async,
ss => ss.Set<CogTag>().Select(w => new { w.Id, Manual = (bool?)!w.Gear.HasSoulPatch }),
ss => ss.Set<CogTag>().Select(w => new { w.Id, Manual = (bool?)(w.Gear == null ? null : !w.Gear.HasSoulPatch) }),
elementSorter: e => e.Id); this actually returns different results with XOR translation when HasSoulPatch (when Gear is null which causes HasSoulPatch to be null, we used to return false and now we return null). I would argue the new translation is the correct one (and on top of consistent with other providers that don't use search condition transformation). Basically it's the case pointed out in #34001, so maybe link this issue as a fix for 34001? |
Hmm now that I think of it, 34001 probably covers other cases not fixed by this,
still produces
and returns true for the null value of FullName. So we should keep #34001 open, until we have a proper fix (needs nullability information flow into search condition?) But I think we should track this change somehow, for the purpose of accurately cataloguing all the breaking changes we do in this space. Thoughts? @roji @ranma42 |
@maumar You are right, I did not think about #34001 when developing this change, but indeed it fixes this for some simple cases (basically a As you noticed, it does not fix it for generic |
83d10f6
to
8ee8dd4
Compare
@maumar I added a test similar to the one yup proposed; the main difference is that it operates directly on a
|
public virtual Task Select_inverted_nullable_boolean(bool async) | ||
=> AssertQuery( | ||
async, | ||
ss => ss.Set<LocustHorde>().Select(w => new { w.Id, Manual = !w.Eradicated }), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Alive = !w.Eradicated
When neither the parent expression nor the inner one is a predicate, translate to: ```sql x ^ CAST(1 AS bit) ``` instead of ```sql CASE WHEN x = CAST(0 AS bit) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END ``` Contributes to dotnet#34001 for simple cases (NOT of BIT expressions).
8ee8dd4
to
19c865e
Compare
thanks a lot again @ranma42 ! Added a breaking-change label so that we don't forget to document this. (although it's more like a bug fix rather than a break, really :) ) |
agreed; ideally this should only be a minor translation improvement, but since part of the translation is currently broken ( |
Since #34080 the SqlServer provider uses XOR to avoid converting to/from predicates when negating BIT expressions. It is actually possible to simply use ~ on BIT values and this changeset implements this. Fixes #34213 * Add minimal support for `ExpressionType.OnesComplement` It is currently only supported in the final part of SqlServer translation pipeline. * Use `~` for negating boolean values Instead of `x ^ 1`, use the `~x` expression when translating boolean values in SqlServer.
When neither the parent expression nor the inner one is a predicate, translate to:
instead of
Contributes to #34001 for simple cases (
NOT
ofBIT
expressions).