Skip to content
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

Merged
merged 6 commits into from
Jun 3, 2024
Merged

Conversation

ranma42
Copy link
Contributor

@ranma42 ranma42 commented Jun 1, 2024

The CASE op WHEN ... expression was incorrectly optimized as if it were a CASE WHEN expression if the test expressions contained a TRUE value.

This also makes it possible to use the CASE op WHEN expression to avoid duplicating some subexpressions in the translation of the bool to string conversion.

Fixes #33867.

@roji roji requested a review from maumar June 2, 2024 16:26
@maumar maumar self-assigned this Jun 3, 2024
Comment on lines 84 to 93
return _sqlExpressionFactory.Case(
instance,
new[]
{
new CaseWhenClause(
_sqlExpressionFactory.Equal(instance, _sqlExpressionFactory.Constant(false)),
_sqlExpressionFactory.Constant(false),
_sqlExpressionFactory.Constant(false.ToString())),
new CaseWhenClause(
_sqlExpressionFactory.Equal(instance, _sqlExpressionFactory.Constant(true)),
_sqlExpressionFactory.Constant(true),
_sqlExpressionFactory.Constant(true.ToString()))
Copy link
Contributor Author

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) 🚀

Copy link
Member

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.

Copy link
Contributor

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

@maumar maumar merged commit ed6213d into dotnet:main Jun 3, 2024
7 checks passed
@maumar
Copy link
Contributor

maumar commented Jun 3, 2024

Thanks @ranma42 - great stuff as always!

b => b.HasTranslation(args => new CaseExpression(
operand: args[0],
[
new CaseWhenClause(new SqlConstantExpression(true, typeMapping: BoolTypeMapping.Default), args[1]),
Copy link
Member

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ouch, sorry; is there a simple way to make it more portable?

Copy link
Member

Choose a reason for hiding this comment

The 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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Invalid optimization of CASE op WHEN expressions
4 participants