sql: Allow DEFAULT/ON UPDATE types that can be assignment-cast#81071
sql: Allow DEFAULT/ON UPDATE types that can be assignment-cast#81071craig[bot] merged 2 commits intocockroachdb:masterfrom
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
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.
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
)
| 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.
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.
nit: indent the lines with column definitions here and below.
pkg/sql/catalog/tabledesc/table.go
Outdated
| 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.
Can you add tests for ON UPDATE too?
016c1b0 to
c14a307
Compare
pkg/sql/opt/optbuilder/scope.go
Outdated
| ) tree.TypedExpr { | ||
| 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.
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.
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.
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
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.
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.
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
| // 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.
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 <marcus@cockroachlabs.com>
c14a307 to
e9962a8
Compare
rafiss
left a comment
There was a problem hiding this comment.
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
default/on update expr with differing types Release note: None
e4c2cf1 to
e4a01e0
Compare
rafiss
left a comment
There was a problem hiding this comment.
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.