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

sql: fix typing of CASE statements to match Postgres #108387

Merged
merged 1 commit into from Aug 25, 2023

Conversation

rytaft
Copy link
Collaborator

@rytaft rytaft commented Aug 8, 2023

Fixes #102110
Informs #75103
Informs #108360

Release note (bug fix): Fixed the type resolution logic for CASE statements to more closely match Postgres' logic. In particular, we now adhere to rule 5 listed in https://www.postgresql.org/docs/current/typeconv-union-case.html, which requires that we select the first non-unknown input type as the candidate type, then consider each other non-unknown input type, left to right (CASE treats its ELSE clause (if any) as the "first" input, with the THEN clauses(s) considered after that). If the candidate type can be implicitly converted to the other type, but not vice-versa, select the other type as the new candidate type. Then continue considering the remaining inputs. If, at any stage of this process, a preferred type is selected, stop considering additional inputs (note that CockroachDB does not yet support the concept of a "preferred type").

@rytaft rytaft requested review from mgartner and msirek August 8, 2023 21:29
@rytaft rytaft requested review from a team as code owners August 8, 2023 21:29
@cockroach-teamcity
Copy link
Member

This change is Reviewable

Copy link
Contributor

@msirek msirek left a comment

Choose a reason for hiding this comment

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

Nice fix!

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @mgartner and @rytaft)


pkg/sql/sem/tree/type_check.go line 2639 at r1 (raw file):

			if typ := typedExpr.ResolvedType(); cast.ValidCast(firstValidType, typ, cast.ContextImplicit) {
				if !cast.ValidCast(typ, firstValidType, cast.ContextImplicit) {
					firstValidType = typ

Since typeCheckSameTypedExprs is called for expressions other than CASE, and adding this rule could change the ordering of expressions in return value typedExprs, could this cause unexpected behavior for non-CASE expressions?

Copy link
Collaborator Author

@rytaft rytaft left a comment

Choose a reason for hiding this comment

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

TFTR!

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @mgartner and @msirek)


pkg/sql/sem/tree/type_check.go line 2639 at r1 (raw file):

Previously, msirek (Mark Sirek) wrote…

Since typeCheckSameTypedExprs is called for expressions other than CASE, and adding this rule could change the ordering of expressions in return value typedExprs, could this cause unexpected behavior for non-CASE expressions?

Looking at the Postgres code, it seems like this logic is used widely for checking various expressions including COALESCE, IN (...), ARRAY, etc. I think this is what they mean by "UNION, CASE and related constructs". I'm inclined not to backport this change since as you mentioned it could affect a large number of expressions beyond CASE, but I do think it's correct for most if not all of the types that use this function.

Does that sound ok to you?

Copy link
Contributor

@msirek msirek left a comment

Choose a reason for hiding this comment

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

:lgtm:

Reviewed 3 of 3 files at r1, all commit messages.
Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @mgartner and @rytaft)


pkg/sql/sem/tree/type_check.go line 2639 at r1 (raw file):

Previously, rytaft (Rebecca Taft) wrote…

Looking at the Postgres code, it seems like this logic is used widely for checking various expressions including COALESCE, IN (...), ARRAY, etc. I think this is what they mean by "UNION, CASE and related constructs". I'm inclined not to backport this change since as you mentioned it could affect a large number of expressions beyond CASE, but I do think it's correct for most if not all of the types that use this function.

Does that sound ok to you?

OK, sounds good. It looks like there's a new test failure in TestLogic_tuple that needs to be figured out too.

Copy link
Collaborator Author

@rytaft rytaft left a comment

Choose a reason for hiding this comment

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

All test failures are fixed. PTAL since I had to make some larger changes to some tests.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (and 1 stale) (waiting on @mgartner and @msirek)


pkg/sql/sem/tree/type_check.go line 2639 at r1 (raw file):

Previously, msirek (Mark Sirek) wrote…

OK, sounds good. It looks like there's a new test failure in TestLogic_tuple that needs to be figured out too.

Thanks, this is fixed now.

Copy link
Contributor

@msirek msirek 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, and results seem to match Postgres overall.

Reviewed 9 of 9 files at r2, all commit messages.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (and 1 stale) (waiting on @mgartner and @rytaft)


pkg/sql/sem/tree/type_check.go line 2639 at r1 (raw file):

Previously, rytaft (Rebecca Taft) wrote…

Thanks, this is fixed now.

OK, looks good!


pkg/sql/opt/exec/execbuilder/testdata/scalar line 1292 at r2 (raw file):


query T
EXPLAIN (VERBOSE) SELECT * FROM t0 WHERE (CASE WHEN (t0.c0) IN (t0.c0) THEN ARRAY[] ELSE ARRAY[NULL] END) IS NULL

This case also returns ERROR: cannot determine type of empty array on Postgres. Not sure if this is covered by another issue, or if we care.

Fixes cockroachdb#102110
Informs cockroachdb#75103
Informs cockroachdb#108360

