-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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: Allow DEFAULT/ON UPDATE types that can be assignment-cast #81071
Conversation
I noticed this particular solution causes us to support use cases that postgres does not. Not sure if we want to disallow these cases. |
fccdc69
to
017cc36
Compare
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.
Great start!
pkg/sql/catalog/tabledesc/table.go
Outdated
return nil, err | ||
// Check if the default expression type can be assignment-cast into the | ||
// column type. If it can allow the default and column type to differ. | ||
ret.DefaultExpr, innerErr = d.DefaultExpr.Expr.TypeCheck(ctx, semaCtx, types.Any) |
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.
schemaexpr.SanitizeVarFreeExpr
above could return an error for reasons other than the expression not matching the column type. For example, it could fail if the expression contains references to other columns. We only want to check if the default expression type can be assignment-cast into the column type if schemaexpr.SanitizeVarFreeExpr
fails during type-checking. Unfortunately, this isn't easy to do from outside schemaexpr.SanitizeVarFreeExpr
. One option is to modify schemaexpr.SanitizeVarFreeExpr
to add a new argument, allowAssignmentCast bool
and move his assignment-cast logic into the function directly where type-checking fails.
I think you could add a test case for this too, like:
CREATE TABLE fail_assn_cast (
a BOOL,
b STRING DEFAULT a
)
@@ -1401,3 +1401,28 @@ select CASE WHEN false THEN 1::REGTYPE ELSE 2::REGNAMESPACE END; | |||
select CASE WHEN false THEN 1::REGTYPE ELSE 2::REGPROC END; | |||
select CASE WHEN false THEN 1::REGTYPE ELSE 2::REGPROCEDURE END; | |||
select CASE WHEN false THEN 1::REGTYPE ELSE 2::REGROLE END; | |||
|
|||
|
|||
# Test that default/on update expression differing from column type |
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.
nit: sentence seems incomplete
# Test that default/on update expression differing from column type | ||
statement ok | ||
CREATE TABLE def_assn_cast ( | ||
a INT4 DEFAULT 1.0::FLOAT4, |
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.
nit: indent the lines with column definitions here and below.
pkg/sql/catalog/tabledesc/table.go
Outdated
ret.OnUpdateExpr, err = schemaexpr.SanitizeVarFreeExpr( | ||
ctx, d.OnUpdateExpr.Expr, resType, "ON UPDATE", semaCtx, volatility.Volatile, | ||
) | ||
if err != nil { | ||
// Check if the on update expression type can be assignment-cast into the | ||
// column type. If it can allow the on update expr and column type to differ. | ||
ret.OnUpdateExpr, innerErr = d.OnUpdateExpr.Expr.TypeCheck(ctx, semaCtx, types.Any) |
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.
Can you add tests for ON UPDATE
too?
016c1b0
to
c14a307
Compare
pkg/sql/opt/optbuilder/scope.go
Outdated
expr = s.walkExprTree(expr) | ||
texpr, err := tree.TypeCheckAndRequire(s.builder.ctx, expr, s.builder.semaCtx, desired, s.context.String()) | ||
texpr, err := tree.TypeCheckAndRequire(s.builder.ctx, expr, s.builder.semaCtx, desired, s.context.String(), true, mutSuffix) |
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 don't think we can allow assignment casts here in all cases. But, taking a step back, I'm curious why the optbuilder changes were necessary. What was failing before this change?
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.
After making the table with differing column and default types, trying to insert into the table would result in an error. This was caused by the condition in TypeCheckRequire
if typ := typedExpr.ResolvedType(); !(typ.Equivalent(required) || typ.Family() == types.UnknownFamily) {
I changed the function in opt builder because I noticed the mutation suffix could be passed here to be used in TypeCheckRequire.
Would specifying that the mutation suffix has to be default or update narrow it down to only the cases we want?
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.
Interesting. I'd expect the types to be fine given that assignment casts should be added in these cases by optbuilder automatically:
cockroach/pkg/sql/opt/optbuilder/insert.go
Line 661 in e55a7bf
mb.addAssignmentCasts(mb.insertColIDs) |
I'll check out your branch and play around with it a bit to better understand what to do here. Thanks for being patient with me!
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.
Ok, I think the change required in optbuilder was simpler, though tricky to figure out. I put up a PR: #81863. If you rebase your changes on that, you shouldn't need to make any changes in optbuilder.
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.
That PR has been merged, so optbuilder should behave as expected if you rebase on the latest version of master.
pkg/sql/catalog/tabledesc/table.go
Outdated
@@ -168,7 +168,7 @@ func MakeColumnDefDescs( | |||
// Verify the on update expression type is compatible with the column type | |||
// and does not contain invalid functions. | |||
ret.OnUpdateExpr, err = schemaexpr.SanitizeVarFreeExpr( | |||
ctx, d.OnUpdateExpr.Expr, resType, "ON UPDATE", semaCtx, volatility.Volatile, | |||
ctx, d.OnUpdateExpr.Expr, resType, "ON UPDATE", semaCtx, volatility.Volatile, true, |
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.
nit: It's helpful to label arguments with simple constants to make it more clear, like true /* allowAssignmentCast */
.
This commit allows the optimizer to build assignment casts for `DEFAULT` and `ON UPDATE` expressions that have types that are not equivalent with their column's type. If the cast from the `DEFAULT` or `ON UPDATE` expression type to the column type is not a valid assignment cast, an error is returned. In practice, this error should never occur because 1) it is currently impossible to create `DEFAULT` and `ON UPDATE` expressions that do not match their column's type (the tests here get around this limitation because they use the optimizer test catalog which has much looser restrictions) and 2) a future PR will allow creating `DEFAULT` and `ON UPDATE` expressions that do not match their column's type only if the cast from the expression type to the column type is a valid assignment cast. Unblocks cockroachdb#81071 Release note: None
81863: opt: assignment casts of non-equivalent types in DEFAULT and ON UPDATE r=mgartner a=mgartner This commit allows the optimizer to build assignment casts for `DEFAULT` and `ON UPDATE` expressions that have types that are not equivalent with their column's type. If the cast from the `DEFAULT` or `ON UPDATE` expression type to the column type is not a valid assignment cast, an error is returned. In practice, this error should never occur because 1) it is currently impossible to create `DEFAULT` and `ON UPDATE` expressions that do not match their column's type (the tests here get around this limitation because they use the optimizer test catalog which has much looser restrictions) and 2) a future PR will allow creating `DEFAULT` and `ON UPDATE` expressions that do not match their column's type only if the cast from the expression type to the column type is a valid assignment cast. Unblocks #81071 Release note: None Co-authored-by: Marcus Gartner <[email protected]>
c14a307
to
e9962a8
Compare
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.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @ajwerner, @e-mbrown, and @mgartner)
pkg/sql/catalog/tabledesc/table.go
line 168 at r5 (raw file):
ctx, d.DefaultExpr.Expr, resType, "DEFAULT", semaCtx, volatility.Volatile, ) if err != nil {
i think it would be more readable if var innerErr error
was here (near where the code where it's assigned), instead of having it earlier in the function
pkg/sql/catalog/tabledesc/table.go
line 173 at r5 (raw file):
ret.DefaultExpr, innerErr = d.DefaultExpr.Expr.TypeCheck(ctx, semaCtx, types.Any) if innerErr != nil { return nil, err
is it intentional to not return innerErr here? (i think maybe it is, but in that case, add a comment explaining why)
pkg/sql/catalog/tabledesc/table.go
line 197 at r5 (raw file):
ctx, d.OnUpdateExpr.Expr, resType, "ON UPDATE", semaCtx, volatility.Volatile, ) if err != nil {
i think it would be more readable if var innerErr error
was here (near where the code where it's assigned), instead of having it earlier in the function
pkg/sql/catalog/tabledesc/table.go
line 202 at r5 (raw file):
ret.OnUpdateExpr, innerErr = d.OnUpdateExpr.Expr.TypeCheck(ctx, semaCtx, types.Any) if innerErr != nil { return nil, err
nit: add a comment for why we don't return innerErr
pkg/sql/catalog/tabledesc/table.go
line 184 at r6 (raw file):
// and does not contain invalid functions. ret.OnUpdateExpr, err = schemaexpr.SanitizeVarFreeExpr( ctx, d.OnUpdateExpr.Expr, resType, "ON UPDATE", semaCtx, volatility.Volatile, true,
nit: add an inline comment here, and all the other places where it's called
SanitizeVarFreeExpr(..., true /* allowAssignmentCasts */)
pkg/sql/opt/optbuilder/scope.go
line 480 at r6 (raw file):
// desired type. func (s *scope) resolveAndRequireType( expr tree.Expr, desired *types.T, mutSuffix string,
is mutSuffix
an accident? it doesn't seem to be used
e9962a8
to
31f6209
Compare
31f6209
to
257f561
Compare
67e73b1
to
f042fae
Compare
Release note (sql change): A column's DEFAULT/ON UPDATE clause can now have a type that differs from the column type,as long as that type can be assignment-cast into the column's type. This increases our PostgreSQL compatibility.
f042fae
to
e4c2cf1
Compare
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.
LGTM. Very nice!
default/on update expr with differing types Release note: None
e4c2cf1
to
e4a01e0
Compare
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.
lgtm!
Reviewed 14 of 17 files at r10, 1 of 1 files at r11, all commit messages.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @ajwerner, @e-mbrown, and @mgartner)
bors r+ |
Build succeeded: |
Resolves #74854
postgres:
crdb:
Release note (sql change): A column's DEFAULT/ON UPDATE clause
can now have a type that differs from the column type, as long as
that type can be assignment-cast into the column's type. This
increases our PostgreSQL compatibility.