-
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
Fix optimization of CASE op WHEN
#33869
Changes from 3 commits
5b6c3f7
59e1b50
f2bcee5
0064d0c
9785ef5
a656e25
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -129,11 +129,28 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con | |
new CaseWhenClause(args[4], args[5]), | ||
])) | ||
); | ||
|
||
modelBuilder.HasDbFunction( | ||
typeof(NullSemanticsQueryFixtureBase).GetMethod(nameof(BoolSwitch)), | ||
b => b.HasTranslation(args => new CaseExpression( | ||
operand: args[0], | ||
[ | ||
new CaseWhenClause(new SqlConstantExpression(true, typeMapping: BoolTypeMapping.Default), args[1]), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ranma42 while bringing the PG provider up to date, this fails because BoolTypeMapping doesn't work there - its literal representation is 1/0, whereas PG has a true boolean type with TRUE/FALSE as its literals. It's no big deal - I'm overriding the definition to use NpgsqlBoolTypeMapping. If anything, this shows the shortcomings of our current HasTranslation API; users shouldn't need to manually deal with type mappings like this, etc. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ouch, sorry; is there a simple way to make it more portable? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can always expose some overridable method for providers to construct their boolean type mapping, but honestly it isn't worth it... They can just override the function definition (as I've done). |
||
new CaseWhenClause(new SqlConstantExpression(false, typeMapping: BoolTypeMapping.Default), args[2]), | ||
])) | ||
); | ||
} | ||
|
||
public static int? Cases(bool c1, int v1, bool c2, int v2, bool c3, int v3) => | ||
c1 ? v1 : | ||
c2 ? v2 : | ||
c3 ? v3 : | ||
null; | ||
|
||
public static int BoolSwitch(bool x, int whenTrue, int whenFalse) => | ||
x switch | ||
{ | ||
true => whenTrue, | ||
false => whenFalse, | ||
}; | ||
} |
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.
this is the same approach recommended by @roji in #33706 (comment) 🚀
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.
Will let @maumar review/approve but this looks great... I remember this form of CASE/WHEN (with an operand) was introduced a bit later back in the day, I don't think we were aware of it originally; so I'm not surprised we have the less efficient other variant in various places - may be worth doing a pass over the code base for those.
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.
I will do the full sweep of our code, but that can be done independently of this PR