Release note (bug fix): Fixed the type resolution logic for CASE statements
to more closely match Postgres' logic. In particular, we now adhere to rule
5 listed in https://www.postgresql.org/docs/current/typeconv-union-case.html,
which requires that we select the first non-unknown input type as the candidate
type, then consider each other non-unknown input type, left to right (CASE
treats its ELSE clause (if any) as the "first" input, with the THEN clauses(s)
considered after that). If the candidate type can be implicitly converted to
the other type, but not vice-versa, select the other type as the new candidate
type. Then continue considering the remaining inputs. If, at any stage of this
process, a preferred type is selected, stop considering additional inputs (note
that CockroachDB does not yet support the concept of a "preferred type").
Copy link
Collaborator Author

@rytaft rytaft left a comment

Choose a reason for hiding this comment

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

Thanks for checking!

bors r+

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (and 1 stale) (waiting on @mgartner and @msirek)


pkg/sql/opt/exec/execbuilder/testdata/scalar line 1292 at r2 (raw file):

Previously, msirek (Mark Sirek) wrote…

This case also returns ERROR: cannot determine type of empty array on Postgres. Not sure if this is covered by another issue, or if we care.

Thanks for checking all of these! I added a TODO to note the difference. Not sure if an issue already exists, but doesn't really seem worth worrying about this case for now.

@craig
Copy link
Contributor

craig bot commented Aug 25, 2023

Build succeeded:

@craig craig bot merged commit 6f2d13f into cockroachdb:master Aug 25, 2023
7 of 8 checks passed
mgartner added a commit to mgartner/cockroach that referenced this pull request Aug 28, 2023
PR cockroachdb#108387 introduced new logic to type-checking that allows nested
expressions of a single expression to have different types in some cases
when the types can be implicitly casted to a common type. For example,
the expression `ARRAY[1::INT, 1::FLOAT8]` would have failed
type-checking but is not successfully typed as `[]FLOAT8`.

However, cockroachdb#108387 does not add an implicit cast to ensure that each
nested expression actually has that type during execution, which causes
internal errors in some cases. This commit add the necessary implicit
casts.

Fixes cockroachdb#109629

There is no release note because the bug is not present in any releases.

Release note: None
mgartner added a commit to mgartner/cockroach that referenced this pull request Aug 30, 2023
PR cockroachdb#108387 introduced new logic to type-checking that allows nested
expressions of a single expression to have different types in some cases
when the types can be implicitly casted to a common type. For example,
the expression `ARRAY[1::INT, 1::FLOAT8]` would have failed
type-checking but is not successfully typed as `[]FLOAT8`.

However, cockroachdb#108387 does not add an implicit cast to ensure that each
nested expression actually has that type during execution, which causes
internal errors in some cases. This commit add the necessary implicit
casts.

Fixes cockroachdb#109629

There is no release note because the bug is not present in any releases.

Release note: None
mgartner added a commit to mgartner/cockroach that referenced this pull request Aug 31, 2023
PR cockroachdb#108387 introduced new logic to type-checking that allows nested
expressions of a single expression to have different types in some cases
when the types can be implicitly casted to a common type. For example,
the expression `ARRAY[1::INT, 1::FLOAT8]` would have failed
type-checking but is not successfully typed as `[]FLOAT8`.

However, cockroachdb#108387 does not add an implicit cast to ensure that each
nested expression actually has that type during execution, which causes
internal errors in some cases. This commit add the necessary implicit
casts.

Fixes cockroachdb#109629

There is no release note because the bug is not present in any releases.

Release note: None
craig bot pushed a commit that referenced this pull request Aug 31, 2023
109635: sql: fix nested expression type-checking r=mgartner a=mgartner

PR #108387 introduced new logic to type-checking that allows nested
expressions of a single expression to have different types in some cases
when the types can be implicitly casted to a common type. For example,
the expression `ARRAY[1::INT, 1::FLOAT8]` would have failed
type-checking but is not successfully typed as `[]FLOAT8`.

However, #108387 does not add an implicit cast to ensure that each
nested expression actually has that type during execution, which causes
internal errors in some cases. This commit add the necessary implicit
casts.

Fixes #109629

There is no release note because the bug is not present in any releases.

Release note: None


109704: roachprod: use more recent ubuntu 20.04 images r=RaduBerinde a=RaduBerinde

Epic: none
Release note: None

Co-authored-by: Marcus Gartner <marcus@cockroachlabs.com>
Co-authored-by: Radu Berinde <radu@cockroachlabs.com>
msirek pushed a commit to msirek/cockroach that referenced this pull request Sep 10, 2023
Function typeCheckSameTypedExprs is updated by cockroachdb#108387 and cockroachdb#109635 to
apply implicit CASTs to the different expressions input to an array,
tuple, case expression or other similar expression, to coerce them all
to a common data type, instead of erroring out. This is not done,
however, if the data types of these expressions are not equivalent with
each other, causing some cases to error out.

The fix is to match Postgres behavior and apply the casts even for
non-equivalent types.

Informs: cockroachdb#109105

Release note (sql change): This patch modifies type checking of arrays,
tuples, and case statements to allow implicit casting of scalar
expressions referenced in these constructs to a common data type, even
for types in different type families, as long at the implicit cast is
legal.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Unexpected results of CASE and BETWEEN
3 participants