diff --git a/pkg/sql/catalog/schemaexpr/computed_column.go b/pkg/sql/catalog/schemaexpr/computed_column.go index e8e521d159ed..f3108342ab65 100644 --- a/pkg/sql/catalog/schemaexpr/computed_column.go +++ b/pkg/sql/catalog/schemaexpr/computed_column.go @@ -146,6 +146,28 @@ func ValidateComputedColumnExpression( } } + // run the same validation in sql/row/row_converter.go => GenerateInsertRow function + var txCtx transform.ExprTransformContext + evalCtx := &eval.Context{} + // compute expression can have dependency to another column, + // in this case line below will throw an error and validation is not necessary + typedExpr, err := tree.TypeCheck(ctx, d.Computed.Expr, semaCtx, defType) + if err == nil { + typedExpr, err = txCtx.NormalizeExpr(ctx, evalCtx, typedExpr) + if err != nil { + return "", nil, err + } + datum, err := eval.Expr(ctx, evalCtx, typedExpr) + if err != nil { + return "", nil, err + } + // AdjustValueToType function does the validation + _, err = tree.AdjustValueToType(defType, datum) + if err != nil { + return "", nil, err + } + } + return expr, typ, nil } diff --git a/pkg/sql/logictest/testdata/logic_test/computed b/pkg/sql/logictest/testdata/logic_test/computed index a0a5222e32e6..e60224fc0736 100644 --- a/pkg/sql/logictest/testdata/logic_test/computed +++ b/pkg/sql/logictest/testdata/logic_test/computed @@ -1095,3 +1095,84 @@ FROM t88128 ---- b1 expected_b1 b2 expected_b2 true true true true + +# Regression tests for #81698 computed columns are not validated on existing data" +subtest regression_81698 + +statement ok +CREATE TABLE t81698 (i INT PRIMARY KEY); + +statement ok +CREATE TYPE greeting AS ENUM ('hello', 'howdy', 'hi'); + +statement ok +ALTER TABLE t81698 ADD COLUMN s VARCHAR(2) AS ('st') STORED; + +statement ok +ALTER TABLE t81698 ADD COLUMN test INT; + +statement ok +ALTER TABLE t81698 ADD COLUMN ii INT AS (test*2) STORED; + +statement ok +ALTER TABLE t81698 ADD COLUMN iii INT AS (test*3) VIRTUAL; + +statement error pgcode 22001 pq: value too long for type VARCHAR\(2\) +ALTER TABLE t81698 ADD COLUMN v2 VARCHAR(2) AS ('virtual') VIRTUAL; + +statement error pgcode 22001 pq: value too long for type VARCHAR\(2\) +ALTER TABLE t81698 ADD COLUMN v2 VARCHAR(2) AS ('stored') STORED; + +statement error pgcode 22003 pq: integer out of range for type int2 +ALTER TABLE t81698 ADD COLUMN s3 INT2 AS (32768) STORED; + +# should this error be categorized? +statement error pgcode XXUUU pq: expected computed column expression to have type bool, but '32768' has type int +ALTER TABLE t81698 ADD COLUMN s4 BOOL AS (32768) STORED; + +statement error pgcode 22003 pq: integer out of range for type int2 +ALTER TABLE t81698 ADD COLUMN s3 INT2 AS (32768) VIRTUAL; + +# should this error be categorized? +statement error pgcode XXUUU pq: expected computed column expression to have type bool, but '32768' has type int +ALTER TABLE t81698 ADD COLUMN s4 BOOL AS (32768) VIRTUAL; + +statement ok +ALTER TABLE t81698 ADD COLUMN w greeting AS ('hi') STORED; + +statement error pgcode 22P02 pq: invalid input value for enum greeting: "none" +ALTER TABLE t81698 ADD COLUMN w2 greeting AS ('none') STORED; + +statement ok +INSERT INTO t81698 VALUES (2); + +statement ok +DROP TABLE t81698; + +statement error pgcode 22001 pq: value too long for type VARCHAR\(2\) +CREATE TABLE t81698 (i INT PRIMARY KEY, +v VARCHAR(2) AS ('virtual') VIRTUAL); + +statement error pgcode 22001 pq: value too long for type VARCHAR\(2\) +CREATE TABLE t81698 (i INT PRIMARY KEY, +v VARCHAR(2) AS ('stored') STORED); + +statement error pgcode 22003 pq: integer out of range for type int2 +CREATE TABLE t81698 (i INT PRIMARY KEY, +s3 INT2 AS (32768) STORED); + +statement error pgcode 22003 pq: integer out of range for type int2 +CREATE TABLE t81698 (i INT PRIMARY KEY, +s3 INT2 AS (32768) VIRTUAL); + +statement error pgcode XXUUU pq: expected computed column expression to have type bool, but '32768' has type int +CREATE TABLE t81698 (i INT PRIMARY KEY, +s4 BOOL AS (32768) STORED); + +statement error pgcode XXUUU pq: expected computed column expression to have type bool, but '32768' has type int +CREATE TABLE t81698 (i INT PRIMARY KEY, +s4 BOOL AS (32768) VIRTUAL); + +statement error pgcode 22P02 pq: invalid input value for enum greeting: "none" +CREATE TABLE t81698 (i INT PRIMARY KEY, +w2 greeting AS ('none') STORED); diff --git a/pkg/sql/logictest/testdata/logic_test/virtual_columns b/pkg/sql/logictest/testdata/logic_test/virtual_columns index 02500d233dde..236cebc94338 100644 --- a/pkg/sql/logictest/testdata/logic_test/virtual_columns +++ b/pkg/sql/logictest/testdata/logic_test/virtual_columns @@ -1313,7 +1313,7 @@ ALTER TABLE t_added ADD COLUMN dn DECIMAL(5, 2) GENERATED ALWAYS AS (NULL) VIRTU # Note that we really should not be able to add this column as the expression # does not fit into the type. See #81698. -statement ok +statement error pgcode 22003 pq: type DECIMAL\(5,2\)\: value with precision 5, scale 2 must round to an absolute value less than 10\^3 ALTER TABLE t_added ADD COLUMN d DECIMAL(5, 2) GENERATED ALWAYS AS (123456.000000::DECIMAL) VIRTUAL; statement ok @@ -1342,7 +1342,6 @@ CREATE TABLE public.t_added ( i INT8 NOT NULL, i4n INT4 NULL AS (NULL) VIRTUAL, dn DECIMAL(5,2) NULL AS (NULL) VIRTUAL, - d DECIMAL(5,2) NULL AS (123456.000000:::DECIMAL) VIRTUAL, i4 INT4 NULL AS (4:::INT8) VIRTUAL, i2 INT2 NULL AS (2:::INT8) VIRTUAL, CONSTRAINT t_added_pkey PRIMARY KEY (i ASC) diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_add_column.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_add_column.go index 01ef49fe934f..fba691748e47 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_add_column.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_add_column.go @@ -207,12 +207,14 @@ func alterTableAddColumn( } if desc.HasDefault() { expression := b.WrapExpression(tbl.TableID, cdd.DefaultExpr) + spec.def = &scpb.ColumnDefaultExpression{ TableID: tbl.TableID, ColumnID: spec.col.ColumnID, Expression: *expression, } b.IncrementSchemaChangeAddColumnQualificationCounter("default_expr") + } // We're checking to see if a user is trying add a non-nullable column without a default to a // non-empty table by scanning the primary index span with a limit of 1 to see if any key exists. @@ -256,6 +258,7 @@ func alterTableAddColumn( default: b.IncrementSchemaChangeAddColumnTypeCounter(spec.colType.Type.TelemetryName()) } + } func columnNamesToIDs(b BuildCtx, tbl *scpb.Table) map[string]descpb.ColumnID {