diff --git a/pkg/ccl/changefeedccl/changefeed_test.go b/pkg/ccl/changefeedccl/changefeed_test.go index f422186ea221..ad7dcad17e56 100644 --- a/pkg/ccl/changefeedccl/changefeed_test.go +++ b/pkg/ccl/changefeedccl/changefeed_test.go @@ -10362,7 +10362,7 @@ func TestChangefeedPredicateWithSchemaChange(t *testing.T) { }, alterStmt: "ALTER TABLE foo RENAME COLUMN c TO c_new", afterAlterStmt: "INSERT INTO foo (a, b) VALUES (3, 'tres')", - expectErr: `column "c" does not exist`, + expectErr: `(column "c" does not exist|could not identify column "c")`, }, { name: "alter enum", diff --git a/pkg/ccl/schemachangerccl/sctestbackupccl/backup_base_generated_test.go b/pkg/ccl/schemachangerccl/sctestbackupccl/backup_base_generated_test.go index 77780c9a254f..0ad53d2a6e47 100644 --- a/pkg/ccl/schemachangerccl/sctestbackupccl/backup_base_generated_test.go +++ b/pkg/ccl/schemachangerccl/sctestbackupccl/backup_base_generated_test.go @@ -456,6 +456,13 @@ func TestBackupRollbacks_base_alter_table_rename_column(t *testing.T) { sctest.BackupRollbacks(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupRollbacks_base_alter_table_rename_multiple_columns(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns" + sctest.BackupRollbacks(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupRollbacks_base_alter_table_validate_constraint(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1212,6 +1219,13 @@ func TestBackupRollbacksMixedVersion_base_alter_table_rename_column(t *testing.T sctest.BackupRollbacksMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupRollbacksMixedVersion_base_alter_table_rename_multiple_columns(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns" + sctest.BackupRollbacksMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupRollbacksMixedVersion_base_alter_table_validate_constraint(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1968,6 +1982,13 @@ func TestBackupSuccess_base_alter_table_rename_column(t *testing.T) { sctest.BackupSuccess(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupSuccess_base_alter_table_rename_multiple_columns(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns" + sctest.BackupSuccess(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupSuccess_base_alter_table_validate_constraint(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -2724,6 +2745,13 @@ func TestBackupSuccessMixedVersion_base_alter_table_rename_column(t *testing.T) sctest.BackupSuccessMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupSuccessMixedVersion_base_alter_table_rename_multiple_columns(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns" + sctest.BackupSuccessMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupSuccessMixedVersion_base_alter_table_validate_constraint(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) diff --git a/pkg/sql/catalog/schemaexpr/column.go b/pkg/sql/catalog/schemaexpr/column.go index 0a3c8691a5a8..c93fe5ce9786 100644 --- a/pkg/sql/catalog/schemaexpr/column.go +++ b/pkg/sql/catalog/schemaexpr/column.go @@ -221,6 +221,51 @@ func iterColDescriptors( return err } +// iterColsWithLookupFn iterates over the expression's variable columns and +// calls f on each, providing the column information from the lookup function. +// +// If the expression references a column that does not exist according to the +// lookup function, iterColsWithLookupFn errs with pgcode.UndefinedColumn. +// +// The column lookup function allows looking up columns both in the descriptor +// or in declarative schema changer elements. +func iterColsWithLookupFn( + rootExpr tree.Expr, + columnLookupFn ColumnLookupFn, + f func(columnName tree.Name, id catid.ColumnID, typ *types.T, isAccessible, isComputed bool) error, +) error { + _, err := tree.SimpleVisit(rootExpr, func(expr tree.Expr) (recurse bool, newExpr tree.Expr, err error) { + vBase, ok := expr.(tree.VarName) + if !ok { + // Not a VarName, don't do anything to this node. + return true, expr, nil + } + + v, err := vBase.NormalizeVarName() + if err != nil { + return false, nil, err + } + + c, ok := v.(*tree.ColumnItem) + if !ok { + return true, expr, nil + } + + colExists, colIsAccessible, isComputed, colID, colType := columnLookupFn(c.ColumnName) + if !colExists { + return false, nil, pgerror.Newf(pgcode.UndefinedColumn, + "column %q does not exist, referenced in %q", c.ColumnName, rootExpr.String()) + } + + if err := f(c.ColumnName, colID, colType, colIsAccessible, isComputed); err != nil { + return false, nil, err + } + return false, expr, err + }) + + return err +} + // dummyColumn represents a variable column that can type-checked. It is used // in validating check constraint and partial index predicate expressions. This // validation requires that the expression can be both both typed-checked and @@ -261,7 +306,7 @@ func (d *dummyColumn) ResolvedType() *types.T { return d.typ } -type ColumnLookupFn func(columnName tree.Name) (exists bool, accessible bool, id catid.ColumnID, typ *types.T) +type ColumnLookupFn func(columnName tree.Name) (exists, accessible, computed bool, id catid.ColumnID, typ *types.T) // ReplaceColumnVars replaces the occurrences of column names in an expression with // dummyColumns containing their type, so that they may be type-checked. It @@ -295,7 +340,7 @@ func ReplaceColumnVars( return true, expr, nil } - colExists, colIsAccessible, colID, colType := columnLookupFn(c.ColumnName) + colExists, colIsAccessible, _, colID, colType := columnLookupFn(c.ColumnName) if !colExists { return false, nil, pgerror.Newf(pgcode.UndefinedColumn, "column %q does not exist, referenced in %q", c.ColumnName, rootExpr.String()) diff --git a/pkg/sql/catalog/schemaexpr/computed_column.go b/pkg/sql/catalog/schemaexpr/computed_column.go index ab5703b38d18..00f60577f69c 100644 --- a/pkg/sql/catalog/schemaexpr/computed_column.go +++ b/pkg/sql/catalog/schemaexpr/computed_column.go @@ -12,10 +12,12 @@ import ( "github.com/cockroachdb/cockroach/pkg/clusterversion" "github.com/cockroachdb/cockroach/pkg/sql/catalog" + "github.com/cockroachdb/cockroach/pkg/sql/catalog/colinfo" "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" "github.com/cockroachdb/cockroach/pkg/sql/parserutils" "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" + "github.com/cockroachdb/cockroach/pkg/sql/sem/catid" "github.com/cockroachdb/cockroach/pkg/sql/sem/eval" "github.com/cockroachdb/cockroach/pkg/sql/sem/transform" "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" @@ -36,6 +38,9 @@ import ( // // - It does not have a default value. // - It does not reference other computed columns. +// - It does not reference inaccessible columns. +// - It does not depend on the region column name if the table is REGIONAL BY +// ROW and uses a foreign key to populate the region column. // // TODO(mgartner): Add unit tests for Validate. func ValidateComputedColumnExpression( @@ -47,69 +52,53 @@ func ValidateComputedColumnExpression( semaCtx *tree.SemaContext, version clusterversion.ClusterVersion, ) (serializedExpr string, _ *types.T, _ error) { - if d.HasDefaultExpr() { - return "", nil, pgerror.Newf( - pgcode.InvalidTableDefinition, - "%s cannot have default values", - context, - ) - } - - var depColIDs catalog.TableColSet - // First, check that no column in the expression is an inaccessible or - // computed column. - err := iterColDescriptors(desc, d.Computed.Expr, func(c catalog.Column) error { - if c.IsInaccessible() { - return pgerror.Newf( - pgcode.UndefinedColumn, - "column %q is inaccessible and cannot be referenced in a computed column expression", - c.GetName(), - ) - } - if c.IsComputed() { - return pgerror.Newf( - pgcode.InvalidTableDefinition, - "%s expression cannot reference computed columns", - context, - ) + // Create helper functions from the descriptor and delegate to the + // lookup-based validation function. + getAllNonDropColumnsFn := func() colinfo.ResultColumns { + cols := desc.NonDropColumns() + ret := make(colinfo.ResultColumns, len(cols)) + for i, col := range cols { + ret[i] = colinfo.ResultColumn{ + Name: col.GetName(), + Typ: col.GetType(), + Hidden: col.IsHidden(), + TableID: desc.GetID(), + PGAttributeNum: uint32(col.GetPGAttributeNum()), + } } - depColIDs.Add(c.GetID()) - - return nil - }) - if err != nil { - return "", nil, err + return ret } - // Resolve the type of the computed column expression. - defType, err := tree.ResolveType(ctx, d.Type, semaCtx.GetTypeResolver()) - if err != nil { - return "", nil, err - } + columnLookupFn := makeColumnLookupFnForTableDesc(desc) - // Check that the type of the expression is of type defType and that there - // are no variable expressions (besides dummyColumnItems) and no impure - // functions. In order to safely serialize user defined types and their - // members, we need to serialize the typed expression here. - expr, typ, _, err := DequalifyAndValidateExpr( + serializedExpr, typ, err := ValidateComputedColumnExpressionWithLookup( ctx, desc, - d.Computed.Expr, - defType, + d, + tn, context, semaCtx, - volatility.Immutable, - tn, version, + getAllNonDropColumnsFn, + columnLookupFn, ) if err != nil { return "", nil, err } + var depColIDs catalog.TableColSet + if err := iterColDescriptors(desc, d.Computed.Expr, func(c catalog.Column) error { + depColIDs.Add(c.GetID()) + return nil + }); err != nil { + return "", nil, err + } + // Virtual computed columns must not refer to mutation columns because it // would not be safe in the case that the mutation column was being // backfilled and the virtual computed column value needed to be computed // for the purpose of writing to a secondary index. + // This check is specific to the legacy schema changer. if d.IsVirtual() { var mutationColumnNames []string var err error @@ -144,6 +133,86 @@ func ValidateComputedColumnExpression( } } + return serializedExpr, typ, nil +} + +// ValidateComputedColumnExpressionWithLookup verifies that an expression is a +// valid computed column expression using a column lookup function. It returns +// the serialized expression and its type if valid, and an error otherwise. +// +// This is similar to ValidateComputedColumnExpression but uses a ColumnLookupFn +// instead of a catalog.TableDescriptor, allowing it to work with declarative +// schema changer elements. +func ValidateComputedColumnExpressionWithLookup( + ctx context.Context, + desc catalog.TableDescriptor, + d *tree.ColumnTableDef, + tn *tree.TableName, + context tree.SchemaExprContext, + semaCtx *tree.SemaContext, + version clusterversion.ClusterVersion, + getAllNonDropColumnsFn func() colinfo.ResultColumns, + columnLookupFn ColumnLookupFn, +) (serializedExpr string, _ *types.T, _ error) { + if d.HasDefaultExpr() { + return "", nil, pgerror.Newf( + pgcode.InvalidTableDefinition, + "%s cannot have default values", + context, + ) + } + + var depColIDs catalog.TableColSet + // First, check that no column in the expression is an inaccessible or + // computed column. + err := iterColsWithLookupFn(d.Computed.Expr, columnLookupFn, + func(columnName tree.Name, id catid.ColumnID, typ *types.T, isAccessible, isComputed bool) error { + if !isAccessible { + return pgerror.Newf( + pgcode.UndefinedColumn, + "column %q is inaccessible and cannot be referenced in a computed column expression", + columnName, + ) + } + if isComputed { + return pgerror.Newf( + pgcode.InvalidTableDefinition, + "%s expression cannot reference computed columns", + context, + ) + } + depColIDs.Add(id) + return nil + }) + if err != nil { + return "", nil, err + } + + // Resolve the type of the computed column expression. + defType, err := tree.ResolveType(ctx, d.Type, semaCtx.GetTypeResolver()) + if err != nil { + return "", nil, err + } + + // Check that the type of the expression is of type defType and that there + // are no variable expressions (besides dummyColumnItems) and no impure + // functions. We use DequalifyAndValidateExprImpl with the lookup function. + expr, typ, _, err := DequalifyAndValidateExprImpl( + ctx, + d.Computed.Expr, + defType, + context, + semaCtx, + volatility.Immutable, + tn, + version, + getAllNonDropColumnsFn, + columnLookupFn, + ) + if err != nil { + return "", nil, err + } + // If this is a REGIONAL BY ROW table using a foreign key to populate the // region column, we need to check that the expression does not reference // the region column. This is because the values of every (possibly computed) diff --git a/pkg/sql/catalog/schemaexpr/expr.go b/pkg/sql/catalog/schemaexpr/expr.go index 748c06a645cc..d68d70a07ce2 100644 --- a/pkg/sql/catalog/schemaexpr/expr.go +++ b/pkg/sql/catalog/schemaexpr/expr.go @@ -113,12 +113,12 @@ func DequalifyAndValidateExpr( getAllNonDropColumnsFn := func() colinfo.ResultColumns { return colinfo.ResultColumnsFromColumns(desc.GetID(), desc.NonDropColumns()) } - columnLookupByNameFn := func(columnName tree.Name) (exists bool, accessible bool, id catid.ColumnID, typ *types.T) { + columnLookupByNameFn := func(columnName tree.Name) (exists, accessible, computed bool, id catid.ColumnID, typ *types.T) { col, err := catalog.MustFindColumnByTreeName(desc, columnName) if err != nil || col.Dropped() { - return false, false, 0, nil + return false, false, false, 0, nil } - return true, !col.IsInaccessible(), col.GetID(), col.GetType() + return true, !col.IsInaccessible(), col.IsComputed(), col.GetID(), col.GetType() } return DequalifyAndValidateExprImpl(ctx, expr, typ, context, semaCtx, maxVolatility, tn, version, @@ -249,12 +249,12 @@ func FormatExprForExpressionIndexDisplay( } func makeColumnLookupFnForTableDesc(desc catalog.TableDescriptor) ColumnLookupFn { - return func(columnName tree.Name) (exists bool, accessible bool, id catid.ColumnID, typ *types.T) { + return func(columnName tree.Name) (exists, accessible, computed bool, id catid.ColumnID, typ *types.T) { col, err := catalog.MustFindColumnByTreeName(desc, columnName) if err != nil || col.Dropped() { - return false, false, 0, nil + return false, false, false, 0, nil } - return true, !col.IsInaccessible(), col.GetID(), col.GetType() + return true, !col.IsInaccessible(), col.IsComputed(), col.GetID(), col.GetType() } } @@ -269,14 +269,14 @@ func ParseTriggerWhenExprForDisplay( semaCtx *tree.SemaContext, fmtFlags tree.FmtFlags, ) (tree.Expr, error) { - lookupFn := func(columnName tree.Name) (exists bool, accessible bool, id catid.ColumnID, typ *types.T) { + lookupFn := func(columnName tree.Name) (exists, accessible, computed bool, id catid.ColumnID, typ *types.T) { // Trigger WHEN expressions can reference only the special OLD and NEW // columns. switch columnName { case "old", "new": - return true, true, 0, tableTyp + return true, true, false, 0, tableTyp } - return false, false, 0, nil + return false, false, false, 0, nil } return parseExprForDisplayImpl( ctx, diff --git a/pkg/sql/logictest/testdata/logic_test/alter_table b/pkg/sql/logictest/testdata/logic_test/alter_table index bc14f2a5fa43..6812bcbd6567 100644 --- a/pkg/sql/logictest/testdata/logic_test/alter_table +++ b/pkg/sql/logictest/testdata/logic_test/alter_table @@ -1221,9 +1221,9 @@ WHERE feature_name IN ( 'sql.schema.new_column.qualification.unique' ) ---- -sql.schema.new_column.qualification.unique sql.schema.new_column.qualification.computed sql.schema.new_column.qualification.default_expr +sql.schema.new_column.qualification.unique statement ok DROP TABLE telemetry_test diff --git a/pkg/sql/logictest/testdata/logic_test/virtual_columns b/pkg/sql/logictest/testdata/logic_test/virtual_columns index 4ecbbe0e26cb..a20c0a16ae23 100644 --- a/pkg/sql/logictest/testdata/logic_test/virtual_columns +++ b/pkg/sql/logictest/testdata/logic_test/virtual_columns @@ -1120,10 +1120,12 @@ subtest referencing_mutations statement ok CREATE TABLE t_ref (i INT PRIMARY KEY) WITH (schema_locked = false); +onlyif config local-legacy-schema-changer local-mixed-25.2 local-mixed-25.3 statement error pgcode 0A000 virtual computed column "k" referencing columns \("j"\) added in the current transaction ALTER TABLE t_ref ADD COLUMN j INT NOT NULL DEFAULT 42, ADD COLUMN k INT AS (i+j) VIRTUAL; +onlyif config local-legacy-schema-changer local-mixed-25.2 local-mixed-25.3 statement error pgcode 0A000 virtual computed column "l" referencing columns \("j", "k"\) added in the current transaction BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; SET LOCAL autocommit_before_ddl = false; @@ -1135,6 +1137,12 @@ COMMIT; statement ok ROLLBACK; +# The declarative schema changer allows this. +skipif config local-legacy-schema-changer local-mixed-25.2 local-mixed-25.3 +statement ok +ALTER TABLE t_ref ADD COLUMN j INT NOT NULL DEFAULT 42, + ADD COLUMN k INT AS (i+j) VIRTUAL; + # Test that adding virtual computed columns to tables which have been created # in the current transaction is fine. diff --git a/pkg/sql/schemachanger/dml_injection_test.go b/pkg/sql/schemachanger/dml_injection_test.go index a44cc988fe21..e15ed57a23e8 100644 --- a/pkg/sql/schemachanger/dml_injection_test.go +++ b/pkg/sql/schemachanger/dml_injection_test.go @@ -567,6 +567,14 @@ func TestAlterTableDMLInjection(t *testing.T) { }, schemaChange: "ALTER TABLE tbl DROP CONSTRAINT c, DROP COLUMN i", }, + { + desc: "verify that names can be swapped atomically", + setup: []string{ + "ALTER TABLE tbl ADD COLUMN i INT DEFAULT 11, ADD COLUMN j INT DEFAULT 22", + }, + schemaChange: "ALTER TABLE tbl RENAME COLUMN i TO i_old, RENAME COLUMN j TO i", + query: "SELECT i FROM tbl LIMIT 1", + }, } ctx := context.Background() diff --git a/pkg/sql/schemachanger/scbuild/builder_state.go b/pkg/sql/schemachanger/scbuild/builder_state.go index 1472f956466a..9d06a7248b75 100644 --- a/pkg/sql/schemachanger/scbuild/builder_state.go +++ b/pkg/sql/schemachanger/scbuild/builder_state.go @@ -838,13 +838,16 @@ func (b *builderState) WrapExpression(tableID catid.DescID, expr tree.Expr) *scp // ComputedColumnExpression implements the scbuildstmt.TableHelpers interface. func (b *builderState) ComputedColumnExpression( - tbl *scpb.Table, d *tree.ColumnTableDef, exprContext tree.SchemaExprContext, + tbl *scpb.Table, + d *tree.ColumnTableDef, + exprContext tree.SchemaExprContext, + getAllNonDropColumnsFn func() colinfo.ResultColumns, + columnLookupByNameFn schemaexpr.ColumnLookupFn, ) (tree.Expr, *types.T) { _, _, ns := scpb.FindNamespace(b.QueryByID(tbl.TableID)) tn := tree.MakeTableNameFromPrefix(b.NamePrefix(tbl), tree.Name(ns.Name)) b.ensureDescriptor(tbl.TableID) - // TODO(postamar): this doesn't work when referencing newly added columns. - expr, typ, err := schemaexpr.ValidateComputedColumnExpression( + expr, typ, err := schemaexpr.ValidateComputedColumnExpressionWithLookup( b.ctx, b.descCache[tbl.TableID].desc.(catalog.TableDescriptor), d, @@ -852,15 +855,10 @@ func (b *builderState) ComputedColumnExpression( exprContext, b.semaCtx, b.clusterSettings.Version.ActiveVersion(b.ctx), + getAllNonDropColumnsFn, + columnLookupByNameFn, ) if err != nil { - // This may be referencing newly added columns, so cheat and return - // a not implemented error. - if pgerror.GetPGCode(err) == pgcode.UndefinedColumn { - - panic(errors.Wrapf(errors.WithSecondaryError(scerrors.NotImplementedError(d), err), - "computed column validation error")) - } panic(err) } parsedExpr, err := parser.ParseExpr(expr) 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 3630e2b1b779..57ae85ff177d 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 @@ -50,7 +50,13 @@ func alterTableAddColumn( RequiredPrivilege: privilege.CREATE, }) _, colTargetStatus, col := scpb.FindColumn(elts) - columnAlreadyExists := col != nil && colTargetStatus != scpb.ToAbsent + _, colNameTargetStatus, colName := scpb.FindColumnName(elts) + // A column name already exists if both the Column and ColumnName elements exist + // and are not transitioning to ABSENT. When a column is being renamed, the + // Column remains but the old ColumnName transitions to ABSENT, freeing up the + // name for reuse. + columnAlreadyExists := col != nil && colTargetStatus != scpb.ToAbsent && + colName != nil && colNameTargetStatus != scpb.ToAbsent // If the column exists and IF NOT EXISTS is specified, continue parsing // to ensure there are no other errors before treating the operation as a no-op. if columnAlreadyExists && !t.IfNotExists { @@ -119,6 +125,9 @@ func alterTableAddColumn( unique: d.Unique.IsUnique, notNull: !desc.Nullable, } + if spec.unique { + b.IncrementSchemaChangeAddColumnQualificationCounter("unique") + } idx := cdd.PrimaryKeyOrUniqueIndexDescriptor isRBR := b.QueryByID(tbl.TableID).FilterTableLocalityRegionalByRow().MustGetZeroOrOneElement() != nil @@ -168,7 +177,15 @@ func alterTableAddColumn( )) } if desc.IsComputed() { - validExpr, _ := b.ComputedColumnExpression(tbl, d, tree.ComputedColumnExprContext(d.IsVirtual())) + validExpr, _ := b.ComputedColumnExpression( + tbl, d, tree.ComputedColumnExprContext(d.IsVirtual()), + func() colinfo.ResultColumns { + return getNonDropResultColumns(b, tbl.TableID) + }, + func(columnName tree.Name) (exists, accessible, computed bool, id catid.ColumnID, typ *types.T) { + return columnLookupFn(b, tbl.TableID, columnName) + }, + ) expr := b.WrapExpression(tbl.TableID, validExpr) if spec.colType.ElementCreationMetadata.In_24_3OrLater { spec.compute = &scpb.ColumnComputeExpression{ diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_add_constraint.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_add_constraint.go index 0f762219e041..6783418cf2e7 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_add_constraint.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_add_constraint.go @@ -123,7 +123,7 @@ func alterTableAddCheck( func() colinfo.ResultColumns { return getNonDropResultColumns(b, tbl.TableID) }, - func(columnName tree.Name) (exists bool, accessible bool, id catid.ColumnID, typ *types.T) { + func(columnName tree.Name) (exists, accessible, computed bool, id catid.ColumnID, typ *types.T) { return columnLookupFn(b, tbl.TableID, columnName) }, ) @@ -522,7 +522,7 @@ func alterTableAddUniqueWithoutIndex( func() colinfo.ResultColumns { return getNonDropResultColumns(b, tbl.TableID) }, - func(columnName tree.Name) (exists bool, accessible bool, id catid.ColumnID, typ *types.T) { + func(columnName tree.Name) (exists, accessible, computed bool, id catid.ColumnID, typ *types.T) { return columnLookupFn(b, tbl.TableID, columnName) }, ) @@ -662,36 +662,6 @@ func validateConstraintNameIsNotUsed( "duplicate constraint name: %q", name) } -// getNonDropResultColumns returns all public and adding columns, sorted by -// column ID in ascending order, in the format of ResultColumns. -func getNonDropResultColumns(b BuildCtx, tableID catid.DescID) (ret colinfo.ResultColumns) { - for _, col := range getNonDropColumns(b, tableID) { - ret = append(ret, colinfo.ResultColumn{ - Name: mustRetrieveColumnNameElem(b, tableID, col.ColumnID).Name, - Typ: mustRetrieveColumnTypeElem(b, tableID, col.ColumnID).Type, - Hidden: col.IsHidden, - TableID: tableID, - PGAttributeNum: uint32(col.PgAttributeNum), - }) - } - return ret -} - -// columnLookupFn can look up information of a column by name. -// It should be exclusively used in DequalifyAndValidateExprImpl. -func columnLookupFn( - b BuildCtx, tableID catid.DescID, columnName tree.Name, -) (exists bool, accessible bool, id catid.ColumnID, typ *types.T) { - columnID := getColumnIDFromColumnName(b, tableID, columnName, false /* required */) - if columnID == 0 { - return false, false, 0, nil - } - - colElem := mustRetrieveColumnElem(b, tableID, columnID) - colTypeElem := mustRetrieveColumnTypeElem(b, tableID, columnID) - return true, !colElem.IsInaccessible, columnID, colTypeElem.Type -} - // generateUniqueCheckConstraintName generates a unique name for check constraint. // The default name is `check_` followed by all columns in the expression (e.g. `check_a_b_a`). // If that name is already in use, append a number (i.e. 1, 2, ...) to it until diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_column_type.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_column_type.go index befd82ab2951..c8092b8d155a 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_column_type.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_column_type.go @@ -215,7 +215,7 @@ func validateNewTypeForComputedColumn( func() colinfo.ResultColumns { return getNonDropResultColumns(b, tableID) }, - func(columnName tree.Name) (exists bool, accessible bool, id catid.ColumnID, typ *types.T) { + func(columnName tree.Name) (exists, accessible, computed bool, id catid.ColumnID, typ *types.T) { return columnLookupFn(b, tableID, columnName) }, ) @@ -531,7 +531,7 @@ func getComputeExpressionForBackfill( func() colinfo.ResultColumns { return getNonDropResultColumns(b, tableID) }, - func(columnName tree.Name) (exists bool, accessible bool, id catid.ColumnID, typ *types.T) { + func(columnName tree.Name) (exists, accessible, computed bool, id catid.ColumnID, typ *types.T) { return columnLookupFn(b, tableID, columnName) }, ) diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_rename_column.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_rename_column.go index 04db236ab73e..35968826766e 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_rename_column.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_rename_column.go @@ -6,6 +6,7 @@ package scbuildstmt import ( + "github.com/cockroachdb/cockroach/pkg/clusterversion" "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" "github.com/cockroachdb/cockroach/pkg/sql/privilege" @@ -24,7 +25,7 @@ func alterTableRenameColumn( n *tree.AlterTable, t *tree.AlterTableRenameColumn, ) { - if len(n.Cmds) > 1 { + if len(n.Cmds) > 1 && !b.EvalCtx().Settings.Version.IsActive(b, clusterversion.V25_4 /* change to 26.1 */) { panic(scerrors.NotImplementedError(n)) } alterColumnPreChecks(b, tn, tbl, t.Column) @@ -123,16 +124,10 @@ func checkNewColumnNameConflicts(b BuildCtx, tableID catid.DescID, oldName, newN "column name %q conflicts with a system column name", tree.ErrString(&newName))) } - if current == scpb.Status_PUBLIC { - if target == scpb.ToAbsent { - panic(pgerror.Newf(pgcode.ObjectNotInPrerequisiteState, "column %q being dropped, try again later", tree.ErrString(&newName))) - } + if current == scpb.Status_PUBLIC && target != scpb.ToAbsent { tableName := b.QueryByID(tableID).FilterNamespace().MustGetOneElement() panic(sqlerrors.NewColumnAlreadyExistsInRelationError(tree.ErrString(&newName), tableName.Name)) } - if current == scpb.Status_ABSENT && target == scpb.ToPublic { - panic(pgerror.Newf(pgcode.ObjectNotInPrerequisiteState, "column %q being dropped, try again later", tree.ErrString(&newName))) - } } }) } diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/create_index.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/create_index.go index 36bdc5345720..d2c5f4e18986 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/create_index.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/create_index.go @@ -979,7 +979,15 @@ func maybeCreateVirtualColumnForIndex( d.Nullable.Nullability = tree.Null // Infer column type from expression. { - _, columnType := b.ComputedColumnExpression(tbl, d, tree.ExpressionIndexElementExpr) + _, columnType := b.ComputedColumnExpression( + tbl, d, tree.ExpressionIndexElementExpr, + func() colinfo.ResultColumns { + return getNonDropResultColumns(b, tbl.TableID) + }, + func(columnName tree.Name) (exists, accessible, computed bool, id catid.ColumnID, typ *types.T) { + return columnLookupFn(b, tbl.TableID, columnName) + }, + ) d.Type = columnType validateColumnIndexableType(columnType) } diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/create_policy.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/create_policy.go index beb167f77299..242a0b6b3ef4 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/create_policy.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/create_policy.go @@ -281,7 +281,7 @@ func validateAndResolveTypesInExpr( func() colinfo.ResultColumns { return getNonDropResultColumns(b, tableID) }, - func(columnName tree.Name) (exists bool, accessible bool, id catid.ColumnID, typ *types.T) { + func(columnName tree.Name) (exists, accessible, computed bool, id catid.ColumnID, typ *types.T) { return columnLookupFn(b, tableID, columnName) }, ) diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/dependencies.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/dependencies.go index d167afb37df8..246490946b04 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/dependencies.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/dependencies.go @@ -15,8 +15,10 @@ import ( "github.com/cockroachdb/cockroach/pkg/settings/cluster" "github.com/cockroachdb/cockroach/pkg/sql/catalog" "github.com/cockroachdb/cockroach/pkg/sql/catalog/catpb" + "github.com/cockroachdb/cockroach/pkg/sql/catalog/colinfo" "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" "github.com/cockroachdb/cockroach/pkg/sql/catalog/multiregion" + "github.com/cockroachdb/cockroach/pkg/sql/catalog/schemaexpr" "github.com/cockroachdb/cockroach/pkg/sql/privilege" "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scdecomp" "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scpb" @@ -313,7 +315,11 @@ type TableHelpers interface { // ComputedColumnExpression returns a validated computed column expression // and its type. // TODO(postamar): make this more low-level instead of consuming an AST - ComputedColumnExpression(tbl *scpb.Table, d *tree.ColumnTableDef, exprContext tree.SchemaExprContext) (tree.Expr, *types.T) + ComputedColumnExpression( + tbl *scpb.Table, d *tree.ColumnTableDef, exprContext tree.SchemaExprContext, + getAllNonDropColumnsFn func() colinfo.ResultColumns, + columnLookupByNameFn schemaexpr.ColumnLookupFn, + ) (tree.Expr, *types.T) // PartialIndexPredicateExpression returns a validated partial predicate // wrapped expression diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/helpers.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/helpers.go index 685008e0e821..3b2a90f02d60 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/helpers.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/helpers.go @@ -1428,6 +1428,36 @@ func getLatestPrimaryIndex(b BuildCtx, tableID catid.DescID) *scpb.PrimaryIndex } } +// getNonDropResultColumns returns all public and adding columns, sorted by +// column ID in ascending order, in the format of ResultColumns. +func getNonDropResultColumns(b BuildCtx, tableID catid.DescID) (ret colinfo.ResultColumns) { + for _, col := range getNonDropColumns(b, tableID) { + ret = append(ret, colinfo.ResultColumn{ + Name: mustRetrieveColumnNameElem(b, tableID, col.ColumnID).Name, + Typ: mustRetrieveColumnTypeElem(b, tableID, col.ColumnID).Type, + Hidden: col.IsHidden, + TableID: tableID, + PGAttributeNum: uint32(col.PgAttributeNum), + }) + } + return ret +} + +// columnLookupFn can look up information of a column by name. +func columnLookupFn( + b BuildCtx, tableID catid.DescID, columnName tree.Name, +) (exists, accessible, computed bool, id catid.ColumnID, typ *types.T) { + columnID := getColumnIDFromColumnName(b, tableID, columnName, false /* required */) + if columnID == 0 { + return false, false, false, 0, nil + } + + colElem := mustRetrieveColumnElem(b, tableID, columnID) + colTypeElem := mustRetrieveColumnTypeElem(b, tableID, columnID) + computeExpr := retrieveColumnComputeExpression(b, tableID, columnID) + return true, !colElem.IsInaccessible, computeExpr != nil, columnID, colTypeElem.Type +} + // addASwapInIndexByCloningFromSource adds a primary index `in` that is going // to swap out `out` yet `in`'s columns are cloned from `source`. // diff --git a/pkg/sql/schemachanger/scbuild/testdata/alter_table_rename_column b/pkg/sql/schemachanger/scbuild/testdata/alter_table_rename_column new file mode 100644 index 000000000000..7a4585ab98eb --- /dev/null +++ b/pkg/sql/schemachanger/scbuild/testdata/alter_table_rename_column @@ -0,0 +1,161 @@ +setup +CREATE TABLE defaultdb.foo (i INT PRIMARY KEY, j INT) +---- + +build +ALTER TABLE defaultdb.foo RENAME COLUMN j TO k +---- +- [[ColumnName:{DescID: 104, Name: j, ColumnID: 2}, ABSENT], PUBLIC] + {columnId: 2, name: j, tableId: 104} +- [[IndexData:{DescID: 104, IndexID: 1}, PUBLIC], PUBLIC] + {indexId: 1, tableId: 104} +- [[TableData:{DescID: 104, ReferencedDescID: 100}, PUBLIC], PUBLIC] + {databaseId: 100, tableId: 104} +- [[ColumnName:{DescID: 104, Name: k, ColumnID: 2}, PUBLIC], ABSENT] + {columnId: 2, name: k, tableId: 104} + +build +ALTER TABLE defaultdb.foo RENAME COLUMN i TO id +---- +- [[ColumnName:{DescID: 104, Name: i, ColumnID: 1}, ABSENT], PUBLIC] + {columnId: 1, name: i, tableId: 104} +- [[IndexData:{DescID: 104, IndexID: 1}, PUBLIC], PUBLIC] + {indexId: 1, tableId: 104} +- [[TableData:{DescID: 104, ReferencedDescID: 100}, PUBLIC], PUBLIC] + {databaseId: 100, tableId: 104} +- [[ColumnName:{DescID: 104, Name: id, ColumnID: 1}, PUBLIC], ABSENT] + {columnId: 1, name: id, tableId: 104} + +setup +CREATE TABLE defaultdb.bar (x INT PRIMARY KEY, y INT, z INT, INDEX idx_y (y)) +---- + +build +ALTER TABLE defaultdb.bar RENAME COLUMN y TO y_new +---- +- [[ColumnName:{DescID: 105, Name: y, ColumnID: 2}, ABSENT], PUBLIC] + {columnId: 2, name: y, tableId: 105} +- [[IndexData:{DescID: 105, IndexID: 1}, PUBLIC], PUBLIC] + {indexId: 1, tableId: 105} +- [[IndexData:{DescID: 105, IndexID: 2}, PUBLIC], PUBLIC] + {indexId: 2, tableId: 105} +- [[TableData:{DescID: 105, ReferencedDescID: 100}, PUBLIC], PUBLIC] + {databaseId: 100, tableId: 105} +- [[ColumnName:{DescID: 105, Name: y_new, ColumnID: 2}, PUBLIC], ABSENT] + {columnId: 2, name: y_new, tableId: 105} + +setup +CREATE TABLE defaultdb.multi (a INT PRIMARY KEY, b INT, c INT, d INT) +---- + +build +ALTER TABLE defaultdb.multi RENAME COLUMN b TO b_renamed, RENAME COLUMN c TO c_renamed +---- +- [[ColumnName:{DescID: 106, Name: b, ColumnID: 2}, ABSENT], PUBLIC] + {columnId: 2, name: b, tableId: 106} +- [[ColumnName:{DescID: 106, Name: c, ColumnID: 3}, ABSENT], PUBLIC] + {columnId: 3, name: c, tableId: 106} +- [[IndexData:{DescID: 106, IndexID: 1}, PUBLIC], PUBLIC] + {indexId: 1, tableId: 106} +- [[TableData:{DescID: 106, ReferencedDescID: 100}, PUBLIC], PUBLIC] + {databaseId: 100, tableId: 106} +- [[ColumnName:{DescID: 106, Name: b_renamed, ColumnID: 2}, PUBLIC], ABSENT] + {columnId: 2, name: b_renamed, tableId: 106} +- [[ColumnName:{DescID: 106, Name: c_renamed, ColumnID: 3}, PUBLIC], ABSENT] + {columnId: 3, name: c_renamed, tableId: 106} + +setup +CREATE TABLE defaultdb.with_constraints ( + id INT PRIMARY KEY, + email TEXT UNIQUE, + age INT CHECK (age > 0), + balance DECIMAL DEFAULT 0.00 +) +---- + +build +ALTER TABLE defaultdb.with_constraints RENAME COLUMN email TO email_address +---- +- [[ColumnName:{DescID: 107, Name: email, ColumnID: 2}, ABSENT], PUBLIC] + {columnId: 2, name: email, tableId: 107} +- [[IndexData:{DescID: 107, IndexID: 1}, PUBLIC], PUBLIC] + {indexId: 1, tableId: 107} +- [[IndexData:{DescID: 107, IndexID: 2}, PUBLIC], PUBLIC] + {indexId: 2, tableId: 107} +- [[TableData:{DescID: 107, ReferencedDescID: 100}, PUBLIC], PUBLIC] + {databaseId: 100, tableId: 107} +- [[ColumnName:{DescID: 107, Name: email_address, ColumnID: 2}, PUBLIC], ABSENT] + {columnId: 2, name: email_address, tableId: 107} + +build +ALTER TABLE defaultdb.with_constraints RENAME COLUMN age TO person_age +---- +- [[ColumnName:{DescID: 107, Name: age, ColumnID: 3}, ABSENT], PUBLIC] + {columnId: 3, name: age, tableId: 107} +- [[IndexData:{DescID: 107, IndexID: 1}, PUBLIC], PUBLIC] + {indexId: 1, tableId: 107} +- [[IndexData:{DescID: 107, IndexID: 2}, PUBLIC], PUBLIC] + {indexId: 2, tableId: 107} +- [[TableData:{DescID: 107, ReferencedDescID: 100}, PUBLIC], PUBLIC] + {databaseId: 100, tableId: 107} +- [[ColumnName:{DescID: 107, Name: person_age, ColumnID: 3}, PUBLIC], ABSENT] + {columnId: 3, name: person_age, tableId: 107} + +build +ALTER TABLE defaultdb.with_constraints RENAME COLUMN balance TO account_balance +---- +- [[ColumnName:{DescID: 107, Name: balance, ColumnID: 4}, ABSENT], PUBLIC] + {columnId: 4, name: balance, tableId: 107} +- [[IndexData:{DescID: 107, IndexID: 1}, PUBLIC], PUBLIC] + {indexId: 1, tableId: 107} +- [[IndexData:{DescID: 107, IndexID: 2}, PUBLIC], PUBLIC] + {indexId: 2, tableId: 107} +- [[TableData:{DescID: 107, ReferencedDescID: 100}, PUBLIC], PUBLIC] + {databaseId: 100, tableId: 107} +- [[ColumnName:{DescID: 107, Name: account_balance, ColumnID: 4}, PUBLIC], ABSENT] + {columnId: 4, name: account_balance, tableId: 107} + +setup +CREATE SCHEMA sc1; +CREATE TABLE sc1.schema_table (col1 INT PRIMARY KEY, col2 TEXT) +---- + +build +ALTER TABLE sc1.schema_table RENAME COLUMN col2 TO column_two +---- +- [[ColumnName:{DescID: 109, Name: col2, ColumnID: 2}, ABSENT], PUBLIC] + {columnId: 2, name: col2, tableId: 109} +- [[IndexData:{DescID: 109, IndexID: 1}, PUBLIC], PUBLIC] + {indexId: 1, tableId: 109} +- [[TableData:{DescID: 109, ReferencedDescID: 100}, PUBLIC], PUBLIC] + {databaseId: 100, tableId: 109} +- [[ColumnName:{DescID: 109, Name: column_two, ColumnID: 2}, PUBLIC], ABSENT] + {columnId: 2, name: column_two, tableId: 109} + +setup +CREATE TABLE defaultdb.computed_col (i INT PRIMARY KEY, j INT, k INT AS (i + j) STORED) +---- + +build +ALTER TABLE defaultdb.computed_col RENAME COLUMN j TO j_new +---- +- [[ColumnName:{DescID: 110, Name: j, ColumnID: 2}, ABSENT], PUBLIC] + {columnId: 2, name: j, tableId: 110} +- [[IndexData:{DescID: 110, IndexID: 1}, PUBLIC], PUBLIC] + {indexId: 1, tableId: 110} +- [[TableData:{DescID: 110, ReferencedDescID: 100}, PUBLIC], PUBLIC] + {databaseId: 100, tableId: 110} +- [[ColumnName:{DescID: 110, Name: j_new, ColumnID: 2}, PUBLIC], ABSENT] + {columnId: 2, name: j_new, tableId: 110} + +build +ALTER TABLE defaultdb.computed_col RENAME COLUMN k TO k_renamed +---- +- [[ColumnName:{DescID: 110, Name: k, ColumnID: 3}, ABSENT], PUBLIC] + {columnId: 3, name: k, tableId: 110} +- [[IndexData:{DescID: 110, IndexID: 1}, PUBLIC], PUBLIC] + {indexId: 1, tableId: 110} +- [[TableData:{DescID: 110, ReferencedDescID: 100}, PUBLIC], PUBLIC] + {databaseId: 100, tableId: 110} +- [[ColumnName:{DescID: 110, Name: k_renamed, ColumnID: 3}, PUBLIC], ABSENT] + {columnId: 3, name: k_renamed, tableId: 110} diff --git a/pkg/sql/schemachanger/scplan/internal/rules/current/dep_add_column.go b/pkg/sql/schemachanger/scplan/internal/rules/current/dep_add_column.go index b6936d9978a1..bd90a0c6366d 100644 --- a/pkg/sql/schemachanger/scplan/internal/rules/current/dep_add_column.go +++ b/pkg/sql/schemachanger/scplan/internal/rules/current/dep_add_column.go @@ -204,6 +204,24 @@ func init() { } }, ) + + registerDepRule( + "column name is public before compute expression referencing it", + scgraph.Precedence, + "column-name", "compute-expression", + func(from, to NodeVars) rel.Clauses { + colID := rel.Var("columnID") + return rel.Clauses{ + from.Type((*scpb.ColumnName)(nil)), + to.Type((*scpb.ColumnComputeExpression)(nil)), + from.El.AttrEqVar(screl.ColumnID, colID), + to.ReferencedColumnIDsContains(colID), + JoinOnDescID(from, to, "table-id"), + from.TargetStatus(scpb.ToPublic), + StatusesToPublicOrTransient(from, scpb.Status_PUBLIC, to, scpb.Status_PUBLIC), + } + }, + ) } // This rule ensures that columns depend on each other in increasing order. diff --git a/pkg/sql/schemachanger/scplan/internal/rules/current/dep_alter_column_type.go b/pkg/sql/schemachanger/scplan/internal/rules/current/dep_alter_column_type.go index 4c02a31adba6..15d8a1587527 100644 --- a/pkg/sql/schemachanger/scplan/internal/rules/current/dep_alter_column_type.go +++ b/pkg/sql/schemachanger/scplan/internal/rules/current/dep_alter_column_type.go @@ -49,6 +49,7 @@ func init() { to.TargetStatus(scpb.ToPublic), from.CurrentStatus(scpb.Status_TRANSIENT_VALIDATED), to.CurrentStatus(scpb.Status_PUBLIC), + rel.And(IsAlterColumnTypeOp("table-id", colID)...), } }, ) diff --git a/pkg/sql/schemachanger/scplan/internal/rules/current/dep_drop_constraint.go b/pkg/sql/schemachanger/scplan/internal/rules/current/dep_drop_constraint.go index e9eccdfeb7da..d26f9d1e6321 100644 --- a/pkg/sql/schemachanger/scplan/internal/rules/current/dep_drop_constraint.go +++ b/pkg/sql/schemachanger/scplan/internal/rules/current/dep_drop_constraint.go @@ -96,19 +96,23 @@ func init() { ) } -// These rules ensure that a non-indexed backed constraint with a column -// name in its expression is cleaned up before the column is dropped. +// These rules ensure that a unique without index constraint with a column +// name in its expression is cleaned up before the column name is dropped. +// This is needed because unique without index constraints can have predicates +// that reference columns by name. func init() { registerDepRuleForDrop( - "non-indexed backed constraint should be cleaned up "+ - "before column name references", + "unique without index constraint should be cleaned up before column name references", scgraph.Precedence, "constraint", "referenced-column-name", scpb.Status_ABSENT, scpb.Status_ABSENT, func(from, to NodeVars) rel.Clauses { fromColumnID := rel.Var("fromColumnID") return rel.Clauses{ - from.TypeFilter(rulesVersionKey, isNonIndexBackedConstraint, isWithExpression), + from.Type( + (*scpb.UniqueWithoutIndexConstraint)(nil), + (*scpb.UniqueWithoutIndexConstraintUnvalidated)(nil), + ), from.ReferencedColumnIDsContains(fromColumnID), to.Type((*scpb.ColumnName)(nil)), to.El.AttrEqVar(screl.ColumnID, fromColumnID), diff --git a/pkg/sql/schemachanger/scplan/internal/rules/current/dep_rename_column.go b/pkg/sql/schemachanger/scplan/internal/rules/current/dep_rename_column.go index a0f8fc45c343..5e69dab6e8f9 100644 --- a/pkg/sql/schemachanger/scplan/internal/rules/current/dep_rename_column.go +++ b/pkg/sql/schemachanger/scplan/internal/rules/current/dep_rename_column.go @@ -10,6 +10,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scpb" . "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scplan/internal/rules" "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scplan/internal/scgraph" + "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/screl" ) // These rules ensure that when renaming a column, the old ColumnName element @@ -32,4 +33,31 @@ func init() { } }, ) + + // This rule ensures that when a column name is being freed up (going to ABSENT), + // that name cannot be used by a different column until the old name is fully removed. + // This prevents duplicate column name errors when renaming one column and adding + // another column with the old name in the same statement. + registerDepRule( + "column name is dropped before same name is used by different column", + scgraph.Precedence, + "old-column-name", "new-column-name", + func(from, to NodeVars) rel.Clauses { + name := rel.Var("name") + return rel.Clauses{ + from.Type((*scpb.ColumnName)(nil)), + to.Type((*scpb.ColumnName)(nil)), + JoinOnDescID(from, to, "table-id"), + from.El.AttrEqVar(screl.Name, name), + to.El.AttrEqVar(screl.Name, name), + from.TargetStatus(scpb.ToAbsent), + from.CurrentStatus(scpb.Status_ABSENT), + to.TargetStatus(scpb.ToPublic), + to.CurrentStatus(scpb.Status_PUBLIC), + FilterElements("DifferentColumnIDs", from, to, func(from, to *scpb.ColumnName) bool { + return from.ColumnID != to.ColumnID + }), + } + }, + ) } diff --git a/pkg/sql/schemachanger/scplan/internal/rules/current/testdata/deprules b/pkg/sql/schemachanger/scplan/internal/rules/current/testdata/deprules index 2990a9baba01..e1113af82f0d 100644 --- a/pkg/sql/schemachanger/scplan/internal/rules/current/testdata/deprules +++ b/pkg/sql/schemachanger/scplan/internal/rules/current/testdata/deprules @@ -2847,6 +2847,39 @@ deprules - $index-Node[CurrentStatus] = WRITE_ONLY - joinTargetNode($column, $column-Target, $column-Node) - joinTargetNode($index, $index-Target, $index-Node) +- name: column name is dropped before same name is used by different column + from: old-column-name-Node + kind: Precedence + to: new-column-name-Node + query: + - $old-column-name[Type] = '*scpb.ColumnName' + - $new-column-name[Type] = '*scpb.ColumnName' + - joinOnDescID($old-column-name, $new-column-name, $table-id) + - $old-column-name[Name] = $name + - $new-column-name[Name] = $name + - $old-column-name-Target[TargetStatus] = ABSENT + - $old-column-name-Node[CurrentStatus] = ABSENT + - $new-column-name-Target[TargetStatus] = PUBLIC + - $new-column-name-Node[CurrentStatus] = PUBLIC + - DifferentColumnIDs(*scpb.ColumnName, *scpb.ColumnName)($old-column-name, $new-column-name) + - joinTargetNode($old-column-name, $old-column-name-Target, $old-column-name-Node) + - joinTargetNode($new-column-name, $new-column-name-Target, $new-column-name-Node) +- name: column name is public before compute expression referencing it + from: column-name-Node + kind: Precedence + to: compute-expression-Node + query: + - $column-name[Type] = '*scpb.ColumnName' + - $compute-expression[Type] = '*scpb.ColumnComputeExpression' + - $column-name[ColumnID] = $columnID + - $compute-expression[ReferencedColumnIDs] CONTAINS $columnID + - joinOnDescID($column-name, $compute-expression, $table-id) + - $column-name-Target[TargetStatus] = PUBLIC + - ToPublicOrTransient($column-name-Target, $compute-expression-Target) + - $column-name-Node[CurrentStatus] = PUBLIC + - $compute-expression-Node[CurrentStatus] = PUBLIC + - joinTargetNode($column-name, $column-name-Target, $column-name-Node) + - joinTargetNode($compute-expression, $compute-expression-Target, $compute-expression-Node) - name: column name set right after column existence, except for alter column type from: column-Node kind: SameStagePrecedence @@ -2958,6 +2991,12 @@ deprules - $column-type-Target[TargetStatus] = PUBLIC - $transient-check-constraint-Node[CurrentStatus] = TRANSIENT_VALIDATED - $column-type-Node[CurrentStatus] = PUBLIC + - $column[Type] = '*scpb.Column' + - $compute-expression[Type] = '*scpb.ColumnComputeExpression' + - joinOnColumnID($column, $compute-expression, $table-id, $columnID) + - $compute-expression[Usage] = ALTER_TYPE_USING + - joinTargetNode($column, $column-Target, $column-Node) + - joinTargetNode($compute-expression, $compute-expression-Target, $compute-expression-Node) - joinTargetNode($transient-check-constraint, $transient-check-constraint-Target, $transient-check-constraint-Node) - joinTargetNode($column-type, $column-type-Target, $column-type-Node) - name: column type removed before column family @@ -4238,68 +4277,6 @@ deprules - $descriptor-Node[CurrentStatus] = ABSENT - joinTargetNode($dependent, $dependent-Target, $dependent-Node) - joinTargetNode($descriptor, $descriptor-Target, $descriptor-Node) -- name: non-indexed backed constraint should be cleaned up before column name references - from: constraint-Node - kind: Precedence - to: referenced-column-name-Node - query: - - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.CheckConstraintUnvalidated', '*scpb.UniqueWithoutIndexConstraint', '*scpb.UniqueWithoutIndexConstraintUnvalidated'] - - $constraint[ReferencedColumnIDs] CONTAINS $fromColumnID - - $referenced-column-name[Type] = '*scpb.ColumnName' - - $referenced-column-name[ColumnID] = $fromColumnID - - joinOnDescID($constraint, $referenced-column-name, $table-id) - - toAbsent($constraint-Target, $referenced-column-name-Target) - - $constraint-Node[CurrentStatus] = ABSENT - - $referenced-column-name-Node[CurrentStatus] = ABSENT - - joinTargetNode($constraint, $constraint-Target, $constraint-Node) - - joinTargetNode($referenced-column-name, $referenced-column-name-Target, $referenced-column-name-Node) -- name: non-indexed backed constraint should be cleaned up before column name references - from: constraint-Node - kind: Precedence - to: referenced-column-name-Node - query: - - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.CheckConstraintUnvalidated', '*scpb.UniqueWithoutIndexConstraint', '*scpb.UniqueWithoutIndexConstraintUnvalidated'] - - $constraint[ReferencedColumnIDs] CONTAINS $fromColumnID - - $referenced-column-name[Type] = '*scpb.ColumnName' - - $referenced-column-name[ColumnID] = $fromColumnID - - joinOnDescID($constraint, $referenced-column-name, $table-id) - - transient($constraint-Target, $referenced-column-name-Target) - - $constraint-Node[CurrentStatus] = TRANSIENT_ABSENT - - $referenced-column-name-Node[CurrentStatus] = TRANSIENT_ABSENT - - joinTargetNode($constraint, $constraint-Target, $constraint-Node) - - joinTargetNode($referenced-column-name, $referenced-column-name-Target, $referenced-column-name-Node) -- name: non-indexed backed constraint should be cleaned up before column name references - from: constraint-Node - kind: Precedence - to: referenced-column-name-Node - query: - - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.CheckConstraintUnvalidated', '*scpb.UniqueWithoutIndexConstraint', '*scpb.UniqueWithoutIndexConstraintUnvalidated'] - - $constraint[ReferencedColumnIDs] CONTAINS $fromColumnID - - $referenced-column-name[Type] = '*scpb.ColumnName' - - $referenced-column-name[ColumnID] = $fromColumnID - - joinOnDescID($constraint, $referenced-column-name, $table-id) - - $constraint-Target[TargetStatus] = TRANSIENT_ABSENT - - $constraint-Node[CurrentStatus] = TRANSIENT_ABSENT - - $referenced-column-name-Target[TargetStatus] = ABSENT - - $referenced-column-name-Node[CurrentStatus] = ABSENT - - joinTargetNode($constraint, $constraint-Target, $constraint-Node) - - joinTargetNode($referenced-column-name, $referenced-column-name-Target, $referenced-column-name-Node) -- name: non-indexed backed constraint should be cleaned up before column name references - from: constraint-Node - kind: Precedence - to: referenced-column-name-Node - query: - - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.CheckConstraintUnvalidated', '*scpb.UniqueWithoutIndexConstraint', '*scpb.UniqueWithoutIndexConstraintUnvalidated'] - - $constraint[ReferencedColumnIDs] CONTAINS $fromColumnID - - $referenced-column-name[Type] = '*scpb.ColumnName' - - $referenced-column-name[ColumnID] = $fromColumnID - - joinOnDescID($constraint, $referenced-column-name, $table-id) - - $constraint-Target[TargetStatus] = ABSENT - - $constraint-Node[CurrentStatus] = ABSENT - - $referenced-column-name-Target[TargetStatus] = TRANSIENT_ABSENT - - $referenced-column-name-Node[CurrentStatus] = TRANSIENT_ABSENT - - joinTargetNode($constraint, $constraint-Target, $constraint-Node) - - joinTargetNode($referenced-column-name, $referenced-column-name-Target, $referenced-column-name-Node) - name: old column name is dropped before new column name is added from: old-column-name-Node kind: Precedence @@ -5079,6 +5056,68 @@ deprules - $dependents-Node[CurrentStatus] = TRANSIENT_PUBLIC - joinTargetNode($trigger, $trigger-Target, $trigger-Node) - joinTargetNode($dependents, $dependents-Target, $dependents-Node) +- name: unique without index constraint should be cleaned up before column name references + from: constraint-Node + kind: Precedence + to: referenced-column-name-Node + query: + - $constraint[Type] IN ['*scpb.UniqueWithoutIndexConstraint', '*scpb.UniqueWithoutIndexConstraintUnvalidated'] + - $constraint[ReferencedColumnIDs] CONTAINS $fromColumnID + - $referenced-column-name[Type] = '*scpb.ColumnName' + - $referenced-column-name[ColumnID] = $fromColumnID + - joinOnDescID($constraint, $referenced-column-name, $table-id) + - toAbsent($constraint-Target, $referenced-column-name-Target) + - $constraint-Node[CurrentStatus] = ABSENT + - $referenced-column-name-Node[CurrentStatus] = ABSENT + - joinTargetNode($constraint, $constraint-Target, $constraint-Node) + - joinTargetNode($referenced-column-name, $referenced-column-name-Target, $referenced-column-name-Node) +- name: unique without index constraint should be cleaned up before column name references + from: constraint-Node + kind: Precedence + to: referenced-column-name-Node + query: + - $constraint[Type] IN ['*scpb.UniqueWithoutIndexConstraint', '*scpb.UniqueWithoutIndexConstraintUnvalidated'] + - $constraint[ReferencedColumnIDs] CONTAINS $fromColumnID + - $referenced-column-name[Type] = '*scpb.ColumnName' + - $referenced-column-name[ColumnID] = $fromColumnID + - joinOnDescID($constraint, $referenced-column-name, $table-id) + - transient($constraint-Target, $referenced-column-name-Target) + - $constraint-Node[CurrentStatus] = TRANSIENT_ABSENT + - $referenced-column-name-Node[CurrentStatus] = TRANSIENT_ABSENT + - joinTargetNode($constraint, $constraint-Target, $constraint-Node) + - joinTargetNode($referenced-column-name, $referenced-column-name-Target, $referenced-column-name-Node) +- name: unique without index constraint should be cleaned up before column name references + from: constraint-Node + kind: Precedence + to: referenced-column-name-Node + query: + - $constraint[Type] IN ['*scpb.UniqueWithoutIndexConstraint', '*scpb.UniqueWithoutIndexConstraintUnvalidated'] + - $constraint[ReferencedColumnIDs] CONTAINS $fromColumnID + - $referenced-column-name[Type] = '*scpb.ColumnName' + - $referenced-column-name[ColumnID] = $fromColumnID + - joinOnDescID($constraint, $referenced-column-name, $table-id) + - $constraint-Target[TargetStatus] = TRANSIENT_ABSENT + - $constraint-Node[CurrentStatus] = TRANSIENT_ABSENT + - $referenced-column-name-Target[TargetStatus] = ABSENT + - $referenced-column-name-Node[CurrentStatus] = ABSENT + - joinTargetNode($constraint, $constraint-Target, $constraint-Node) + - joinTargetNode($referenced-column-name, $referenced-column-name-Target, $referenced-column-name-Node) +- name: unique without index constraint should be cleaned up before column name references + from: constraint-Node + kind: Precedence + to: referenced-column-name-Node + query: + - $constraint[Type] IN ['*scpb.UniqueWithoutIndexConstraint', '*scpb.UniqueWithoutIndexConstraintUnvalidated'] + - $constraint[ReferencedColumnIDs] CONTAINS $fromColumnID + - $referenced-column-name[Type] = '*scpb.ColumnName' + - $referenced-column-name[ColumnID] = $fromColumnID + - joinOnDescID($constraint, $referenced-column-name, $table-id) + - $constraint-Target[TargetStatus] = ABSENT + - $constraint-Node[CurrentStatus] = ABSENT + - $referenced-column-name-Target[TargetStatus] = TRANSIENT_ABSENT + - $referenced-column-name-Node[CurrentStatus] = TRANSIENT_ABSENT + - joinTargetNode($constraint, $constraint-Target, $constraint-Node) + - joinTargetNode($referenced-column-name, $referenced-column-name-Target, $referenced-column-name-Node) deprules ---- @@ -7929,6 +7968,39 @@ deprules - $index-Node[CurrentStatus] = WRITE_ONLY - joinTargetNode($column, $column-Target, $column-Node) - joinTargetNode($index, $index-Target, $index-Node) +- name: column name is dropped before same name is used by different column + from: old-column-name-Node + kind: Precedence + to: new-column-name-Node + query: + - $old-column-name[Type] = '*scpb.ColumnName' + - $new-column-name[Type] = '*scpb.ColumnName' + - joinOnDescID($old-column-name, $new-column-name, $table-id) + - $old-column-name[Name] = $name + - $new-column-name[Name] = $name + - $old-column-name-Target[TargetStatus] = ABSENT + - $old-column-name-Node[CurrentStatus] = ABSENT + - $new-column-name-Target[TargetStatus] = PUBLIC + - $new-column-name-Node[CurrentStatus] = PUBLIC + - DifferentColumnIDs(*scpb.ColumnName, *scpb.ColumnName)($old-column-name, $new-column-name) + - joinTargetNode($old-column-name, $old-column-name-Target, $old-column-name-Node) + - joinTargetNode($new-column-name, $new-column-name-Target, $new-column-name-Node) +- name: column name is public before compute expression referencing it + from: column-name-Node + kind: Precedence + to: compute-expression-Node + query: + - $column-name[Type] = '*scpb.ColumnName' + - $compute-expression[Type] = '*scpb.ColumnComputeExpression' + - $column-name[ColumnID] = $columnID + - $compute-expression[ReferencedColumnIDs] CONTAINS $columnID + - joinOnDescID($column-name, $compute-expression, $table-id) + - $column-name-Target[TargetStatus] = PUBLIC + - ToPublicOrTransient($column-name-Target, $compute-expression-Target) + - $column-name-Node[CurrentStatus] = PUBLIC + - $compute-expression-Node[CurrentStatus] = PUBLIC + - joinTargetNode($column-name, $column-name-Target, $column-name-Node) + - joinTargetNode($compute-expression, $compute-expression-Target, $compute-expression-Node) - name: column name set right after column existence, except for alter column type from: column-Node kind: SameStagePrecedence @@ -8040,6 +8112,12 @@ deprules - $column-type-Target[TargetStatus] = PUBLIC - $transient-check-constraint-Node[CurrentStatus] = TRANSIENT_VALIDATED - $column-type-Node[CurrentStatus] = PUBLIC + - $column[Type] = '*scpb.Column' + - $compute-expression[Type] = '*scpb.ColumnComputeExpression' + - joinOnColumnID($column, $compute-expression, $table-id, $columnID) + - $compute-expression[Usage] = ALTER_TYPE_USING + - joinTargetNode($column, $column-Target, $column-Node) + - joinTargetNode($compute-expression, $compute-expression-Target, $compute-expression-Node) - joinTargetNode($transient-check-constraint, $transient-check-constraint-Target, $transient-check-constraint-Node) - joinTargetNode($column-type, $column-type-Target, $column-type-Node) - name: column type removed before column family @@ -9320,68 +9398,6 @@ deprules - $descriptor-Node[CurrentStatus] = ABSENT - joinTargetNode($dependent, $dependent-Target, $dependent-Node) - joinTargetNode($descriptor, $descriptor-Target, $descriptor-Node) -- name: non-indexed backed constraint should be cleaned up before column name references - from: constraint-Node - kind: Precedence - to: referenced-column-name-Node - query: - - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.CheckConstraintUnvalidated', '*scpb.UniqueWithoutIndexConstraint', '*scpb.UniqueWithoutIndexConstraintUnvalidated'] - - $constraint[ReferencedColumnIDs] CONTAINS $fromColumnID - - $referenced-column-name[Type] = '*scpb.ColumnName' - - $referenced-column-name[ColumnID] = $fromColumnID - - joinOnDescID($constraint, $referenced-column-name, $table-id) - - toAbsent($constraint-Target, $referenced-column-name-Target) - - $constraint-Node[CurrentStatus] = ABSENT - - $referenced-column-name-Node[CurrentStatus] = ABSENT - - joinTargetNode($constraint, $constraint-Target, $constraint-Node) - - joinTargetNode($referenced-column-name, $referenced-column-name-Target, $referenced-column-name-Node) -- name: non-indexed backed constraint should be cleaned up before column name references - from: constraint-Node - kind: Precedence - to: referenced-column-name-Node - query: - - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.CheckConstraintUnvalidated', '*scpb.UniqueWithoutIndexConstraint', '*scpb.UniqueWithoutIndexConstraintUnvalidated'] - - $constraint[ReferencedColumnIDs] CONTAINS $fromColumnID - - $referenced-column-name[Type] = '*scpb.ColumnName' - - $referenced-column-name[ColumnID] = $fromColumnID - - joinOnDescID($constraint, $referenced-column-name, $table-id) - - transient($constraint-Target, $referenced-column-name-Target) - - $constraint-Node[CurrentStatus] = TRANSIENT_ABSENT - - $referenced-column-name-Node[CurrentStatus] = TRANSIENT_ABSENT - - joinTargetNode($constraint, $constraint-Target, $constraint-Node) - - joinTargetNode($referenced-column-name, $referenced-column-name-Target, $referenced-column-name-Node) -- name: non-indexed backed constraint should be cleaned up before column name references - from: constraint-Node - kind: Precedence - to: referenced-column-name-Node - query: - - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.CheckConstraintUnvalidated', '*scpb.UniqueWithoutIndexConstraint', '*scpb.UniqueWithoutIndexConstraintUnvalidated'] - - $constraint[ReferencedColumnIDs] CONTAINS $fromColumnID - - $referenced-column-name[Type] = '*scpb.ColumnName' - - $referenced-column-name[ColumnID] = $fromColumnID - - joinOnDescID($constraint, $referenced-column-name, $table-id) - - $constraint-Target[TargetStatus] = TRANSIENT_ABSENT - - $constraint-Node[CurrentStatus] = TRANSIENT_ABSENT - - $referenced-column-name-Target[TargetStatus] = ABSENT - - $referenced-column-name-Node[CurrentStatus] = ABSENT - - joinTargetNode($constraint, $constraint-Target, $constraint-Node) - - joinTargetNode($referenced-column-name, $referenced-column-name-Target, $referenced-column-name-Node) -- name: non-indexed backed constraint should be cleaned up before column name references - from: constraint-Node - kind: Precedence - to: referenced-column-name-Node - query: - - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.CheckConstraintUnvalidated', '*scpb.UniqueWithoutIndexConstraint', '*scpb.UniqueWithoutIndexConstraintUnvalidated'] - - $constraint[ReferencedColumnIDs] CONTAINS $fromColumnID - - $referenced-column-name[Type] = '*scpb.ColumnName' - - $referenced-column-name[ColumnID] = $fromColumnID - - joinOnDescID($constraint, $referenced-column-name, $table-id) - - $constraint-Target[TargetStatus] = ABSENT - - $constraint-Node[CurrentStatus] = ABSENT - - $referenced-column-name-Target[TargetStatus] = TRANSIENT_ABSENT - - $referenced-column-name-Node[CurrentStatus] = TRANSIENT_ABSENT - - joinTargetNode($constraint, $constraint-Target, $constraint-Node) - - joinTargetNode($referenced-column-name, $referenced-column-name-Target, $referenced-column-name-Node) - name: old column name is dropped before new column name is added from: old-column-name-Node kind: Precedence @@ -10161,3 +10177,65 @@ deprules - $dependents-Node[CurrentStatus] = TRANSIENT_PUBLIC - joinTargetNode($trigger, $trigger-Target, $trigger-Node) - joinTargetNode($dependents, $dependents-Target, $dependents-Node) +- name: unique without index constraint should be cleaned up before column name references + from: constraint-Node + kind: Precedence + to: referenced-column-name-Node + query: + - $constraint[Type] IN ['*scpb.UniqueWithoutIndexConstraint', '*scpb.UniqueWithoutIndexConstraintUnvalidated'] + - $constraint[ReferencedColumnIDs] CONTAINS $fromColumnID + - $referenced-column-name[Type] = '*scpb.ColumnName' + - $referenced-column-name[ColumnID] = $fromColumnID + - joinOnDescID($constraint, $referenced-column-name, $table-id) + - toAbsent($constraint-Target, $referenced-column-name-Target) + - $constraint-Node[CurrentStatus] = ABSENT + - $referenced-column-name-Node[CurrentStatus] = ABSENT + - joinTargetNode($constraint, $constraint-Target, $constraint-Node) + - joinTargetNode($referenced-column-name, $referenced-column-name-Target, $referenced-column-name-Node) +- name: unique without index constraint should be cleaned up before column name references + from: constraint-Node + kind: Precedence + to: referenced-column-name-Node + query: + - $constraint[Type] IN ['*scpb.UniqueWithoutIndexConstraint', '*scpb.UniqueWithoutIndexConstraintUnvalidated'] + - $constraint[ReferencedColumnIDs] CONTAINS $fromColumnID + - $referenced-column-name[Type] = '*scpb.ColumnName' + - $referenced-column-name[ColumnID] = $fromColumnID + - joinOnDescID($constraint, $referenced-column-name, $table-id) + - transient($constraint-Target, $referenced-column-name-Target) + - $constraint-Node[CurrentStatus] = TRANSIENT_ABSENT + - $referenced-column-name-Node[CurrentStatus] = TRANSIENT_ABSENT + - joinTargetNode($constraint, $constraint-Target, $constraint-Node) + - joinTargetNode($referenced-column-name, $referenced-column-name-Target, $referenced-column-name-Node) +- name: unique without index constraint should be cleaned up before column name references + from: constraint-Node + kind: Precedence + to: referenced-column-name-Node + query: + - $constraint[Type] IN ['*scpb.UniqueWithoutIndexConstraint', '*scpb.UniqueWithoutIndexConstraintUnvalidated'] + - $constraint[ReferencedColumnIDs] CONTAINS $fromColumnID + - $referenced-column-name[Type] = '*scpb.ColumnName' + - $referenced-column-name[ColumnID] = $fromColumnID + - joinOnDescID($constraint, $referenced-column-name, $table-id) + - $constraint-Target[TargetStatus] = TRANSIENT_ABSENT + - $constraint-Node[CurrentStatus] = TRANSIENT_ABSENT + - $referenced-column-name-Target[TargetStatus] = ABSENT + - $referenced-column-name-Node[CurrentStatus] = ABSENT + - joinTargetNode($constraint, $constraint-Target, $constraint-Node) + - joinTargetNode($referenced-column-name, $referenced-column-name-Target, $referenced-column-name-Node) +- name: unique without index constraint should be cleaned up before column name references + from: constraint-Node + kind: Precedence + to: referenced-column-name-Node + query: + - $constraint[Type] IN ['*scpb.UniqueWithoutIndexConstraint', '*scpb.UniqueWithoutIndexConstraintUnvalidated'] + - $constraint[ReferencedColumnIDs] CONTAINS $fromColumnID + - $referenced-column-name[Type] = '*scpb.ColumnName' + - $referenced-column-name[ColumnID] = $fromColumnID + - joinOnDescID($constraint, $referenced-column-name, $table-id) + - $constraint-Target[TargetStatus] = ABSENT + - $constraint-Node[CurrentStatus] = ABSENT + - $referenced-column-name-Target[TargetStatus] = TRANSIENT_ABSENT + - $referenced-column-name-Node[CurrentStatus] = TRANSIENT_ABSENT + - joinTargetNode($constraint, $constraint-Target, $constraint-Node) + - joinTargetNode($referenced-column-name, $referenced-column-name-Target, $referenced-column-name-Node) diff --git a/pkg/sql/schemachanger/scplan/testdata/alter_table_alter_column_type b/pkg/sql/schemachanger/scplan/testdata/alter_table_alter_column_type index b203ba6b4f5c..3278a59687ea 100644 --- a/pkg/sql/schemachanger/scplan/testdata/alter_table_alter_column_type +++ b/pkg/sql/schemachanger/scplan/testdata/alter_table_alter_column_type @@ -57,11 +57,26 @@ PreCommitPhase stage 2 of 2 with 1 MutationType op ops ALTER TABLE defaultdb.act ALTER COLUMN c1 SET DATA TYPE SMALLINT; ---- -StatementPhase stage 1 of 1 with 1 MutationType op +StatementPhase stage 1 of 1 with 2 MutationType ops transitions: [[ColumnType:{DescID: 104, ColumnFamilyID: 0, ColumnID: 2, TypeName: INT4}, ABSENT], PUBLIC] -> ABSENT + [[ColumnType:{DescID: 104, ColumnFamilyID: 0, ColumnID: 2, TypeName: INT2}, PUBLIC], ABSENT] -> PUBLIC [[CheckConstraint:{DescID: 104, IndexID: 1, ConstraintID: 2, ReferencedColumnIDs: [2]}, TRANSIENT_ABSENT], ABSENT] -> WRITE_ONLY ops: + *scop.UpsertColumnType + ColumnType: + ColumnID: 2 + ElementCreationMetadata: + in231OrLater: true + in243OrLater: true + IsNullable: true + TableID: 104 + TypeT: + Type: + family: IntFamily + oid: 21 + width: 16 + TypeName: INT2 *scop.AddCheckConstraint CheckExpr: (CAST(CAST(c1 AS INT2) AS INT4) = c1) ColumnIDs: @@ -72,14 +87,30 @@ StatementPhase stage 1 of 1 with 1 MutationType op PreCommitPhase stage 1 of 2 with 1 MutationType op transitions: [[ColumnType:{DescID: 104, ColumnFamilyID: 0, ColumnID: 2, TypeName: INT4}, ABSENT], ABSENT] -> PUBLIC + [[ColumnType:{DescID: 104, ColumnFamilyID: 0, ColumnID: 2, TypeName: INT2}, PUBLIC], PUBLIC] -> ABSENT [[CheckConstraint:{DescID: 104, IndexID: 1, ConstraintID: 2, ReferencedColumnIDs: [2]}, TRANSIENT_ABSENT], WRITE_ONLY] -> ABSENT ops: *scop.UndoAllInTxnImmediateMutationOpSideEffects {} -PreCommitPhase stage 2 of 2 with 3 MutationType ops +PreCommitPhase stage 2 of 2 with 4 MutationType ops transitions: + [[ColumnType:{DescID: 104, ColumnFamilyID: 0, ColumnID: 2, TypeName: INT2}, PUBLIC], ABSENT] -> PUBLIC [[CheckConstraint:{DescID: 104, IndexID: 1, ConstraintID: 2, ReferencedColumnIDs: [2]}, TRANSIENT_ABSENT], ABSENT] -> WRITE_ONLY ops: + *scop.UpsertColumnType + ColumnType: + ColumnID: 2 + ElementCreationMetadata: + in231OrLater: true + in243OrLater: true + IsNullable: true + TableID: 104 + TypeT: + Type: + family: IntFamily + oid: 21 + width: 16 + TypeName: INT2 *scop.AddCheckConstraint CheckExpr: (CAST(CAST(c1 AS INT2) AS INT4) = c1) ColumnIDs: @@ -123,28 +154,13 @@ PostCommitNonRevertiblePhase stage 1 of 3 with 3 MutationType ops *scop.UpdateSchemaChangerJob IsNonCancelable: true JobID: 1 -PostCommitNonRevertiblePhase stage 2 of 3 with 4 MutationType ops +PostCommitNonRevertiblePhase stage 2 of 3 with 3 MutationType ops transitions: - [[ColumnType:{DescID: 104, ColumnFamilyID: 0, ColumnID: 2, TypeName: INT2}, PUBLIC], ABSENT] -> PUBLIC [[CheckConstraint:{DescID: 104, IndexID: 1, ConstraintID: 2, ReferencedColumnIDs: [2]}, TRANSIENT_ABSENT], PUBLIC] -> TRANSIENT_VALIDATED ops: *scop.MakePublicCheckConstraintValidated ConstraintID: 2 TableID: 104 - *scop.UpsertColumnType - ColumnType: - ColumnID: 2 - ElementCreationMetadata: - in231OrLater: true - in243OrLater: true - IsNullable: true - TableID: 104 - TypeT: - Type: - family: IntFamily - oid: 21 - width: 16 - TypeName: INT2 *scop.SetJobStateOnDescriptor DescriptorID: 104 *scop.UpdateSchemaChangerJob diff --git a/pkg/sql/schemachanger/scplan/testdata/alter_table_rename_column b/pkg/sql/schemachanger/scplan/testdata/alter_table_rename_column new file mode 100644 index 000000000000..a4805a034ee7 --- /dev/null +++ b/pkg/sql/schemachanger/scplan/testdata/alter_table_rename_column @@ -0,0 +1,272 @@ +setup +CREATE TABLE defaultdb.foo (i INT PRIMARY KEY, j INT); +---- + +ops +ALTER TABLE defaultdb.foo RENAME COLUMN j TO k +---- +StatementPhase stage 1 of 1 with 2 MutationType ops + transitions: + [[ColumnName:{DescID: 104, Name: j, ColumnID: 2}, ABSENT], PUBLIC] -> ABSENT + [[ColumnName:{DescID: 104, Name: k, ColumnID: 2}, PUBLIC], ABSENT] -> PUBLIC + ops: + *scop.SetColumnName + ColumnID: 2 + Name: crdb_internal_column_2_name_placeholder + TableID: 104 + *scop.SetColumnName + ColumnID: 2 + Name: k + TableID: 104 +PreCommitPhase stage 1 of 2 with 1 MutationType op + transitions: + [[ColumnName:{DescID: 104, Name: j, ColumnID: 2}, ABSENT], ABSENT] -> PUBLIC + [[ColumnName:{DescID: 104, Name: k, ColumnID: 2}, PUBLIC], PUBLIC] -> ABSENT + ops: + *scop.UndoAllInTxnImmediateMutationOpSideEffects + {} +PreCommitPhase stage 2 of 2 with 2 MutationType ops + transitions: + [[ColumnName:{DescID: 104, Name: j, ColumnID: 2}, ABSENT], PUBLIC] -> ABSENT + [[ColumnName:{DescID: 104, Name: k, ColumnID: 2}, PUBLIC], ABSENT] -> PUBLIC + ops: + *scop.SetColumnName + ColumnID: 2 + Name: crdb_internal_column_2_name_placeholder + TableID: 104 + *scop.SetColumnName + ColumnID: 2 + Name: k + TableID: 104 + +setup +CREATE TABLE defaultdb.bar (x INT PRIMARY KEY, y INT, z INT, INDEX idx_y (y)); +---- + +ops +ALTER TABLE defaultdb.bar RENAME COLUMN y TO y_new +---- +StatementPhase stage 1 of 1 with 2 MutationType ops + transitions: + [[ColumnName:{DescID: 105, Name: y, ColumnID: 2}, ABSENT], PUBLIC] -> ABSENT + [[ColumnName:{DescID: 105, Name: y_new, ColumnID: 2}, PUBLIC], ABSENT] -> PUBLIC + ops: + *scop.SetColumnName + ColumnID: 2 + Name: crdb_internal_column_2_name_placeholder + TableID: 105 + *scop.SetColumnName + ColumnID: 2 + Name: y_new + TableID: 105 +PreCommitPhase stage 1 of 2 with 1 MutationType op + transitions: + [[ColumnName:{DescID: 105, Name: y, ColumnID: 2}, ABSENT], ABSENT] -> PUBLIC + [[ColumnName:{DescID: 105, Name: y_new, ColumnID: 2}, PUBLIC], PUBLIC] -> ABSENT + ops: + *scop.UndoAllInTxnImmediateMutationOpSideEffects + {} +PreCommitPhase stage 2 of 2 with 2 MutationType ops + transitions: + [[ColumnName:{DescID: 105, Name: y, ColumnID: 2}, ABSENT], PUBLIC] -> ABSENT + [[ColumnName:{DescID: 105, Name: y_new, ColumnID: 2}, PUBLIC], ABSENT] -> PUBLIC + ops: + *scop.SetColumnName + ColumnID: 2 + Name: crdb_internal_column_2_name_placeholder + TableID: 105 + *scop.SetColumnName + ColumnID: 2 + Name: y_new + TableID: 105 + +setup +CREATE TABLE defaultdb.multi (a INT PRIMARY KEY, b INT, c INT); +---- + +ops +ALTER TABLE defaultdb.multi RENAME COLUMN b TO b_renamed, RENAME COLUMN c TO c_renamed +---- +StatementPhase stage 1 of 1 with 4 MutationType ops + transitions: + [[ColumnName:{DescID: 106, Name: b, ColumnID: 2}, ABSENT], PUBLIC] -> ABSENT + [[ColumnName:{DescID: 106, Name: c, ColumnID: 3}, ABSENT], PUBLIC] -> ABSENT + [[ColumnName:{DescID: 106, Name: b_renamed, ColumnID: 2}, PUBLIC], ABSENT] -> PUBLIC + [[ColumnName:{DescID: 106, Name: c_renamed, ColumnID: 3}, PUBLIC], ABSENT] -> PUBLIC + ops: + *scop.SetColumnName + ColumnID: 2 + Name: crdb_internal_column_2_name_placeholder + TableID: 106 + *scop.SetColumnName + ColumnID: 3 + Name: crdb_internal_column_3_name_placeholder + TableID: 106 + *scop.SetColumnName + ColumnID: 2 + Name: b_renamed + TableID: 106 + *scop.SetColumnName + ColumnID: 3 + Name: c_renamed + TableID: 106 +PreCommitPhase stage 1 of 2 with 1 MutationType op + transitions: + [[ColumnName:{DescID: 106, Name: b, ColumnID: 2}, ABSENT], ABSENT] -> PUBLIC + [[ColumnName:{DescID: 106, Name: c, ColumnID: 3}, ABSENT], ABSENT] -> PUBLIC + [[ColumnName:{DescID: 106, Name: b_renamed, ColumnID: 2}, PUBLIC], PUBLIC] -> ABSENT + [[ColumnName:{DescID: 106, Name: c_renamed, ColumnID: 3}, PUBLIC], PUBLIC] -> ABSENT + ops: + *scop.UndoAllInTxnImmediateMutationOpSideEffects + {} +PreCommitPhase stage 2 of 2 with 4 MutationType ops + transitions: + [[ColumnName:{DescID: 106, Name: b, ColumnID: 2}, ABSENT], PUBLIC] -> ABSENT + [[ColumnName:{DescID: 106, Name: c, ColumnID: 3}, ABSENT], PUBLIC] -> ABSENT + [[ColumnName:{DescID: 106, Name: b_renamed, ColumnID: 2}, PUBLIC], ABSENT] -> PUBLIC + [[ColumnName:{DescID: 106, Name: c_renamed, ColumnID: 3}, PUBLIC], ABSENT] -> PUBLIC + ops: + *scop.SetColumnName + ColumnID: 2 + Name: crdb_internal_column_2_name_placeholder + TableID: 106 + *scop.SetColumnName + ColumnID: 3 + Name: crdb_internal_column_3_name_placeholder + TableID: 106 + *scop.SetColumnName + ColumnID: 2 + Name: b_renamed + TableID: 106 + *scop.SetColumnName + ColumnID: 3 + Name: c_renamed + TableID: 106 + +setup +CREATE TABLE defaultdb.with_constraints ( + id INT PRIMARY KEY, + email TEXT UNIQUE, + age INT CHECK (age > 0) +); +---- + +ops +ALTER TABLE defaultdb.with_constraints RENAME COLUMN email TO email_address +---- +StatementPhase stage 1 of 1 with 2 MutationType ops + transitions: + [[ColumnName:{DescID: 107, Name: email, ColumnID: 2}, ABSENT], PUBLIC] -> ABSENT + [[ColumnName:{DescID: 107, Name: email_address, ColumnID: 2}, PUBLIC], ABSENT] -> PUBLIC + ops: + *scop.SetColumnName + ColumnID: 2 + Name: crdb_internal_column_2_name_placeholder + TableID: 107 + *scop.SetColumnName + ColumnID: 2 + Name: email_address + TableID: 107 +PreCommitPhase stage 1 of 2 with 1 MutationType op + transitions: + [[ColumnName:{DescID: 107, Name: email, ColumnID: 2}, ABSENT], ABSENT] -> PUBLIC + [[ColumnName:{DescID: 107, Name: email_address, ColumnID: 2}, PUBLIC], PUBLIC] -> ABSENT + ops: + *scop.UndoAllInTxnImmediateMutationOpSideEffects + {} +PreCommitPhase stage 2 of 2 with 2 MutationType ops + transitions: + [[ColumnName:{DescID: 107, Name: email, ColumnID: 2}, ABSENT], PUBLIC] -> ABSENT + [[ColumnName:{DescID: 107, Name: email_address, ColumnID: 2}, PUBLIC], ABSENT] -> PUBLIC + ops: + *scop.SetColumnName + ColumnID: 2 + Name: crdb_internal_column_2_name_placeholder + TableID: 107 + *scop.SetColumnName + ColumnID: 2 + Name: email_address + TableID: 107 + +setup +CREATE SCHEMA sc1; +CREATE TABLE sc1.schema_table (col1 INT PRIMARY KEY, col2 TEXT); +---- + +ops +ALTER TABLE sc1.schema_table RENAME COLUMN col2 TO column_two +---- +StatementPhase stage 1 of 1 with 2 MutationType ops + transitions: + [[ColumnName:{DescID: 109, Name: col2, ColumnID: 2}, ABSENT], PUBLIC] -> ABSENT + [[ColumnName:{DescID: 109, Name: column_two, ColumnID: 2}, PUBLIC], ABSENT] -> PUBLIC + ops: + *scop.SetColumnName + ColumnID: 2 + Name: crdb_internal_column_2_name_placeholder + TableID: 109 + *scop.SetColumnName + ColumnID: 2 + Name: column_two + TableID: 109 +PreCommitPhase stage 1 of 2 with 1 MutationType op + transitions: + [[ColumnName:{DescID: 109, Name: col2, ColumnID: 2}, ABSENT], ABSENT] -> PUBLIC + [[ColumnName:{DescID: 109, Name: column_two, ColumnID: 2}, PUBLIC], PUBLIC] -> ABSENT + ops: + *scop.UndoAllInTxnImmediateMutationOpSideEffects + {} +PreCommitPhase stage 2 of 2 with 2 MutationType ops + transitions: + [[ColumnName:{DescID: 109, Name: col2, ColumnID: 2}, ABSENT], PUBLIC] -> ABSENT + [[ColumnName:{DescID: 109, Name: column_two, ColumnID: 2}, PUBLIC], ABSENT] -> PUBLIC + ops: + *scop.SetColumnName + ColumnID: 2 + Name: crdb_internal_column_2_name_placeholder + TableID: 109 + *scop.SetColumnName + ColumnID: 2 + Name: column_two + TableID: 109 + +setup +CREATE TABLE defaultdb.computed_col (i INT PRIMARY KEY, j INT, k INT AS (i + j) STORED); +---- + +ops +ALTER TABLE defaultdb.computed_col RENAME COLUMN j TO j_new +---- +StatementPhase stage 1 of 1 with 2 MutationType ops + transitions: + [[ColumnName:{DescID: 110, Name: j, ColumnID: 2}, ABSENT], PUBLIC] -> ABSENT + [[ColumnName:{DescID: 110, Name: j_new, ColumnID: 2}, PUBLIC], ABSENT] -> PUBLIC + ops: + *scop.SetColumnName + ColumnID: 2 + Name: crdb_internal_column_2_name_placeholder + TableID: 110 + *scop.SetColumnName + ColumnID: 2 + Name: j_new + TableID: 110 +PreCommitPhase stage 1 of 2 with 1 MutationType op + transitions: + [[ColumnName:{DescID: 110, Name: j, ColumnID: 2}, ABSENT], ABSENT] -> PUBLIC + [[ColumnName:{DescID: 110, Name: j_new, ColumnID: 2}, PUBLIC], PUBLIC] -> ABSENT + ops: + *scop.UndoAllInTxnImmediateMutationOpSideEffects + {} +PreCommitPhase stage 2 of 2 with 2 MutationType ops + transitions: + [[ColumnName:{DescID: 110, Name: j, ColumnID: 2}, ABSENT], PUBLIC] -> ABSENT + [[ColumnName:{DescID: 110, Name: j_new, ColumnID: 2}, PUBLIC], ABSENT] -> PUBLIC + ops: + *scop.SetColumnName + ColumnID: 2 + Name: crdb_internal_column_2_name_placeholder + TableID: 110 + *scop.SetColumnName + ColumnID: 2 + Name: j_new + TableID: 110 diff --git a/pkg/sql/schemachanger/scplan/testdata/drop_index b/pkg/sql/schemachanger/scplan/testdata/drop_index index 2d79b469b6d5..8f27f6caf5cb 100644 --- a/pkg/sql/schemachanger/scplan/testdata/drop_index +++ b/pkg/sql/schemachanger/scplan/testdata/drop_index @@ -549,10 +549,6 @@ PostCommitNonRevertiblePhase stage 3 of 3 with 4 MutationType ops deps DROP INDEX idx3 CASCADE ---- -- from: [CheckConstraint:{DescID: 105, IndexID: 0, ConstraintID: 3, ReferencedColumnIDs: [5]}, ABSENT] - to: [ColumnName:{DescID: 105, Name: crdb_internal_i_shard_16, ColumnID: 5}, ABSENT] - kind: Precedence - rule: non-indexed backed constraint should be cleaned up before column name references - from: [CheckConstraint:{DescID: 105, IndexID: 0, ConstraintID: 3, ReferencedColumnIDs: [5]}, PUBLIC] to: [CheckConstraint:{DescID: 105, IndexID: 0, ConstraintID: 3, ReferencedColumnIDs: [5]}, VALIDATED] kind: PreviousTransactionPrecedence diff --git a/pkg/sql/schemachanger/sctest_generated_test.go b/pkg/sql/schemachanger/sctest_generated_test.go index 8afee7fff1ac..18b81f07cf6d 100644 --- a/pkg/sql/schemachanger/sctest_generated_test.go +++ b/pkg/sql/schemachanger/sctest_generated_test.go @@ -456,6 +456,13 @@ func TestEndToEndSideEffects_alter_table_rename_column(t *testing.T) { sctest.EndToEndSideEffects(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestEndToEndSideEffects_alter_table_rename_multiple_columns(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns" + sctest.EndToEndSideEffects(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestEndToEndSideEffects_alter_table_validate_constraint(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1212,6 +1219,13 @@ func TestExecuteWithDMLInjection_alter_table_rename_column(t *testing.T) { sctest.ExecuteWithDMLInjection(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestExecuteWithDMLInjection_alter_table_rename_multiple_columns(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns" + sctest.ExecuteWithDMLInjection(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestExecuteWithDMLInjection_alter_table_validate_constraint(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1968,6 +1982,13 @@ func TestGenerateSchemaChangeCorpus_alter_table_rename_column(t *testing.T) { sctest.GenerateSchemaChangeCorpus(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestGenerateSchemaChangeCorpus_alter_table_rename_multiple_columns(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns" + sctest.GenerateSchemaChangeCorpus(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestGenerateSchemaChangeCorpus_alter_table_validate_constraint(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -2724,6 +2745,13 @@ func TestPause_alter_table_rename_column(t *testing.T) { sctest.Pause(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestPause_alter_table_rename_multiple_columns(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns" + sctest.Pause(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestPause_alter_table_validate_constraint(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -3480,6 +3508,13 @@ func TestPauseMixedVersion_alter_table_rename_column(t *testing.T) { sctest.PauseMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestPauseMixedVersion_alter_table_rename_multiple_columns(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns" + sctest.PauseMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestPauseMixedVersion_alter_table_validate_constraint(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -4236,6 +4271,13 @@ func TestRollback_alter_table_rename_column(t *testing.T) { sctest.Rollback(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestRollback_alter_table_rename_multiple_columns(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns" + sctest.Rollback(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestRollback_alter_table_validate_constraint(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) diff --git a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_1_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_1_of_7.explain index f7bfff5bf291..1544cfe6195e 100644 --- a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_1_of_7.explain +++ b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_1_of_7.explain @@ -24,19 +24,19 @@ Schema change plan for rolling back ALTER TABLE defaultdb.public.t DROP COLUMN i │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (i-), IndexID: 2 (t_pkey-)} │ │ └── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (i-), IndexID: 3} │ └── 15 Mutation operations - │ ├── SetColumnName {"ColumnID":1,"Name":"i","TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"TableID":104} │ ├── SetColumnName {"ColumnID":3,"Name":"crdb_internal_co...","TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":1,"Kind":2,"Ordinal":1,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":2,"Kind":2,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":3,"Kind":2,"TableID":104} - │ ├── MakeWriteOnlyColumnPublic {"ColumnID":1,"TableID":104} - │ ├── RefreshStats {"TableID":104} + │ ├── SetColumnName {"ColumnID":1,"Name":"i","TableID":104} │ ├── MakeIndexAbsent {"IndexID":2,"TableID":104} │ ├── CreateGCJobForIndex {"IndexID":2,"TableID":104} │ ├── MakeIndexAbsent {"IndexID":3,"TableID":104} │ ├── MakeDeleteOnlyColumnAbsent {"ColumnID":3,"TableID":104} + │ ├── MakeWriteOnlyColumnPublic {"ColumnID":1,"TableID":104} + │ ├── RefreshStats {"TableID":104} │ ├── SetJobStateOnDescriptor {"DescriptorID":104} │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"Pending: Updatin..."} └── Stage 2 of 2 in PostCommitNonRevertiblePhase diff --git a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_2_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_2_of_7.explain index 75dbc36620f5..4da5cae92969 100644 --- a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_2_of_7.explain +++ b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_2_of_7.explain @@ -22,7 +22,6 @@ Schema change plan for rolling back ALTER TABLE defaultdb.public.t DROP COLUMN i │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (i-), IndexID: 2 (t_pkey-)} │ │ └── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (i-), IndexID: 3} │ └── 14 Mutation operations - │ ├── SetColumnName {"ColumnID":1,"Name":"i","TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"TableID":104} │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"TableID":104} @@ -31,9 +30,10 @@ Schema change plan for rolling back ALTER TABLE defaultdb.public.t DROP COLUMN i │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":1,"Kind":2,"Ordinal":1,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":2,"Kind":2,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":3,"Kind":2,"TableID":104} + │ ├── SetColumnName {"ColumnID":1,"Name":"i","TableID":104} + │ ├── MakeIndexAbsent {"IndexID":2,"TableID":104} │ ├── MakeWriteOnlyColumnPublic {"ColumnID":1,"TableID":104} │ ├── RefreshStats {"TableID":104} - │ ├── MakeIndexAbsent {"IndexID":2,"TableID":104} │ ├── SetJobStateOnDescriptor {"DescriptorID":104} │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"Pending: Updatin..."} ├── Stage 2 of 3 in PostCommitNonRevertiblePhase diff --git a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_3_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_3_of_7.explain index ba679bc01eb9..3d2cf9bcdf51 100644 --- a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_3_of_7.explain +++ b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_3_of_7.explain @@ -22,7 +22,6 @@ Schema change plan for rolling back ALTER TABLE defaultdb.public.t DROP COLUMN i │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (i-), IndexID: 2 (t_pkey-)} │ │ └── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (i-), IndexID: 3} │ └── 14 Mutation operations - │ ├── SetColumnName {"ColumnID":1,"Name":"i","TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"TableID":104} │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"TableID":104} @@ -31,9 +30,10 @@ Schema change plan for rolling back ALTER TABLE defaultdb.public.t DROP COLUMN i │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":1,"Kind":2,"Ordinal":1,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":2,"Kind":2,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":3,"Kind":2,"TableID":104} + │ ├── SetColumnName {"ColumnID":1,"Name":"i","TableID":104} + │ ├── MakeIndexAbsent {"IndexID":2,"TableID":104} │ ├── MakeWriteOnlyColumnPublic {"ColumnID":1,"TableID":104} │ ├── RefreshStats {"TableID":104} - │ ├── MakeIndexAbsent {"IndexID":2,"TableID":104} │ ├── SetJobStateOnDescriptor {"DescriptorID":104} │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"Pending: Updatin..."} ├── Stage 2 of 3 in PostCommitNonRevertiblePhase diff --git a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_4_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_4_of_7.explain index 154c0fc6a736..938970a40d78 100644 --- a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_4_of_7.explain +++ b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_4_of_7.explain @@ -22,7 +22,6 @@ Schema change plan for rolling back ALTER TABLE defaultdb.public.t DROP COLUMN i │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (i-), IndexID: 2 (t_pkey-)} │ │ └── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (i-), IndexID: 3} │ └── 14 Mutation operations - │ ├── SetColumnName {"ColumnID":1,"Name":"i","TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"TableID":104} │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"TableID":104} @@ -31,9 +30,10 @@ Schema change plan for rolling back ALTER TABLE defaultdb.public.t DROP COLUMN i │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":1,"Kind":2,"Ordinal":1,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":2,"Kind":2,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":3,"Kind":2,"TableID":104} + │ ├── SetColumnName {"ColumnID":1,"Name":"i","TableID":104} + │ ├── MakeIndexAbsent {"IndexID":2,"TableID":104} │ ├── MakeWriteOnlyColumnPublic {"ColumnID":1,"TableID":104} │ ├── RefreshStats {"TableID":104} - │ ├── MakeIndexAbsent {"IndexID":2,"TableID":104} │ ├── SetJobStateOnDescriptor {"DescriptorID":104} │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"Pending: Updatin..."} ├── Stage 2 of 3 in PostCommitNonRevertiblePhase diff --git a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_5_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_5_of_7.explain index 875e6621aaab..12f225ad164e 100644 --- a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_5_of_7.explain +++ b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_5_of_7.explain @@ -22,18 +22,18 @@ Schema change plan for rolling back ALTER TABLE defaultdb.public.t DROP COLUMN i │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (i-), IndexID: 2 (t_pkey-)} │ │ └── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (i-), IndexID: 3} │ └── 14 Mutation operations - │ ├── SetColumnName {"ColumnID":1,"Name":"i","TableID":104} │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"TableID":104} │ ├── MakeWriteOnlyColumnDeleteOnly {"ColumnID":3,"TableID":104} │ ├── SetColumnName {"ColumnID":3,"Name":"crdb_internal_co...","TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":1,"Kind":2,"Ordinal":1,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":3,"Kind":2,"TableID":104} - │ ├── MakeWriteOnlyColumnPublic {"ColumnID":1,"TableID":104} - │ ├── RefreshStats {"TableID":104} + │ ├── SetColumnName {"ColumnID":1,"Name":"i","TableID":104} │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":2,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":2,"Kind":2,"TableID":104} + │ ├── MakeWriteOnlyColumnPublic {"ColumnID":1,"TableID":104} + │ ├── RefreshStats {"TableID":104} │ ├── SetJobStateOnDescriptor {"DescriptorID":104} │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"Pending: Updatin..."} ├── Stage 2 of 3 in PostCommitNonRevertiblePhase diff --git a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_6_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_6_of_7.explain index bb0a44caae7b..5a972420325a 100644 --- a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_6_of_7.explain +++ b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_6_of_7.explain @@ -22,18 +22,18 @@ Schema change plan for rolling back ALTER TABLE defaultdb.public.t DROP COLUMN i │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (i-), IndexID: 2 (t_pkey-)} │ │ └── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (i-), IndexID: 3} │ └── 14 Mutation operations - │ ├── SetColumnName {"ColumnID":1,"Name":"i","TableID":104} │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"TableID":104} │ ├── MakeWriteOnlyColumnDeleteOnly {"ColumnID":3,"TableID":104} │ ├── SetColumnName {"ColumnID":3,"Name":"crdb_internal_co...","TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":1,"Kind":2,"Ordinal":1,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":3,"Kind":2,"TableID":104} - │ ├── MakeWriteOnlyColumnPublic {"ColumnID":1,"TableID":104} - │ ├── RefreshStats {"TableID":104} + │ ├── SetColumnName {"ColumnID":1,"Name":"i","TableID":104} │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":2,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":2,"Kind":2,"TableID":104} + │ ├── MakeWriteOnlyColumnPublic {"ColumnID":1,"TableID":104} + │ ├── RefreshStats {"TableID":104} │ ├── SetJobStateOnDescriptor {"DescriptorID":104} │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"Pending: Updatin..."} ├── Stage 2 of 3 in PostCommitNonRevertiblePhase diff --git a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_7_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_7_of_7.explain index 3dcb298bd85c..28ffcb667b42 100644 --- a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_7_of_7.explain +++ b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_drop_add_same_col_implicit/alter_table_drop_add_same_col_implicit__rollback_7_of_7.explain @@ -22,7 +22,6 @@ Schema change plan for rolling back ALTER TABLE defaultdb.public.t DROP COLUMN i │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (i-), IndexID: 2 (t_pkey-)} │ │ └── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (i-), IndexID: 3} │ └── 14 Mutation operations - │ ├── SetColumnName {"ColumnID":1,"Name":"i","TableID":104} │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":2,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"TableID":104} @@ -31,9 +30,10 @@ Schema change plan for rolling back ALTER TABLE defaultdb.public.t DROP COLUMN i │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":1,"Kind":2,"Ordinal":1,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":2,"Kind":2,"TableID":104} │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":3,"Kind":2,"TableID":104} + │ ├── SetColumnName {"ColumnID":1,"Name":"i","TableID":104} + │ ├── MakeIndexAbsent {"IndexID":3,"TableID":104} │ ├── MakeWriteOnlyColumnPublic {"ColumnID":1,"TableID":104} │ ├── RefreshStats {"TableID":104} - │ ├── MakeIndexAbsent {"IndexID":3,"TableID":104} │ ├── SetJobStateOnDescriptor {"DescriptorID":104} │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"Pending: Updatin..."} ├── Stage 2 of 3 in PostCommitNonRevertiblePhase diff --git a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns/alter_table_rename_multiple_columns.definition b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns/alter_table_rename_multiple_columns.definition new file mode 100644 index 000000000000..27399ca9a396 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns/alter_table_rename_multiple_columns.definition @@ -0,0 +1,7 @@ +setup +CREATE TABLE t (i INT PRIMARY KEY, j INT, k INT); +---- + +test +ALTER TABLE t RENAME COLUMN j TO j_old, RENAME COLUMN k TO j, ADD COLUMN k INT AS (j + 1) STORED; +---- diff --git a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns/alter_table_rename_multiple_columns.explain b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns/alter_table_rename_multiple_columns.explain new file mode 100644 index 000000000000..608bcd91c045 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns/alter_table_rename_multiple_columns.explain @@ -0,0 +1,257 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j INT, k INT); + +/* test */ +EXPLAIN (DDL) ALTER TABLE t RENAME COLUMN j TO j_old, RENAME COLUMN k TO j, ADD COLUMN k INT AS (j + 1) STORED; +---- +Schema change plan for ALTER TABLE ‹defaultdb›.‹public›.‹t› RENAME COLUMN ‹j› TO ‹j_old›, RENAME COLUMN ‹k› TO ‹j›, ADD COLUMN ‹k› INT8 AS (‹j› + ‹1›) STORED; + ├── StatementPhase + │ └── Stage 1 of 1 in StatementPhase + │ ├── 12 elements transitioning toward PUBLIC + │ │ ├── ABSENT → PUBLIC ColumnName:{DescID: 104 (t), Name: "j_old", ColumnID: 2 (j-j_old+)} + │ │ ├── ABSENT → PUBLIC ColumnName:{DescID: 104 (t), Name: "j", ColumnID: 3 (k-j+)} + │ │ ├── ABSENT → DELETE_ONLY Column:{DescID: 104 (t), ColumnID: 4 (k+)} + │ │ ├── ABSENT → PUBLIC ColumnName:{DescID: 104 (t), Name: "k", ColumnID: 4 (k+)} + │ │ ├── ABSENT → PUBLIC ColumnType:{DescID: 104 (t), ColumnFamilyID: 0 (primary), ColumnID: 4 (k+), TypeName: "INT8"} + │ │ ├── ABSENT → PUBLIC ColumnComputeExpression:{DescID: 104 (t), ColumnID: 4 (k+), ReferencedColumnIDs: [3], Usage: REGULAR} + │ │ ├── ABSENT → BACKFILL_ONLY PrimaryIndex:{DescID: 104 (t), IndexID: 2 (t_pkey+), ConstraintID: 3, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey-)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 2 (t_pkey+)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 2 (j-j_old+), IndexID: 2 (t_pkey+)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 3 (k-j+), IndexID: 2 (t_pkey+)} + │ │ ├── ABSENT → PUBLIC IndexData:{DescID: 104 (t), IndexID: 2 (t_pkey+)} + │ │ └── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 4 (k+), IndexID: 2 (t_pkey+)} + │ ├── 6 elements transitioning toward TRANSIENT_ABSENT + │ │ ├── ABSENT → WRITE_ONLY CheckConstraint:{DescID: 104 (t), IndexID: 2 (t_pkey+), ConstraintID: 2, ReferencedColumnIDs: [3]} + │ │ ├── ABSENT → DELETE_ONLY TemporaryIndex:{DescID: 104 (t), IndexID: 3, ConstraintID: 4, SourceIndexID: 1 (t_pkey-)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 2 (j-j_old+), IndexID: 3} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 3 (k-j+), IndexID: 3} + │ │ └── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 4 (k+), IndexID: 3} + │ ├── 1 element transitioning toward TRANSIENT_PUBLIC + │ │ └── PUBLIC → ABSENT TableSchemaLocked:{DescID: 104 (t)} + │ ├── 2 elements transitioning toward ABSENT + │ │ ├── PUBLIC → ABSENT ColumnName:{DescID: 104 (t), Name: "j", ColumnID: 2 (j-j_old+)} + │ │ └── PUBLIC → ABSENT ColumnName:{DescID: 104 (t), Name: "k", ColumnID: 3 (k-j+)} + │ └── 20 Mutation operations + │ ├── SetTableSchemaLocked {"TableID":104} + │ ├── AddCheckConstraint {"CheckExpr":"CASE WHEN (crdb_...","ConstraintID":2,"TableID":104,"Validity":2} + │ ├── MakeAbsentColumnDeleteOnly {"Column":{"ColumnID":4,"TableID":104}} + │ ├── UpsertColumnType {"ColumnType":{"ColumnID":4,"IsNullable":true,"TableID":104}} + │ ├── MakeAbsentIndexBackfilling {"Index":{"ConstraintID":3,"IndexID":2,"IsUnique":true,"SourceIndexID":1,"TableID":104,"TemporaryIndexID":3}} + │ ├── AddColumnToIndex {"ColumnID":1,"IndexID":2,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":2,"IndexID":2,"Kind":2,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":3,"IndexID":2,"Kind":2,"Ordinal":1,"TableID":104} + │ ├── MakeAbsentTempIndexDeleteOnly {"Index":{"ConstraintID":4,"IndexID":3,"IsUnique":true,"SourceIndexID":1,"TableID":104}} + │ ├── AddColumnToIndex {"ColumnID":1,"IndexID":3,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":2,"IndexID":3,"Kind":2,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":3,"IndexID":3,"Kind":2,"Ordinal":1,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":4,"IndexID":2,"Kind":2,"Ordinal":2,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":4,"IndexID":3,"Kind":2,"Ordinal":2,"TableID":104} + │ ├── SetColumnName {"ColumnID":2,"Name":"crdb_internal_co...","TableID":104} + │ ├── SetColumnName {"ColumnID":3,"Name":"crdb_internal_co...","TableID":104} + │ ├── SetColumnName {"ColumnID":2,"Name":"j_old","TableID":104} + │ ├── SetColumnName {"ColumnID":3,"Name":"j","TableID":104} + │ ├── SetColumnName {"ColumnID":4,"Name":"k","TableID":104} + │ └── AddColumnComputeExpression {"ComputeExpression":{"ColumnID":4,"TableID":104}} + ├── PreCommitPhase + │ ├── Stage 1 of 2 in PreCommitPhase + │ │ ├── 12 elements transitioning toward PUBLIC + │ │ │ ├── PUBLIC → ABSENT ColumnName:{DescID: 104 (t), Name: "j_old", ColumnID: 2 (j-j_old+)} + │ │ │ ├── PUBLIC → ABSENT ColumnName:{DescID: 104 (t), Name: "j", ColumnID: 3 (k-j+)} + │ │ │ ├── DELETE_ONLY → ABSENT Column:{DescID: 104 (t), ColumnID: 4 (k+)} + │ │ │ ├── PUBLIC → ABSENT ColumnName:{DescID: 104 (t), Name: "k", ColumnID: 4 (k+)} + │ │ │ ├── PUBLIC → ABSENT ColumnType:{DescID: 104 (t), ColumnFamilyID: 0 (primary), ColumnID: 4 (k+), TypeName: "INT8"} + │ │ │ ├── PUBLIC → ABSENT ColumnComputeExpression:{DescID: 104 (t), ColumnID: 4 (k+), ReferencedColumnIDs: [3], Usage: REGULAR} + │ │ │ ├── BACKFILL_ONLY → ABSENT PrimaryIndex:{DescID: 104 (t), IndexID: 2 (t_pkey+), ConstraintID: 3, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey-)} + │ │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 2 (t_pkey+)} + │ │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j-j_old+), IndexID: 2 (t_pkey+)} + │ │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (k-j+), IndexID: 2 (t_pkey+)} + │ │ │ ├── PUBLIC → ABSENT IndexData:{DescID: 104 (t), IndexID: 2 (t_pkey+)} + │ │ │ └── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 4 (k+), IndexID: 2 (t_pkey+)} + │ │ ├── 6 elements transitioning toward TRANSIENT_ABSENT + │ │ │ ├── WRITE_ONLY → ABSENT CheckConstraint:{DescID: 104 (t), IndexID: 2 (t_pkey+), ConstraintID: 2, ReferencedColumnIDs: [3]} + │ │ │ ├── DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 104 (t), IndexID: 3, ConstraintID: 4, SourceIndexID: 1 (t_pkey-)} + │ │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3} + │ │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j-j_old+), IndexID: 3} + │ │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (k-j+), IndexID: 3} + │ │ │ └── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 4 (k+), IndexID: 3} + │ │ ├── 1 element transitioning toward TRANSIENT_PUBLIC + │ │ │ └── ABSENT → PUBLIC TableSchemaLocked:{DescID: 104 (t)} + │ │ ├── 2 elements transitioning toward ABSENT + │ │ │ ├── ABSENT → PUBLIC ColumnName:{DescID: 104 (t), Name: "j", ColumnID: 2 (j-j_old+)} + │ │ │ └── ABSENT → PUBLIC ColumnName:{DescID: 104 (t), Name: "k", ColumnID: 3 (k-j+)} + │ │ └── 1 Mutation operation + │ │ └── UndoAllInTxnImmediateMutationOpSideEffects + │ └── Stage 2 of 2 in PreCommitPhase + │ ├── 12 elements transitioning toward PUBLIC + │ │ ├── ABSENT → PUBLIC ColumnName:{DescID: 104 (t), Name: "j_old", ColumnID: 2 (j-j_old+)} + │ │ ├── ABSENT → PUBLIC ColumnName:{DescID: 104 (t), Name: "j", ColumnID: 3 (k-j+)} + │ │ ├── ABSENT → DELETE_ONLY Column:{DescID: 104 (t), ColumnID: 4 (k+)} + │ │ ├── ABSENT → PUBLIC ColumnName:{DescID: 104 (t), Name: "k", ColumnID: 4 (k+)} + │ │ ├── ABSENT → PUBLIC ColumnType:{DescID: 104 (t), ColumnFamilyID: 0 (primary), ColumnID: 4 (k+), TypeName: "INT8"} + │ │ ├── ABSENT → PUBLIC ColumnComputeExpression:{DescID: 104 (t), ColumnID: 4 (k+), ReferencedColumnIDs: [3], Usage: REGULAR} + │ │ ├── ABSENT → BACKFILL_ONLY PrimaryIndex:{DescID: 104 (t), IndexID: 2 (t_pkey+), ConstraintID: 3, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey-)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 2 (t_pkey+)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 2 (j-j_old+), IndexID: 2 (t_pkey+)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 3 (k-j+), IndexID: 2 (t_pkey+)} + │ │ ├── ABSENT → PUBLIC IndexData:{DescID: 104 (t), IndexID: 2 (t_pkey+)} + │ │ └── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 4 (k+), IndexID: 2 (t_pkey+)} + │ ├── 6 elements transitioning toward TRANSIENT_ABSENT + │ │ ├── ABSENT → WRITE_ONLY CheckConstraint:{DescID: 104 (t), IndexID: 2 (t_pkey+), ConstraintID: 2, ReferencedColumnIDs: [3]} + │ │ ├── ABSENT → DELETE_ONLY TemporaryIndex:{DescID: 104 (t), IndexID: 3, ConstraintID: 4, SourceIndexID: 1 (t_pkey-)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 2 (j-j_old+), IndexID: 3} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 3 (k-j+), IndexID: 3} + │ │ └── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 4 (k+), IndexID: 3} + │ ├── 1 element transitioning toward TRANSIENT_PUBLIC + │ │ └── PUBLIC → ABSENT TableSchemaLocked:{DescID: 104 (t)} + │ ├── 2 elements transitioning toward ABSENT + │ │ ├── PUBLIC → ABSENT ColumnName:{DescID: 104 (t), Name: "j", ColumnID: 2 (j-j_old+)} + │ │ └── PUBLIC → ABSENT ColumnName:{DescID: 104 (t), Name: "k", ColumnID: 3 (k-j+)} + │ └── 24 Mutation operations + │ ├── SetTableSchemaLocked {"TableID":104} + │ ├── AddCheckConstraint {"CheckExpr":"CASE WHEN (crdb_...","ConstraintID":2,"TableID":104,"Validity":2} + │ ├── MakeAbsentColumnDeleteOnly {"Column":{"ColumnID":4,"TableID":104}} + │ ├── UpsertColumnType {"ColumnType":{"ColumnID":4,"IsNullable":true,"TableID":104}} + │ ├── MakeAbsentIndexBackfilling {"Index":{"ConstraintID":3,"IndexID":2,"IsUnique":true,"SourceIndexID":1,"TableID":104,"TemporaryIndexID":3}} + │ ├── MaybeAddSplitForIndex {"IndexID":2,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":1,"IndexID":2,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":2,"IndexID":2,"Kind":2,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":3,"IndexID":2,"Kind":2,"Ordinal":1,"TableID":104} + │ ├── MakeAbsentTempIndexDeleteOnly {"Index":{"ConstraintID":4,"IndexID":3,"IsUnique":true,"SourceIndexID":1,"TableID":104}} + │ ├── MaybeAddSplitForIndex {"IndexID":3,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":1,"IndexID":3,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":2,"IndexID":3,"Kind":2,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":3,"IndexID":3,"Kind":2,"Ordinal":1,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":4,"IndexID":2,"Kind":2,"Ordinal":2,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":4,"IndexID":3,"Kind":2,"Ordinal":2,"TableID":104} + │ ├── SetColumnName {"ColumnID":2,"Name":"crdb_internal_co...","TableID":104} + │ ├── SetColumnName {"ColumnID":3,"Name":"crdb_internal_co...","TableID":104} + │ ├── SetColumnName {"ColumnID":2,"Name":"j_old","TableID":104} + │ ├── SetColumnName {"ColumnID":3,"Name":"j","TableID":104} + │ ├── SetColumnName {"ColumnID":4,"Name":"k","TableID":104} + │ ├── AddColumnComputeExpression {"ComputeExpression":{"ColumnID":4,"TableID":104}} + │ ├── SetJobStateOnDescriptor {"DescriptorID":104,"Initialize":true} + │ └── CreateSchemaChangerJob {"RunningStatus":"Pending: Updatin..."} + ├── PostCommitPhase + │ ├── Stage 1 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── DELETE_ONLY → WRITE_ONLY Column:{DescID: 104 (t), ColumnID: 4 (k+)} + │ │ ├── 2 elements transitioning toward TRANSIENT_ABSENT + │ │ │ ├── DELETE_ONLY → WRITE_ONLY TemporaryIndex:{DescID: 104 (t), IndexID: 3, ConstraintID: 4, SourceIndexID: 1 (t_pkey-)} + │ │ │ └── ABSENT → PUBLIC IndexData:{DescID: 104 (t), IndexID: 3} + │ │ └── 4 Mutation operations + │ │ ├── MakeDeleteOnlyColumnWriteOnly {"ColumnID":4,"TableID":104} + │ │ ├── MakeDeleteOnlyIndexWriteOnly {"IndexID":3,"TableID":104} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ │ └── UpdateSchemaChangerJob {"RunningStatus":"Pending: Backfil..."} + │ ├── Stage 2 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── BACKFILL_ONLY → BACKFILLED PrimaryIndex:{DescID: 104 (t), IndexID: 2 (t_pkey+), ConstraintID: 3, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey-)} + │ │ └── 1 Backfill operation + │ │ └── BackfillIndex {"IndexID":2,"SourceIndexID":1,"TableID":104} + │ ├── Stage 3 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── BACKFILLED → DELETE_ONLY PrimaryIndex:{DescID: 104 (t), IndexID: 2 (t_pkey+), ConstraintID: 3, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey-)} + │ │ └── 3 Mutation operations + │ │ ├── MakeBackfillingIndexDeleteOnly {"IndexID":2,"TableID":104} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ │ └── UpdateSchemaChangerJob {"RunningStatus":"Pending: Updatin..."} + │ ├── Stage 4 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── DELETE_ONLY → MERGE_ONLY PrimaryIndex:{DescID: 104 (t), IndexID: 2 (t_pkey+), ConstraintID: 3, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey-)} + │ │ └── 3 Mutation operations + │ │ ├── MakeBackfilledIndexMerging {"IndexID":2,"TableID":104} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ │ └── UpdateSchemaChangerJob {"RunningStatus":"Pending: Merging..."} + │ ├── Stage 5 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── MERGE_ONLY → MERGED PrimaryIndex:{DescID: 104 (t), IndexID: 2 (t_pkey+), ConstraintID: 3, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey-)} + │ │ └── 1 Backfill operation + │ │ └── MergeIndex {"BackfilledIndexID":2,"TableID":104,"TemporaryIndexID":3} + │ ├── Stage 6 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── MERGED → WRITE_ONLY PrimaryIndex:{DescID: 104 (t), IndexID: 2 (t_pkey+), ConstraintID: 3, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey-)} + │ │ ├── 1 element transitioning toward TRANSIENT_ABSENT + │ │ │ └── WRITE_ONLY → TRANSIENT_DELETE_ONLY TemporaryIndex:{DescID: 104 (t), IndexID: 3, ConstraintID: 4, SourceIndexID: 1 (t_pkey-)} + │ │ └── 4 Mutation operations + │ │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":104} + │ │ ├── MakeMergedIndexWriteOnly {"IndexID":2,"TableID":104} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ │ └── UpdateSchemaChangerJob {"RunningStatus":"Pending: Validat..."} + │ └── Stage 7 of 7 in PostCommitPhase + │ ├── 1 element transitioning toward PUBLIC + │ │ └── WRITE_ONLY → VALIDATED PrimaryIndex:{DescID: 104 (t), IndexID: 2 (t_pkey+), ConstraintID: 3, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey-)} + │ ├── 1 element transitioning toward TRANSIENT_ABSENT + │ │ └── WRITE_ONLY → VALIDATED CheckConstraint:{DescID: 104 (t), IndexID: 2 (t_pkey+), ConstraintID: 2, ReferencedColumnIDs: [3]} + │ └── 2 Validation operations + │ ├── ValidateIndex {"IndexID":2,"TableID":104} + │ └── ValidateConstraint {"ConstraintID":2,"IndexIDForValidation":2,"TableID":104} + └── PostCommitNonRevertiblePhase + ├── Stage 1 of 4 in PostCommitNonRevertiblePhase + │ ├── 3 elements transitioning toward PUBLIC + │ │ ├── WRITE_ONLY → PUBLIC Column:{DescID: 104 (t), ColumnID: 4 (k+)} + │ │ ├── VALIDATED → PUBLIC PrimaryIndex:{DescID: 104 (t), IndexID: 2 (t_pkey+), ConstraintID: 3, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey-)} + │ │ └── ABSENT → PUBLIC IndexName:{DescID: 104 (t), Name: "t_pkey", IndexID: 2 (t_pkey+)} + │ ├── 6 elements transitioning toward TRANSIENT_ABSENT + │ │ ├── VALIDATED → PUBLIC CheckConstraint:{DescID: 104 (t), IndexID: 2 (t_pkey+), ConstraintID: 2, ReferencedColumnIDs: [3]} + │ │ ├── TRANSIENT_DELETE_ONLY → TRANSIENT_ABSENT TemporaryIndex:{DescID: 104 (t), IndexID: 3, ConstraintID: 4, SourceIndexID: 1 (t_pkey-)} + │ │ ├── PUBLIC → TRANSIENT_ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3} + │ │ ├── PUBLIC → TRANSIENT_ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j-j_old+), IndexID: 3} + │ │ ├── PUBLIC → TRANSIENT_ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (k-j+), IndexID: 3} + │ │ └── PUBLIC → TRANSIENT_ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 4 (k+), IndexID: 3} + │ ├── 2 elements transitioning toward ABSENT + │ │ ├── PUBLIC → VALIDATED PrimaryIndex:{DescID: 104 (t), IndexID: 1 (t_pkey-), ConstraintID: 1} + │ │ └── PUBLIC → ABSENT IndexName:{DescID: 104 (t), Name: "t_pkey", IndexID: 1 (t_pkey-)} + │ └── 14 Mutation operations + │ ├── MakePublicPrimaryIndexWriteOnly {"IndexID":1,"TableID":104} + │ ├── SetIndexName {"IndexID":1,"Name":"crdb_internal_in...","TableID":104} + │ ├── MakeValidatedCheckConstraintPublic {"ConstraintID":2,"TableID":104} + │ ├── SetIndexName {"IndexID":2,"Name":"t_pkey","TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"Kind":2,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":3,"Kind":2,"Ordinal":1,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":4,"IndexID":3,"Kind":2,"Ordinal":2,"TableID":104} + │ ├── MakeValidatedPrimaryIndexPublic {"IndexID":2,"TableID":104} + │ ├── MakeIndexAbsent {"IndexID":3,"TableID":104} + │ ├── MakeWriteOnlyColumnPublic {"ColumnID":4,"TableID":104} + │ ├── RefreshStats {"TableID":104} + │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"Pending: Updatin..."} + ├── Stage 2 of 4 in PostCommitNonRevertiblePhase + │ ├── 1 element transitioning toward TRANSIENT_ABSENT + │ │ └── PUBLIC → TRANSIENT_VALIDATED CheckConstraint:{DescID: 104 (t), IndexID: 2 (t_pkey+), ConstraintID: 2, ReferencedColumnIDs: [3]} + │ ├── 4 elements transitioning toward ABSENT + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 1 (t_pkey-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j-j_old+), IndexID: 1 (t_pkey-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 3 (k-j+), IndexID: 1 (t_pkey-)} + │ │ └── VALIDATED → DELETE_ONLY PrimaryIndex:{DescID: 104 (t), IndexID: 1 (t_pkey-), ConstraintID: 1} + │ └── 7 Mutation operations + │ ├── MakePublicCheckConstraintValidated {"ConstraintID":2,"TableID":104} + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":1,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":1,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":1,"Kind":2,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":3,"IndexID":1,"Kind":2,"Ordinal":1,"TableID":104} + │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"Pending: Updatin..."} + ├── Stage 3 of 4 in PostCommitNonRevertiblePhase + │ ├── 2 elements transitioning toward TRANSIENT_ABSENT + │ │ ├── TRANSIENT_VALIDATED → TRANSIENT_ABSENT CheckConstraint:{DescID: 104 (t), IndexID: 2 (t_pkey+), ConstraintID: 2, ReferencedColumnIDs: [3]} + │ │ └── PUBLIC → TRANSIENT_ABSENT IndexData:{DescID: 104 (t), IndexID: 3} + │ ├── 2 elements transitioning toward ABSENT + │ │ ├── DELETE_ONLY → ABSENT PrimaryIndex:{DescID: 104 (t), IndexID: 1 (t_pkey-), ConstraintID: 1} + │ │ └── PUBLIC → ABSENT IndexData:{DescID: 104 (t), IndexID: 1 (t_pkey-)} + │ └── 6 Mutation operations + │ ├── MakeIndexAbsent {"IndexID":1,"TableID":104} + │ ├── CreateGCJobForIndex {"IndexID":1,"TableID":104} + │ ├── RemoveCheckConstraint {"ConstraintID":2,"TableID":104} + │ ├── CreateGCJobForIndex {"IndexID":3,"TableID":104} + │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"Pending: Updatin..."} + └── Stage 4 of 4 in PostCommitNonRevertiblePhase + ├── 1 element transitioning toward TRANSIENT_PUBLIC + │ └── ABSENT → TRANSIENT_PUBLIC TableSchemaLocked:{DescID: 104 (t)} + └── 3 Mutation operations + ├── SetTableSchemaLocked {"Locked":true,"TableID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":104} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns/alter_table_rename_multiple_columns.explain_shape b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns/alter_table_rename_multiple_columns.explain_shape new file mode 100644 index 000000000000..98c67c3fe70d --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns/alter_table_rename_multiple_columns.explain_shape @@ -0,0 +1,17 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j INT, k INT); + +/* test */ +EXPLAIN (DDL, SHAPE) ALTER TABLE t RENAME COLUMN j TO j_old, RENAME COLUMN k TO j, ADD COLUMN k INT AS (j + 1) STORED; +---- +Schema change plan for ALTER TABLE ‹defaultdb›.‹public›.‹t› RENAME COLUMN ‹j› TO ‹j_old›, RENAME COLUMN ‹k› TO ‹j›, ADD COLUMN ‹k› INT8 AS (‹j› + ‹1›) STORED; + ├── execute 2 system table mutations transactions + ├── backfill using primary index t_pkey- in relation t + │ └── into t_pkey+ (i; j-j_old+, k-j+, k+) + ├── execute 2 system table mutations transactions + ├── merge temporary indexes into backfilled indexes in relation t + │ └── from t@[3] into t_pkey+ + ├── execute 1 system table mutations transaction + ├── validate UNIQUE constraint backed by index t_pkey+ in relation t + ├── validate non-index-backed constraint t.[constraint 2] in relation t + └── execute 4 system table mutations transactions diff --git a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns/alter_table_rename_multiple_columns.side_effects b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns/alter_table_rename_multiple_columns.side_effects new file mode 100644 index 000000000000..d09cd8c89170 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_rename_multiple_columns/alter_table_rename_multiple_columns.side_effects @@ -0,0 +1,819 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j INT, k INT); +---- +... ++object {100 101 t} -> 104 + +/* test */ +ALTER TABLE t RENAME COLUMN j TO j_old, RENAME COLUMN k TO j, ADD COLUMN k INT AS (j + 1) STORED; +---- +begin transaction #1 +# begin StatementPhase +checking for feature: ALTER TABLE +increment telemetry for sql.schema.alter_table +increment telemetry for sql.schema.alter_table.rename_column +increment telemetry for sql.schema.alter_table.rename_column +increment telemetry for sql.schema.alter_table.add_column +increment telemetry for sql.schema.qualifcation.computed +increment telemetry for sql.schema.new_column_type.int8 +write *eventpb.AlterTable to event log: + mutationId: 1 + sql: + descriptorId: 104 + statement: ALTER TABLE ‹defaultdb›.‹public›.‹t› RENAME COLUMN ‹j› TO ‹j_old›, RENAME COLUMN ‹k› TO ‹j›, ADD COLUMN ‹k› INT8 AS (‹j› + ‹1›) STORED + tag: ALTER TABLE + user: root + tableName: defaultdb.public.t +## StatementPhase stage 1 of 1 with 20 MutationType ops +upsert descriptor #104 + table: + + checks: + + - columnIds: + + - 1 + + - 2 + + - 3 + + constraintId: 2 + + expr: CASE WHEN (crdb_internal.assignment_cast(j_old + 1:::INT8, NULL::INT8)) IS NULL THEN true ELSE true END + + name: crdb_internal_constraint_2_name_placeholder + + validity: Validating + columns: + - id: 1 + ... + width: 64 + - id: 2 + - name: j + + name: j_old + nullable: true + type: + ... + width: 64 + - id: 3 + - name: k + + name: j + nullable: true + type: + ... + - 2 + - 3 + + - 4 + columnNames: + - i + + - j_old + - j + - k + ... + id: 104 + modificationTime: {} + + mutations: + + - constraint: + + check: + + columnIds: + + - 1 + + - 2 + + - 3 + + constraintId: 2 + + expr: CASE WHEN (crdb_internal.assignment_cast(j_old + 1:::INT8, NULL::INT8)) IS NULL THEN true ELSE true END + + name: crdb_internal_constraint_2_name_placeholder + + validity: Validating + + foreignKey: {} + + name: crdb_internal_constraint_2_name_placeholder + + uniqueWithoutIndexConstraint: {} + + direction: ADD + + mutationId: 1 + + state: WRITE_ONLY + + - column: + + computeExpr: j + 1:::INT8 + + id: 4 + + name: k + + nullable: true + + type: + + family: IntFamily + + oid: 20 + + width: 64 + + direction: ADD + + mutationId: 1 + + state: DELETE_ONLY + + - direction: ADD + + index: + + constraintId: 3 + + createdExplicitly: true + + encodingType: 1 + + foreignKey: {} + + geoConfig: {} + + id: 2 + + interleave: {} + + keyColumnDirections: + + - ASC + + keyColumnIds: + + - 1 + + keyColumnNames: + + - i + + name: crdb_internal_index_2_name_placeholder + + partitioning: {} + + sharded: {} + + storeColumnIds: + + - 2 + + - 3 + + - 4 + + storeColumnNames: + + - j_old + + - j + + - k + + unique: true + + vecConfig: {} + + version: 4 + + mutationId: 1 + + state: BACKFILLING + + - direction: ADD + + index: + + constraintId: 4 + + createdExplicitly: true + + encodingType: 1 + + foreignKey: {} + + geoConfig: {} + + id: 3 + + interleave: {} + + keyColumnDirections: + + - ASC + + keyColumnIds: + + - 1 + + keyColumnNames: + + - i + + name: crdb_internal_index_3_name_placeholder + + partitioning: {} + + sharded: {} + + storeColumnIds: + + - 2 + + - 3 + + - 4 + + storeColumnNames: + + - j_old + + - j + + - k + + unique: true + + useDeletePreservingEncoding: true + + vecConfig: {} + + version: 4 + + mutationId: 1 + + state: DELETE_ONLY + name: t + - nextColumnId: 4 + - nextConstraintId: 2 + + nextColumnId: 5 + + nextConstraintId: 5 + nextFamilyId: 1 + - nextIndexId: 2 + + nextIndexId: 4 + nextMutationId: 1 + parentId: 100 + ... + - 3 + storeColumnNames: + + - j_old + - j + - - k + unique: true + vecConfig: {} + ... + replacementOf: + time: {} + - schemaLocked: true + unexposedParentSchemaId: 101 + - version: "1" + + version: "2" +# end StatementPhase +# begin PreCommitPhase +## PreCommitPhase stage 1 of 2 with 1 MutationType op +undo all catalog changes within txn #1 +persist all catalog changes to storage +## PreCommitPhase stage 2 of 2 with 24 MutationType ops +upsert descriptor #104 + table: + + checks: + + - columnIds: + + - 1 + + - 2 + + - 3 + + constraintId: 2 + + expr: CASE WHEN (crdb_internal.assignment_cast(j_old + 1:::INT8, NULL::INT8)) IS NULL THEN true ELSE true END + + name: crdb_internal_constraint_2_name_placeholder + + validity: Validating + columns: + - id: 1 + ... + width: 64 + - id: 2 + - name: j + + name: j_old + nullable: true + type: + ... + width: 64 + - id: 3 + - name: k + + name: j + nullable: true + type: + ... + createAsOfTime: + wallTime: "1640995200000000000" + + declarativeSchemaChangerState: + + authorization: + + userName: root + + currentStatuses: + + jobId: "1" + + nameMapping: + + columns: + + "1": i + + "2": j_old + + "3": j + + "4": k + + "4294967292": crdb_internal_origin_timestamp + + "4294967293": crdb_internal_origin_id + + "4294967294": tableoid + + "4294967295": crdb_internal_mvcc_timestamp + + families: + + "0": primary + + id: 104 + + indexes: + + "2": t_pkey + + name: t + + relevantStatements: + + - statement: + + redactedStatement: ALTER TABLE ‹defaultdb›.‹public›.‹t› RENAME COLUMN ‹j› TO ‹j_old›, RENAME COLUMN ‹k› TO ‹j›, ADD COLUMN ‹k› INT8 AS (‹j› + ‹1›) STORED + + statement: ALTER TABLE t RENAME COLUMN j TO j_old, RENAME COLUMN k TO j, ADD COLUMN k INT8 AS (j + 1) STORED + + statementTag: ALTER TABLE + + revertible: true + + targetRanks: + + targets: + families: + - columnIds: + ... + - 2 + - 3 + + - 4 + columnNames: + - i + + - j_old + - j + - k + ... + id: 104 + modificationTime: {} + + mutations: + + - constraint: + + check: + + columnIds: + + - 1 + + - 2 + + - 3 + + constraintId: 2 + + expr: CASE WHEN (crdb_internal.assignment_cast(j_old + 1:::INT8, NULL::INT8)) IS NULL THEN true ELSE true END + + name: crdb_internal_constraint_2_name_placeholder + + validity: Validating + + foreignKey: {} + + name: crdb_internal_constraint_2_name_placeholder + + uniqueWithoutIndexConstraint: {} + + direction: ADD + + mutationId: 1 + + state: WRITE_ONLY + + - column: + + computeExpr: j + 1:::INT8 + + id: 4 + + name: k + + nullable: true + + type: + + family: IntFamily + + oid: 20 + + width: 64 + + direction: ADD + + mutationId: 1 + + state: DELETE_ONLY + + - direction: ADD + + index: + + constraintId: 3 + + createdExplicitly: true + + encodingType: 1 + + foreignKey: {} + + geoConfig: {} + + id: 2 + + interleave: {} + + keyColumnDirections: + + - ASC + + keyColumnIds: + + - 1 + + keyColumnNames: + + - i + + name: crdb_internal_index_2_name_placeholder + + partitioning: {} + + sharded: {} + + storeColumnIds: + + - 2 + + - 3 + + - 4 + + storeColumnNames: + + - j_old + + - j + + - k + + unique: true + + vecConfig: {} + + version: 4 + + mutationId: 1 + + state: BACKFILLING + + - direction: ADD + + index: + + constraintId: 4 + + createdExplicitly: true + + encodingType: 1 + + foreignKey: {} + + geoConfig: {} + + id: 3 + + interleave: {} + + keyColumnDirections: + + - ASC + + keyColumnIds: + + - 1 + + keyColumnNames: + + - i + + name: crdb_internal_index_3_name_placeholder + + partitioning: {} + + sharded: {} + + storeColumnIds: + + - 2 + + - 3 + + - 4 + + storeColumnNames: + + - j_old + + - j + + - k + + unique: true + + useDeletePreservingEncoding: true + + vecConfig: {} + + version: 4 + + mutationId: 1 + + state: DELETE_ONLY + name: t + - nextColumnId: 4 + - nextConstraintId: 2 + + nextColumnId: 5 + + nextConstraintId: 5 + nextFamilyId: 1 + - nextIndexId: 2 + + nextIndexId: 4 + nextMutationId: 1 + parentId: 100 + ... + - 3 + storeColumnNames: + + - j_old + - j + - - k + unique: true + vecConfig: {} + ... + replacementOf: + time: {} + - schemaLocked: true + unexposedParentSchemaId: 101 + - version: "1" + + version: "2" +persist all catalog changes to storage +create job #1 (non-cancelable: false): "ALTER TABLE defaultdb.public.t RENAME COLUMN j TO j_old, RENAME COLUMN k TO j, ADD COLUMN k INT8 AS (j + 1) STORED" + descriptor IDs: [104] +# end PreCommitPhase +commit transaction #1 +notified job registry to adopt jobs: [1] +# begin PostCommitPhase +begin transaction #2 +commit transaction #2 +begin transaction #3 +## PostCommitPhase stage 1 of 7 with 4 MutationType ops +upsert descriptor #104 + ... + direction: ADD + mutationId: 1 + - state: DELETE_ONLY + + state: WRITE_ONLY + - direction: ADD + index: + ... + version: 4 + mutationId: 1 + - state: DELETE_ONLY + + state: WRITE_ONLY + name: t + nextColumnId: 5 + ... + time: {} + unexposedParentSchemaId: 101 + - version: "2" + + version: "3" +persist all catalog changes to storage +update progress of schema change job #1: "Pending: Backfilling index (1 operation) — PostCommit phase (stage 2 of 7)." +commit transaction #3 +begin transaction #4 +## PostCommitPhase stage 2 of 7 with 1 BackfillType op +backfill indexes [2] from index #1 in table #104 +commit transaction #4 +begin transaction #5 +## PostCommitPhase stage 3 of 7 with 3 MutationType ops +upsert descriptor #104 + ... + version: 4 + mutationId: 1 + - state: BACKFILLING + + state: DELETE_ONLY + - direction: ADD + index: + ... + time: {} + unexposedParentSchemaId: 101 + - version: "3" + + version: "4" +persist all catalog changes to storage +update progress of schema change job #1: "Pending: Updating schema metadata (1 operation) — PostCommit phase (stage 4 of 7)." +commit transaction #5 +begin transaction #6 +## PostCommitPhase stage 4 of 7 with 3 MutationType ops +upsert descriptor #104 + ... + version: 4 + mutationId: 1 + - state: DELETE_ONLY + + state: MERGING + - direction: ADD + index: + ... + time: {} + unexposedParentSchemaId: 101 + - version: "4" + + version: "5" +persist all catalog changes to storage +update progress of schema change job #1: "Pending: Merging index (1 operation) — PostCommit phase (stage 5 of 7)." +commit transaction #6 +begin transaction #7 +## PostCommitPhase stage 5 of 7 with 1 BackfillType op +merge temporary indexes [3] into backfilled indexes [2] in table #104 +commit transaction #7 +begin transaction #8 +## PostCommitPhase stage 6 of 7 with 4 MutationType ops +upsert descriptor #104 + ... + version: 4 + mutationId: 1 + - state: MERGING + - - direction: ADD + + state: WRITE_ONLY + + - direction: DROP + index: + constraintId: 4 + ... + version: 4 + mutationId: 1 + - state: WRITE_ONLY + + state: DELETE_ONLY + name: t + nextColumnId: 5 + ... + time: {} + unexposedParentSchemaId: 101 + - version: "5" + + version: "6" +persist all catalog changes to storage +update progress of schema change job #1: "Pending: Validating CHECK constraint (1 operation); Validating index (1 operation) — PostCommit phase (stage 7 of 7)." +commit transaction #8 +begin transaction #9 +## PostCommitPhase stage 7 of 7 with 2 ValidationType ops +validate forward indexes [2] in table #104 +validate CHECK constraint crdb_internal_constraint_2_name_placeholder in table #104 +commit transaction #9 +begin transaction #10 +## PostCommitNonRevertiblePhase stage 1 of 4 with 14 MutationType ops +upsert descriptor #104 + ... + expr: CASE WHEN (crdb_internal.assignment_cast(j_old + 1:::INT8, NULL::INT8)) IS NULL THEN true ELSE true END + name: crdb_internal_constraint_2_name_placeholder + - validity: Validating + columns: + - id: 1 + ... + oid: 20 + width: 64 + + - computeExpr: j + 1:::INT8 + + id: 4 + + name: k + + nullable: true + + type: + + family: IntFamily + + oid: 20 + + width: 64 + createAsOfTime: + wallTime: "1640995200000000000" + ... + statement: ALTER TABLE t RENAME COLUMN j TO j_old, RENAME COLUMN k TO j, ADD COLUMN k INT8 AS (j + 1) STORED + statementTag: ALTER TABLE + - revertible: true + targetRanks: + targets: + ... + modificationTime: {} + mutations: + - - constraint: + - check: + - columnIds: + - - 1 + - - 2 + - - 3 + - constraintId: 2 + - expr: CASE WHEN (crdb_internal.assignment_cast(j_old + 1:::INT8, NULL::INT8)) IS NULL THEN true ELSE true END + - name: crdb_internal_constraint_2_name_placeholder + - validity: Validating + - foreignKey: {} + - name: crdb_internal_constraint_2_name_placeholder + - uniqueWithoutIndexConstraint: {} + - direction: ADD + - mutationId: 1 + - state: WRITE_ONLY + - - column: + - computeExpr: j + 1:::INT8 + - id: 4 + - name: k + - nullable: true + - type: + - family: IntFamily + - oid: 20 + - width: 64 + - direction: ADD + - mutationId: 1 + - state: WRITE_ONLY + - - direction: ADD + - index: + - constraintId: 3 + - createdExplicitly: true + - encodingType: 1 + - foreignKey: {} + - geoConfig: {} + - id: 2 + - interleave: {} + - keyColumnDirections: + - - ASC + - keyColumnIds: + - - 1 + - keyColumnNames: + - - i + - name: crdb_internal_index_2_name_placeholder + - partitioning: {} + - sharded: {} + - storeColumnIds: + - - 2 + - - 3 + - - 4 + - storeColumnNames: + - - j_old + - - j + - - k + - unique: true + - vecConfig: {} + - version: 4 + - mutationId: 1 + - state: WRITE_ONLY + - direction: DROP + index: + - constraintId: 4 + - createdExplicitly: true + + constraintId: 1 + + createdAtNanos: "1640995200000000000" + encodingType: 1 + foreignKey: {} + geoConfig: {} + - id: 3 + + id: 1 + interleave: {} + keyColumnDirections: + ... + keyColumnNames: + - i + - name: crdb_internal_index_3_name_placeholder + + name: crdb_internal_index_1_name_placeholder + partitioning: {} + sharded: {} + ... + - 2 + - 3 + - - 4 + storeColumnNames: + - j_old + - j + - - k + unique: true + - useDeletePreservingEncoding: true + vecConfig: {} + version: 4 + mutationId: 1 + - state: DELETE_ONLY + + state: WRITE_ONLY + name: t + nextColumnId: 5 + ... + parentId: 100 + primaryIndex: + - constraintId: 1 + - createdAtNanos: "1640995200000000000" + + constraintId: 3 + + createdExplicitly: true + encodingType: 1 + foreignKey: {} + geoConfig: {} + - id: 1 + + id: 2 + interleave: {} + keyColumnDirections: + ... + - 2 + - 3 + + - 4 + storeColumnNames: + - j_old + - j + + - k + unique: true + vecConfig: {} + ... + time: {} + unexposedParentSchemaId: 101 + - version: "6" + + version: "7" +persist all catalog changes to storage +adding table for stats refresh: 104 +update progress of schema change job #1: "Pending: Updating schema metadata (5 operations) — PostCommitNonRevertible phase (stage 2 of 4)." +set schema change job #1 to non-cancellable +commit transaction #10 +begin transaction #11 +## PostCommitNonRevertiblePhase stage 2 of 4 with 7 MutationType ops +upsert descriptor #104 + ... + expr: CASE WHEN (crdb_internal.assignment_cast(j_old + 1:::INT8, NULL::INT8)) IS NULL THEN true ELSE true END + name: crdb_internal_constraint_2_name_placeholder + + validity: Dropping + columns: + - id: 1 + ... + version: 4 + mutationId: 1 + + state: DELETE_ONLY + + - constraint: + + check: + + columnIds: + + - 1 + + - 2 + + - 3 + + constraintId: 2 + + expr: CASE WHEN (crdb_internal.assignment_cast(j_old + 1:::INT8, NULL::INT8)) IS NULL THEN true ELSE true END + + name: crdb_internal_constraint_2_name_placeholder + + validity: Dropping + + foreignKey: {} + + name: crdb_internal_constraint_2_name_placeholder + + uniqueWithoutIndexConstraint: {} + + direction: DROP + + mutationId: 1 + state: WRITE_ONLY + name: t + ... + time: {} + unexposedParentSchemaId: 101 + - version: "7" + + version: "8" +persist all catalog changes to storage +update progress of schema change job #1: "Pending: Updating schema metadata (4 operations) — PostCommitNonRevertible phase (stage 3 of 4)." +commit transaction #11 +begin transaction #12 +## PostCommitNonRevertiblePhase stage 3 of 4 with 6 MutationType ops +upsert descriptor #104 + table: + - checks: + - - columnIds: + - - 1 + - - 2 + - - 3 + - constraintId: 2 + - expr: CASE WHEN (crdb_internal.assignment_cast(j_old + 1:::INT8, NULL::INT8)) IS NULL THEN true ELSE true END + - name: crdb_internal_constraint_2_name_placeholder + - validity: Dropping + + checks: [] + columns: + - id: 1 + ... + id: 104 + modificationTime: {} + - mutations: + - - direction: DROP + - index: + - constraintId: 1 + - createdAtNanos: "1640995200000000000" + - encodingType: 1 + - foreignKey: {} + - geoConfig: {} + - id: 1 + - interleave: {} + - keyColumnDirections: + - - ASC + - keyColumnIds: + - - 1 + - keyColumnNames: + - - i + - name: crdb_internal_index_1_name_placeholder + - partitioning: {} + - sharded: {} + - storeColumnIds: + - - 2 + - - 3 + - storeColumnNames: + - - j_old + - - j + - unique: true + - vecConfig: {} + - version: 4 + - mutationId: 1 + - state: DELETE_ONLY + - - constraint: + - check: + - columnIds: + - - 1 + - - 2 + - - 3 + - constraintId: 2 + - expr: CASE WHEN (crdb_internal.assignment_cast(j_old + 1:::INT8, NULL::INT8)) IS NULL THEN true ELSE true END + - name: crdb_internal_constraint_2_name_placeholder + - validity: Dropping + - foreignKey: {} + - name: crdb_internal_constraint_2_name_placeholder + - uniqueWithoutIndexConstraint: {} + - direction: DROP + - mutationId: 1 + - state: WRITE_ONLY + + mutations: [] + name: t + nextColumnId: 5 + ... + time: {} + unexposedParentSchemaId: 101 + - version: "8" + + version: "9" +persist all catalog changes to storage +create job #2 (non-cancelable: true): "GC for ALTER TABLE defaultdb.public.t RENAME COLUMN j TO j_old, RENAME COLUMN k TO j, ADD COLUMN k INT8 AS (j + 1) STORED" + descriptor IDs: [104] +update progress of schema change job #1: "Pending: Updating schema metadata (1 operation) — PostCommitNonRevertible phase (stage 4 of 4)." +commit transaction #12 +notified job registry to adopt jobs: [2] +begin transaction #13 +## PostCommitNonRevertiblePhase stage 4 of 4 with 3 MutationType ops +upsert descriptor #104 + ... + createAsOfTime: + wallTime: "1640995200000000000" + - declarativeSchemaChangerState: + - authorization: + - userName: root + - currentStatuses: + - jobId: "1" + - nameMapping: + - columns: + - "1": i + - "2": j_old + - "3": j + - "4": k + - "4294967292": crdb_internal_origin_timestamp + - "4294967293": crdb_internal_origin_id + - "4294967294": tableoid + - "4294967295": crdb_internal_mvcc_timestamp + - families: + - "0": primary + - id: 104 + - indexes: + - "2": t_pkey + - name: t + - relevantStatements: + - - statement: + - redactedStatement: ALTER TABLE ‹defaultdb›.‹public›.‹t› RENAME COLUMN ‹j› TO ‹j_old›, RENAME COLUMN ‹k› TO ‹j›, ADD COLUMN ‹k› INT8 AS (‹j› + ‹1›) STORED + - statement: ALTER TABLE t RENAME COLUMN j TO j_old, RENAME COLUMN k TO j, ADD COLUMN k INT8 AS (j + 1) STORED + - statementTag: ALTER TABLE + - targetRanks: + - targets: + families: + - columnIds: + ... + replacementOf: + time: {} + + schemaLocked: true + unexposedParentSchemaId: 101 + - version: "9" + + version: "10" +persist all catalog changes to storage +update progress of schema change job #1: "all stages completed" +set schema change job #1 to non-cancellable +updated schema change job #1 descriptor IDs to [] +write *eventpb.FinishSchemaChange to event log: + sc: + descriptorId: 104 +commit transaction #13 +# end PostCommitPhase