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: cast derived to proposed types in WMR CTEs #23658

Merged
merged 2 commits into from
Dec 5, 2023

Conversation

sploiselle
Copy link
Contributor

The code on main prevented you from using numeric values with different scales interchangeably, though SQL supports the operation.

cc @frankmcsherry

Motivation

This PR fixes a recognized bug. Slack

Checklist

  • This PR has adequate test coverage / QA involvement has been duly considered.
  • This PR has an associated up-to-date design doc, is a design doc (template), or is sufficiently small to not require a design.
  • If this PR evolves an existing $T ⇔ Proto$T mapping (possibly in a backwards-incompatible way), then it is tagged with a T-proto label.
  • If this PR will require changes to cloud orchestration or tests, there is a companion cloud PR to account for those changes that is tagged with the release-blocker label (example).
  • This PR includes the following user-facing behavior changes:
    • Improve type coercion in WITH MUTUALLY RECURSIVE common table expressions. For example, you can now return NUMERIC values of arbitrary scales (e.g. NUMERIC(38,2) for columns defined as NUMERIC; previously, this would error because NUMERIC has no scale applied and NUMERIC(38,2) does.

@sploiselle sploiselle requested a review from a team as a code owner December 4, 2023 19:24
@sploiselle sploiselle requested review from a team and jkosh44 December 4, 2023 19:24
Copy link
Contributor

@benesch benesch left a comment

Choose a reason for hiding this comment

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

This is impressive and fast work, @sploiselle—thank you so much! 🙇🏽

Someone else from surfaces should take a deeper look, but I read through the design and implementation in medium detail and it all checked out for me.

## Solution Proposal

We can cast the derived `RelationExpr`'s output types to match those that the
user proposed in their statement using `CastContext::Assignment`.
Copy link
Contributor

Choose a reason for hiding this comment

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

👍🏽👍🏽👍🏽

casting `numeric(38,10)` to `numeric(38,2)` (such as adding two values of these
types) will produce `numeric(38,10)`––there is no way of performing the
truncation expressed by the typmod to the higher-scaled value. Because of this,
I don't think the implicit context is appropriate to use when casting the
Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed.

return any `numeric` type irrespective of its scale, e.g. `numeric(38,0)`,
`numeric(38,2)`.

This might be the "easiest" to implement, but introduces a type of
Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed.

WITH MUTUALLY RECURSIVE
foo (a int, b int) AS (SELECT 1 UNION SELECT a FROM bar),
bar (a int) as (SELECT a FROM foo)
SELECT a FROM foo, bar;

## Test with more columns than declared
statement error did not match inferred type
statement error db error: ERROR: WITH MUTUALLY RECURSIVE query "foo" declared types \(integer, integer\), but query returns types \(integer, integer, integer\)
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this show typmods properly? I know the whole inspiration behind this work is that numeric typmods are now automatically cast, but I'm curious whether providing an integer when, say, a numeric(1, 2) is required properly renders the numeric(1, 2).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don't include the typmod, which is a feature/limitation of humanize_scalar_type––it only refers to the type objects. With the assignment-type casts in place, this makes sense because the errors have to be more dramatic than the typmods being mismatched (i.e. you gave us text and we needed a number). So including the typmod won't give folks meaningful context to fix the problem.

});

if !all_keys {
return err(proposed_typ, derived_typ);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this was pre-existing, but if these don't match, the error message will talk only about the scalar types when in fact it is a key mismatch, no?

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 was actually impossible to trigger because WMR CTEs don't support keys. Converted the existence of any key into an error so that if we support it, we'll have to fix this error (assuming we write a test 😄)

.zip(proposed_typ.column_types.iter())
{
if derived_col.nullable && !proposed_col.nullable {
return err(proposed_typ, derived_typ);
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto... do we properly render errors given nullability mismatches?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ditto above but we don't support NOT NULL in the CTE column definitions

We checked that the derived and proposed RelationTypes in WMR CTEs
had compatible definitions for NOT NULL columns and keys. However,
the proposed column types cannot contain the NOT NULL constraint,
nor can we express keys.

Convert the potentially confusing errors we returned previously
to internal errors that should surface in testing when these
features get added.
@sploiselle sploiselle merged commit d65b150 into MaterializeInc:main Dec 5, 2023
@sploiselle sploiselle deleted the wmr-cte-type-casts branch December 5, 2023 16:15
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.

3 participants