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: do not cast enum to text within min/max #4453

Merged
merged 5 commits into from
Nov 27, 2023
Merged

Conversation

Weakky
Copy link
Contributor

@Weakky Weakky commented Nov 15, 2023

Overview

fixes prisma/prisma#21789

Changes text casting on enums from:

SELECT MAX(enum_col::text), MIN(enum_col::text) FROM "Table"

to

SELECT MAX(enum_col)::text, MIN(enum_col)::text FROM "Table"

So that the behavior of min/max on enums remains unaltered. sum/avg/count remain unchanged because we don't allow these aggregations on enums.

@Weakky Weakky requested a review from a team as a code owner November 15, 2023 16:29
@Weakky Weakky requested review from miguelff and jkomyno and removed request for a team November 15, 2023 16:29
Copy link

codspeed-hq bot commented Nov 15, 2023

CodSpeed Performance Report

Merging #4453 will not alter performance

Comparing fix/enum-min-max-casting (8496150) with main (e08be2e)

Summary

✅ 11 untouched benchmarks

@Weakky Weakky added this to the 5.7.0 milestone Nov 15, 2023
@Weakky Weakky marked this pull request as draft November 16, 2023 09:47
@Weakky Weakky self-assigned this Nov 16, 2023
let select = columns
.map(|c| c.set_is_selected(true))
.fold(select, |acc, col| acc.column(col));
let select = columns.fold(select, |acc, col| acc.column(col));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

get_records is no longer responsible for setting the hacky is_selected field, the caller is

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 makes it possible in aggregate and group_by to not mark columns of the sub-select as selected and thus not cast them.

Here's an example:

SELECT
  MAX(col) -- mark as selected
FROM (
  SELECT col FROM "Table" -- not mark as selected
) as "sub"

Comment on lines +204 to 207
select.value(min(Column::from(next_field.db_name().to_owned())
.set_is_enum(next_field.type_identifier().is_enum())
.set_is_selected(true)))
}),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These outer columns (see comment above) are now set as enum (if they are) and selected

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for these clarifying comments

Comment on lines +637 to +649
fn visit_min(&mut self, min: Minimum<'a>) -> visitor::Result {
// If the inner column is a selected enum, then we cast the result of MIN(enum)::text instead of casting the inner enum column, which changes the behavior of MIN.
let should_cast = min.column.is_enum && min.column.is_selected;

self.write("MIN")?;
self.surround_with("(", ")", |ref mut s| s.visit_column(min.column.set_is_selected(false)))?;

if should_cast {
self.write("::text")?;
}

Ok(())
}
Copy link
Contributor Author

@Weakky Weakky Nov 16, 2023

Choose a reason for hiding this comment

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

We use, again, is_enum and is_selected to only cast enum columns to ::text when they're seleted. We need a custom implementation now to perform the cast on the function itself rather than the result.

@Weakky Weakky marked this pull request as ready for review November 16, 2023 14:56
Copy link
Contributor

@miguelff miguelff left a comment

Choose a reason for hiding this comment

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

Looks good. Thanks for the inline comments 🥇

@Oreilles
Copy link
Contributor

Just wondering, wouldn't the initial issue also affect the operator visitors visit_greater_than, visit_lower_than etc ? If the enum values are always being casted to text, then those comparison might also return unexpected results just like min and max did.

@Weakky
Copy link
Contributor Author

Weakky commented Nov 24, 2023

Just wondering, wouldn't the initial issue also affect the operator visitors visit_greater_than, visit_lower_than etc ? If the enum values are always being casted to text, then those comparison might also return unexpected results just like min and max did.

Hey @Oreilles, no, because we currently don't allow selecting columns with these functions. Only min/max/sum/avg are available through aggregateX and groupByX, and enums can't currently be summed or averaged.

@Weakky Weakky merged commit 0a59e97 into main Nov 27, 2023
66 of 67 checks passed
@Weakky Weakky deleted the fix/enum-min-max-casting branch November 27, 2023 14:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Side effect of casting enums to text on max aggregates
4 participants