diff --git a/pkg/ccl/schemachangerccl/backup_base_generated_test.go b/pkg/ccl/schemachangerccl/backup_base_generated_test.go index 4e5e35c7ea38..e7e01bc8dc67 100644 --- a/pkg/ccl/schemachangerccl/backup_base_generated_test.go +++ b/pkg/ccl/schemachangerccl/backup_base_generated_test.go @@ -53,6 +53,13 @@ func TestBackupRollbacks_base_add_column_no_default(t *testing.T) { sctest.BackupRollbacks(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupRollbacks_base_add_column_serial(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/add_column_serial" + sctest.BackupRollbacks(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupRollbacks_base_add_column_virtual_not_null(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -557,6 +564,13 @@ func TestBackupRollbacksMixedVersion_base_add_column_no_default(t *testing.T) { sctest.BackupRollbacksMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupRollbacksMixedVersion_base_add_column_serial(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/add_column_serial" + sctest.BackupRollbacksMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupRollbacksMixedVersion_base_add_column_virtual_not_null(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1061,6 +1075,13 @@ func TestBackupSuccess_base_add_column_no_default(t *testing.T) { sctest.BackupSuccess(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupSuccess_base_add_column_serial(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/add_column_serial" + sctest.BackupSuccess(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupSuccess_base_add_column_virtual_not_null(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1565,6 +1586,13 @@ func TestBackupSuccessMixedVersion_base_add_column_no_default(t *testing.T) { sctest.BackupSuccessMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupSuccessMixedVersion_base_add_column_serial(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/add_column_serial" + sctest.BackupSuccessMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupSuccessMixedVersion_base_add_column_virtual_not_null(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) diff --git a/pkg/kv/kvserver/tenantrate/limiter_test.go b/pkg/kv/kvserver/tenantrate/limiter_test.go index ea3d079a271c..e4029155c76a 100644 --- a/pkg/kv/kvserver/tenantrate/limiter_test.go +++ b/pkg/kv/kvserver/tenantrate/limiter_test.go @@ -668,7 +668,7 @@ func (ts *testState) BindReader(tenantcapabilities.Reader) {} var _ tenantcapabilities.Authorizer = &testState{} -func (ts *testState) HasCrossTenantRead(tenID roachpb.TenantID) bool { +func (ts *testState) HasCrossTenantRead(ctx context.Context, tenID roachpb.TenantID) bool { return false } @@ -790,7 +790,7 @@ type fakeAuthorizer struct{} var _ tenantcapabilities.Authorizer = &fakeAuthorizer{} -func (fakeAuthorizer) HasCrossTenantRead(tenID roachpb.TenantID) bool { +func (fakeAuthorizer) HasCrossTenantRead(ctx context.Context, tenID roachpb.TenantID) bool { return false } diff --git a/pkg/multitenant/tenantcapabilities/interfaces.go b/pkg/multitenant/tenantcapabilities/interfaces.go index 62b17dd34474..4565c28de0c2 100644 --- a/pkg/multitenant/tenantcapabilities/interfaces.go +++ b/pkg/multitenant/tenantcapabilities/interfaces.go @@ -42,7 +42,7 @@ type Reader interface { // usage pattern over a timespan. type Authorizer interface { // HasCrossTenantRead returns true if a tenant can read other tenant spans. - HasCrossTenantRead(tenID roachpb.TenantID) bool + HasCrossTenantRead(ctx context.Context, tenID roachpb.TenantID) bool // HasCapabilityForBatch returns an error if a tenant, referenced by its ID, // is not allowed to execute the supplied batch request given the capabilities diff --git a/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/allow_everything.go b/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/allow_everything.go index 14c236ccd306..51d02e67f1cb 100644 --- a/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/allow_everything.go +++ b/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/allow_everything.go @@ -30,7 +30,9 @@ func NewAllowEverythingAuthorizer() *AllowEverythingAuthorizer { } // HasCrossTenantRead returns true if a tenant can read from other tenants. -func (n *AllowEverythingAuthorizer) HasCrossTenantRead(tenID roachpb.TenantID) bool { +func (n *AllowEverythingAuthorizer) HasCrossTenantRead( + ctx context.Context, tenID roachpb.TenantID, +) bool { return true } diff --git a/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/allow_nothing.go b/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/allow_nothing.go index 8fb0fc170bd2..2af86695ecaf 100644 --- a/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/allow_nothing.go +++ b/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/allow_nothing.go @@ -31,7 +31,9 @@ func NewAllowNothingAuthorizer() *AllowNothingAuthorizer { } // HasCrossTenantRead returns true if a tenant can read from other tenants. -func (n *AllowNothingAuthorizer) HasCrossTenantRead(tenID roachpb.TenantID) bool { +func (n *AllowNothingAuthorizer) HasCrossTenantRead( + ctx context.Context, tenID roachpb.TenantID, +) bool { return false } diff --git a/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/authorizer.go b/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/authorizer.go index f66fb9c78ef9..41c214909167 100644 --- a/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/authorizer.go +++ b/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/authorizer.go @@ -98,8 +98,22 @@ func New(settings *cluster.Settings, knobs *tenantcapabilities.TestingKnobs) *Au } // HasCrossTenantRead returns true if a tenant can read from other tenants. -func (a *Authorizer) HasCrossTenantRead(tenID roachpb.TenantID) bool { - return tenID.IsSystem() +func (a *Authorizer) HasCrossTenantRead(ctx context.Context, tenID roachpb.TenantID) bool { + if tenID.IsSystem() { + // The system tenant has access to all request types. + return true + } + _, mode := a.getMode(ctx, tenID) + switch mode { + case authorizerModeOn, authorizerModeV222: + return false + case authorizerModeAllowAll: + return true + default: + err := errors.AssertionFailedf("unknown authorizer mode: %d", mode) + logcrash.ReportOrPanic(ctx, &a.settings.SV, "%v", err) + return false + } } // HasCapabilityForBatch implements the tenantcapabilities.Authorizer interface. diff --git a/pkg/rpc/auth_tenant.go b/pkg/rpc/auth_tenant.go index 1b7374587a5d..84f9c055d98a 100644 --- a/pkg/rpc/auth_tenant.go +++ b/pkg/rpc/auth_tenant.go @@ -64,7 +64,7 @@ func (a tenantAuthorizer) authorize( return a.authBatch(ctx, sv, tenID, req.(*kvpb.BatchRequest)) case "/cockroach.roachpb.Internal/RangeLookup": - return a.authRangeLookup(tenID, req.(*kvpb.RangeLookupRequest)) + return a.authRangeLookup(ctx, tenID, req.(*kvpb.RangeLookupRequest)) case "/cockroach.roachpb.Internal/RangeFeed", "/cockroach.roachpb.Internal/MuxRangeFeed": return a.authRangeFeed(tenID, req.(*kvpb.RangeFeedRequest)) @@ -123,22 +123,22 @@ func (a tenantAuthorizer) authorize( return a.authTenant(tenID) case "/cockroach.server.serverpb.Status/SpanStats": - return a.authSpanStats(tenID, req.(*roachpb.SpanStatsRequest)) + return a.authSpanStats(ctx, tenID, req.(*roachpb.SpanStatsRequest)) case "/cockroach.roachpb.Internal/GetSpanConfigs": - return a.authGetSpanConfigs(tenID, req.(*roachpb.GetSpanConfigsRequest)) + return a.authGetSpanConfigs(ctx, tenID, req.(*roachpb.GetSpanConfigsRequest)) case "/cockroach.roachpb.Internal/SpanConfigConformance": - return a.authSpanConfigConformance(tenID, req.(*roachpb.SpanConfigConformanceRequest)) + return a.authSpanConfigConformance(ctx, tenID, req.(*roachpb.SpanConfigConformanceRequest)) case "/cockroach.roachpb.Internal/GetAllSystemSpanConfigsThatApply": return a.authGetAllSystemSpanConfigsThatApply(tenID, req.(*roachpb.GetAllSystemSpanConfigsThatApplyRequest)) case "/cockroach.roachpb.Internal/UpdateSpanConfigs": - return a.authUpdateSpanConfigs(tenID, req.(*roachpb.UpdateSpanConfigsRequest)) + return a.authUpdateSpanConfigs(ctx, tenID, req.(*roachpb.UpdateSpanConfigsRequest)) case "/cockroach.roachpb.Internal/GetRangeDescriptors": - return a.authGetRangeDescriptors(tenID, req.(*kvpb.GetRangeDescriptorsRequest)) + return a.authGetRangeDescriptors(ctx, tenID, req.(*kvpb.GetRangeDescriptorsRequest)) case "/cockroach.server.serverpb.Status/HotRangesV2": return a.authHotRangesV2(tenID) @@ -205,7 +205,7 @@ func (a tenantAuthorizer) authBatch( tenSpan := tenantPrefix(tenID) if outsideTenant(rSpan, tenSpan) { - if args.IsReadOnly() && a.capabilitiesAuthorizer.HasCrossTenantRead(tenID) { + if args.IsReadOnly() && a.capabilitiesAuthorizer.HasCrossTenantRead(ctx, tenID) { return nil } return spanErr(rSpan, tenSpan) @@ -214,16 +214,16 @@ func (a tenantAuthorizer) authBatch( } func (a tenantAuthorizer) authGetRangeDescriptors( - tenID roachpb.TenantID, args *kvpb.GetRangeDescriptorsRequest, + ctx context.Context, tenID roachpb.TenantID, args *kvpb.GetRangeDescriptorsRequest, ) error { - return validateSpan(tenID, args.Span, true, a) + return validateSpan(ctx, tenID, args.Span, true, a) } func (a tenantAuthorizer) authSpanStats( - tenID roachpb.TenantID, args *roachpb.SpanStatsRequest, + ctx context.Context, tenID roachpb.TenantID, args *roachpb.SpanStatsRequest, ) error { for _, span := range args.Spans { - err := validateSpan(tenID, span, true, a) + err := validateSpan(ctx, tenID, span, true, a) if err != nil { return err } @@ -234,12 +234,12 @@ func (a tenantAuthorizer) authSpanStats( // authRangeLookup authorizes the provided tenant to invoke the RangeLookup RPC // with the provided args. func (a tenantAuthorizer) authRangeLookup( - tenID roachpb.TenantID, args *kvpb.RangeLookupRequest, + ctx context.Context, tenID roachpb.TenantID, args *kvpb.RangeLookupRequest, ) error { tenSpan := tenantPrefix(tenID) if !tenSpan.ContainsKey(args.Key) { // Allow it anyway if the tenant can read other tenants. - if a.capabilitiesAuthorizer.HasCrossTenantRead(tenID) { + if a.capabilitiesAuthorizer.HasCrossTenantRead(ctx, tenID) { return nil } return authErrorf("requested key %s not fully contained in tenant keyspace %s", args.Key, tenSpan) @@ -357,10 +357,10 @@ func (a tenantAuthorizer) authGetAllSystemSpanConfigsThatApply( // authGetSpanConfigs authorizes the provided tenant to invoke the // GetSpanConfigs RPC with the provided args. func (a tenantAuthorizer) authGetSpanConfigs( - tenID roachpb.TenantID, args *roachpb.GetSpanConfigsRequest, + ctx context.Context, tenID roachpb.TenantID, args *roachpb.GetSpanConfigsRequest, ) error { for _, target := range args.Targets { - if err := validateSpanConfigTarget(tenID, target, true, a); err != nil { + if err := validateSpanConfigTarget(ctx, tenID, target, true, a); err != nil { return err } } @@ -370,15 +370,15 @@ func (a tenantAuthorizer) authGetSpanConfigs( // authUpdateSpanConfigs authorizes the provided tenant to invoke the // UpdateSpanConfigs RPC with the provided args. func (a tenantAuthorizer) authUpdateSpanConfigs( - tenID roachpb.TenantID, args *roachpb.UpdateSpanConfigsRequest, + ctx context.Context, tenID roachpb.TenantID, args *roachpb.UpdateSpanConfigsRequest, ) error { for _, entry := range args.ToUpsert { - if err := validateSpanConfigTarget(tenID, entry.Target, false, a); err != nil { + if err := validateSpanConfigTarget(ctx, tenID, entry.Target, false, a); err != nil { return err } } for _, target := range args.ToDelete { - if err := validateSpanConfigTarget(tenID, target, false, a); err != nil { + if err := validateSpanConfigTarget(ctx, tenID, target, false, a); err != nil { return err } } @@ -399,10 +399,10 @@ func (a tenantAuthorizer) authHotRangesV2(tenID roachpb.TenantID) error { // authSpanConfigConformance authorizes the provided tenant to invoke the // SpanConfigConformance RPC with the provided args. func (a tenantAuthorizer) authSpanConfigConformance( - tenID roachpb.TenantID, args *roachpb.SpanConfigConformanceRequest, + ctx context.Context, tenID roachpb.TenantID, args *roachpb.SpanConfigConformanceRequest, ) error { for _, sp := range args.Spans { - if err := validateSpan(tenID, sp, false, a); err != nil { + if err := validateSpan(ctx, tenID, sp, false, a); err != nil { return err } } @@ -440,7 +440,11 @@ func (a tenantAuthorizer) authTSDBQuery( // wholly contained within the tenant keyspace and system span config targets // must be well-formed. func validateSpanConfigTarget( - tenID roachpb.TenantID, spanConfigTarget roachpb.SpanConfigTarget, read bool, a tenantAuthorizer, + ctx context.Context, + tenID roachpb.TenantID, + spanConfigTarget roachpb.SpanConfigTarget, + read bool, + a tenantAuthorizer, ) error { validateSystemTarget := func(target roachpb.SystemSpanConfigTarget) error { if target.SourceTenantID != tenID { @@ -469,7 +473,7 @@ func validateSpanConfigTarget( switch spanConfigTarget.Union.(type) { case *roachpb.SpanConfigTarget_Span: - return validateSpan(tenID, *spanConfigTarget.GetSpan(), read, a) + return validateSpan(ctx, tenID, *spanConfigTarget.GetSpan(), read, a) case *roachpb.SpanConfigTarget_SystemSpanConfigTarget: return validateSystemTarget(*spanConfigTarget.GetSystemSpanConfigTarget()) default: @@ -477,7 +481,9 @@ func validateSpanConfigTarget( } } -func validateSpan(tenID roachpb.TenantID, sp roachpb.Span, isRead bool, a tenantAuthorizer) error { +func validateSpan( + ctx context.Context, tenID roachpb.TenantID, sp roachpb.Span, isRead bool, a tenantAuthorizer, +) error { tenSpan := tenantPrefix(tenID) rSpan, err := keys.SpanAddr(sp) if err != nil { @@ -485,7 +491,7 @@ func validateSpan(tenID roachpb.TenantID, sp roachpb.Span, isRead bool, a tenant } if outsideTenant(rSpan, tenSpan) { // Allow it anyway if the tenant can read other tenants. - if isRead && a.capabilitiesAuthorizer.HasCrossTenantRead(tenID) { + if isRead && a.capabilitiesAuthorizer.HasCrossTenantRead(ctx, tenID) { return nil } return spanErr(rSpan, tenSpan) diff --git a/pkg/rpc/auth_test.go b/pkg/rpc/auth_test.go index b59b29a777dc..f656522965ba 100644 --- a/pkg/rpc/auth_test.go +++ b/pkg/rpc/auth_test.go @@ -1120,7 +1120,7 @@ func (m mockAuthorizer) HasProcessDebugCapability( return errors.New("tenant does not have capability") } -func (m mockAuthorizer) HasCrossTenantRead(tenID roachpb.TenantID) bool { +func (m mockAuthorizer) HasCrossTenantRead(ctx context.Context, tenID roachpb.TenantID) bool { return m.hasCrossTenantRead } diff --git a/pkg/sql/catalog/BUILD.bazel b/pkg/sql/catalog/BUILD.bazel index 105b137fcf20..e859418225e6 100644 --- a/pkg/sql/catalog/BUILD.bazel +++ b/pkg/sql/catalog/BUILD.bazel @@ -11,6 +11,7 @@ go_library( "metadata.go", "post_deserialization_changes.go", "schema.go", + "serial_helper.go", "system_table.go", "table_col_map.go", "table_col_set.go", diff --git a/pkg/sql/catalog/serial_helper.go b/pkg/sql/catalog/serial_helper.go new file mode 100644 index 000000000000..530ed06bdcc5 --- /dev/null +++ b/pkg/sql/catalog/serial_helper.go @@ -0,0 +1,54 @@ +// Copyright 2024 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package catalog + +import ( + "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" + "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" + "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" + "github.com/cockroachdb/cockroach/pkg/sql/types" +) + +func UseRowID(d tree.ColumnTableDef) *tree.ColumnTableDef { + d.DefaultExpr.Expr = &tree.FuncExpr{Func: tree.WrapFunction("unique_rowid")} + d.Type = types.Int + // Column is non-nullable in all cases. PostgreSQL requires this. + d.Nullable.Nullability = tree.NotNull + + return &d +} + +func AssertValidSerialColumnDef(d *tree.ColumnTableDef, tableName *tree.TableName) error { + if d.HasDefaultExpr() { + // SERIAL implies a new default expression, we can't have one to + // start with. This is the error produced by pg in such case. + return pgerror.Newf(pgcode.Syntax, + "multiple default values specified for column %q of table %q", + tree.ErrString(&d.Name), tree.ErrString(tableName)) + } + + if d.Nullable.Nullability == tree.Null { + // SERIAL implies a non-NULL column, we can't accept a nullability + // spec. This is the error produced by pg in such case. + return pgerror.Newf(pgcode.Syntax, + "conflicting NULL/NOT NULL declarations for column %q of table %q", + tree.ErrString(&d.Name), tree.ErrString(tableName)) + } + + if d.Computed.Expr != nil { + // SERIAL cannot be a computed column. + return pgerror.Newf(pgcode.Syntax, + "SERIAL column %q of table %q cannot be computed", + tree.ErrString(&d.Name), tree.ErrString(tableName)) + } + + return nil +} diff --git a/pkg/sql/logictest/testdata/logic_test/alter_table b/pkg/sql/logictest/testdata/logic_test/alter_table index 440caa1fbb62..49985febb498 100644 --- a/pkg/sql/logictest/testdata/logic_test/alter_table +++ b/pkg/sql/logictest/testdata/logic_test/alter_table @@ -3967,3 +3967,37 @@ statement error pgcode 42601 variable sub-expressions are not allowed in EXPRESS ALTER TABLE t_124546 ADD CONSTRAINT ident UNIQUE ( ( EXISTS ( TABLE error FOR READ ONLY ) ) DESC ) STORING ( ident , ident ); subtest end + +subtest alter_table_add_column_serial + +statement ok +create table roach (id int); +insert into roach DEFAULT VALUES; +insert into roach DEFAULT VALUES; +SET serial_normalization = rowid + +statement ok +alter table roach add column serial_id SERIAL; + +query TTBTTTB colnames,rowsort +show columns from roach; +---- +column_name data_type is_nullable column_default generation_expression indices is_hidden +id INT8 true NULL · {roach_pkey} false +rowid INT8 false unique_rowid() · {roach_pkey} true +serial_id INT8 false unique_rowid() · {roach_pkey} false + +subtest end + +subtest unimplemented_for_non_rowid_in_DSC + +statement ok +SET serial_normalization = sql_sequence + +statement ok +SET use_declarative_schema_changer = unsafe_always + +statement error pq: \*tree.ColumnTableDef not implemented in the new schema changer: contains serial data type in unsupported mode +alter table roach add column serial_id2 SERIAL + +subtest end 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 830b5d56168c..4fa86bd1fda6 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 @@ -15,6 +15,8 @@ import ( "sort" "strings" + "github.com/cockroachdb/cockroach/pkg/docs" + "github.com/cockroachdb/cockroach/pkg/server/telemetry" "github.com/cockroachdb/cockroach/pkg/sql/catalog" "github.com/cockroachdb/cockroach/pkg/sql/catalog/catenumpb" "github.com/cockroachdb/cockroach/pkg/sql/catalog/catpb" @@ -25,12 +27,14 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/catalog/typedesc" "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" + "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgnotice" "github.com/cockroachdb/cockroach/pkg/sql/privilege" "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scdecomp" "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scerrors" "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scpb" "github.com/cockroachdb/cockroach/pkg/sql/sem/catid" "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" + "github.com/cockroachdb/cockroach/pkg/sql/sessiondatapb" "github.com/cockroachdb/cockroach/pkg/sql/sqlerrors" "github.com/cockroachdb/cockroach/pkg/sql/sqltelemetry" "github.com/cockroachdb/cockroach/pkg/sql/types" @@ -71,7 +75,11 @@ func alterTableAddColumn( } } if d.IsSerial { - panic(scerrors.NotImplementedErrorf(d, "contains serial data type")) + if b.SessionData().SerialNormalizationMode != sessiondatapb.SerialUsesRowID { + panic(scerrors.NotImplementedErrorf(d, "contains serial data type in unsupported mode")) + } + d = alterTableAddColumnSerial(b, d, tn) + } if d.GeneratedIdentity.IsGeneratedAsIdentity { panic(scerrors.NotImplementedErrorf(d, "contains generated identity type")) @@ -259,6 +267,43 @@ func alterTableAddColumn( } } +func alterTableAddColumnSerial( + b BuildCtx, d *tree.ColumnTableDef, tn *tree.TableName, +) *tree.ColumnTableDef { + if err := catalog.AssertValidSerialColumnDef(d, tn); err != nil { + panic(err) + } + + defType, err := tree.ResolveType(b, d.Type, b.SemaCtx().GetTypeResolver()) + if err != nil { + panic(err) + } + + telemetry.Inc(sqltelemetry.SerialColumnNormalizationCounter( + defType.Name(), b.SessionData().SerialNormalizationMode.String())) + + if defType.Width() < types.Int.Width() { + b.EvalCtx().ClientNoticeSender.BufferClientNotice( + b, + errors.WithHintf( + pgnotice.Newf( + "upgrading the column %s to %s to utilize the session serial_normalization setting", + d.Name.String(), + types.Int.SQLString(), + ), + "change the serial_normalization to sql_sequence or sql_sequence_cached if you wish "+ + "to use a smaller sized serial column at the cost of performance. See %s", + docs.URL("serial.html"), + ), + ) + } + + // Serial is an alias for a real column definition. False indicates a remapped alias. + d.IsSerial = false + + return catalog.UseRowID(*d) +} + func columnNamesToIDs(b BuildCtx, tbl *scpb.Table) map[string]descpb.ColumnID { tableElts := b.QueryByID(tbl.TableID) namesToIDs := make(map[string]descpb.ColumnID) diff --git a/pkg/sql/schemachanger/scbuild/testdata/alter_table_add_column b/pkg/sql/schemachanger/scbuild/testdata/alter_table_add_column index ce1dc7dcb0d4..63b1756fa29a 100644 --- a/pkg/sql/schemachanger/scbuild/testdata/alter_table_add_column +++ b/pkg/sql/schemachanger/scbuild/testdata/alter_table_add_column @@ -153,6 +153,48 @@ ALTER TABLE defaultdb.foo ADD COLUMN a INT AS (i+1) STORED - [[IndexColumn:{DescID: 104, ColumnID: 2, IndexID: 3}, TRANSIENT_ABSENT], ABSENT] {columnId: 2, indexId: 3, kind: STORED, tableId: 104} +build +ALTER TABLE defaultdb.foo ADD COLUMN serial_id SERIAL +---- +- [[IndexColumn:{DescID: 104, ColumnID: 1, IndexID: 1}, ABSENT], PUBLIC] + {columnId: 1, indexId: 1, tableId: 104} +- [[PrimaryIndex:{DescID: 104, IndexID: 1, ConstraintID: 1}, ABSENT], PUBLIC] + {constraintId: 1, indexId: 1, isUnique: true, tableId: 104} +- [[IndexName:{DescID: 104, Name: foo_pkey, IndexID: 1}, ABSENT], PUBLIC] + {indexId: 1, name: foo_pkey, tableId: 104} +- [[IndexData:{DescID: 104, IndexID: 1}, ABSENT], PUBLIC] + {indexId: 1, tableId: 104} +- [[TableData:{DescID: 104, ReferencedDescID: 100}, PUBLIC], PUBLIC] + {databaseId: 100, tableId: 104} +- [[Column:{DescID: 104, ColumnID: 2}, PUBLIC], ABSENT] + {columnId: 2, tableId: 104} +- [[ColumnName:{DescID: 104, Name: serial_id, ColumnID: 2}, PUBLIC], ABSENT] + {columnId: 2, name: serial_id, tableId: 104} +- [[ColumnType:{DescID: 104, ColumnFamilyID: 0, ColumnID: 2, TypeName: INT8}, PUBLIC], ABSENT] + {columnId: 2, elementCreationMetadata: {in231OrLater: true, in243OrLater: true}, tableId: 104, type: {family: IntFamily, oid: 20, width: 64}, typeName: INT8} +- [[ColumnDefaultExpression:{DescID: 104, ColumnID: 2, Expr: unique_rowid()}, PUBLIC], ABSENT] + {columnId: 2, expr: unique_rowid(), tableId: 104} +- [[PrimaryIndex:{DescID: 104, IndexID: 2, ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1}, PUBLIC], ABSENT] + {constraintId: 2, indexId: 2, isUnique: true, sourceIndexId: 1, tableId: 104, temporaryIndexId: 3} +- [[IndexName:{DescID: 104, Name: foo_pkey, IndexID: 2}, PUBLIC], ABSENT] + {indexId: 2, name: foo_pkey, tableId: 104} +- [[IndexColumn:{DescID: 104, ColumnID: 1, IndexID: 2}, PUBLIC], ABSENT] + {columnId: 1, indexId: 2, tableId: 104} +- [[IndexData:{DescID: 104, IndexID: 2}, PUBLIC], ABSENT] + {indexId: 2, tableId: 104} +- [[TemporaryIndex:{DescID: 104, IndexID: 3, ConstraintID: 3, SourceIndexID: 1}, TRANSIENT_ABSENT], ABSENT] + {constraintId: 3, indexId: 3, isUnique: true, sourceIndexId: 1, tableId: 104} +- [[IndexColumn:{DescID: 104, ColumnID: 1, IndexID: 3}, TRANSIENT_ABSENT], ABSENT] + {columnId: 1, indexId: 3, tableId: 104} +- [[IndexData:{DescID: 104, IndexID: 3}, TRANSIENT_ABSENT], ABSENT] + {indexId: 3, tableId: 104} +- [[IndexColumn:{DescID: 104, ColumnID: 2, IndexID: 2}, PUBLIC], ABSENT] + {columnId: 2, indexId: 2, kind: STORED, tableId: 104} +- [[IndexColumn:{DescID: 104, ColumnID: 2, IndexID: 3}, TRANSIENT_ABSENT], ABSENT] + {columnId: 2, indexId: 3, kind: STORED, tableId: 104} +- [[ColumnNotNull:{DescID: 104, ColumnID: 2, IndexID: 2}, PUBLIC], ABSENT] + {columnId: 2, indexIdForValidation: 2, tableId: 104} + setup CREATE TABLE defaultdb.bar (j INT); ---- diff --git a/pkg/sql/schemachanger/scbuild/testdata/unimplemented_alter_table b/pkg/sql/schemachanger/scbuild/testdata/unimplemented_alter_table index ecc469652668..31350b82d852 100644 --- a/pkg/sql/schemachanger/scbuild/testdata/unimplemented_alter_table +++ b/pkg/sql/schemachanger/scbuild/testdata/unimplemented_alter_table @@ -12,10 +12,6 @@ CREATE TABLE defaultdb.foo ( ); ---- -unimplemented -ALTER TABLE defaultdb.foo ADD COLUMN j SERIAL ----- - unimplemented ALTER TABLE defaultdb.foo ALTER COLUMN i DROP NOT NULL ---- diff --git a/pkg/sql/schemachanger/scplan/testdata/alter_table_add_column b/pkg/sql/schemachanger/scplan/testdata/alter_table_add_column index 0ab9b0a1f1c8..4c226eea6f14 100644 --- a/pkg/sql/schemachanger/scplan/testdata/alter_table_add_column +++ b/pkg/sql/schemachanger/scplan/testdata/alter_table_add_column @@ -1374,6 +1374,374 @@ PostCommitNonRevertiblePhase stage 3 of 3 with 5 MutationType ops IsNonCancelable: true JobID: 1 +ops +ALTER TABLE defaultdb.foo ADD COLUMN serial_id SERIAL +---- +StatementPhase stage 1 of 1 with 10 MutationType ops + transitions: + [[Column:{DescID: 104, ColumnID: 2}, PUBLIC], ABSENT] -> DELETE_ONLY + [[ColumnName:{DescID: 104, Name: serial_id, ColumnID: 2}, PUBLIC], ABSENT] -> PUBLIC + [[ColumnType:{DescID: 104, ColumnFamilyID: 0, ColumnID: 2, TypeName: INT8}, PUBLIC], ABSENT] -> PUBLIC + [[ColumnDefaultExpression:{DescID: 104, ColumnID: 2, Expr: unique_rowid()}, PUBLIC], ABSENT] -> PUBLIC + [[PrimaryIndex:{DescID: 104, IndexID: 2, ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1}, PUBLIC], ABSENT] -> BACKFILL_ONLY + [[IndexColumn:{DescID: 104, ColumnID: 1, IndexID: 2}, PUBLIC], ABSENT] -> PUBLIC + [[IndexData:{DescID: 104, IndexID: 2}, PUBLIC], ABSENT] -> PUBLIC + [[TemporaryIndex:{DescID: 104, IndexID: 3, ConstraintID: 3, SourceIndexID: 1}, TRANSIENT_ABSENT], ABSENT] -> DELETE_ONLY + [[IndexColumn:{DescID: 104, ColumnID: 1, IndexID: 3}, TRANSIENT_ABSENT], ABSENT] -> PUBLIC + [[IndexColumn:{DescID: 104, ColumnID: 2, IndexID: 2}, PUBLIC], ABSENT] -> PUBLIC + [[IndexColumn:{DescID: 104, ColumnID: 2, IndexID: 3}, TRANSIENT_ABSENT], ABSENT] -> PUBLIC + ops: + *scop.MakeAbsentColumnDeleteOnly + Column: + ColumnID: 2 + TableID: 104 + *scop.SetColumnName + ColumnID: 2 + Name: serial_id + TableID: 104 + *scop.UpsertColumnType + ColumnType: + ColumnID: 2 + ElementCreationMetadata: + in231OrLater: true + in243OrLater: true + TableID: 104 + TypeT: + Type: + family: IntFamily + oid: 20 + width: 64 + TypeName: INT8 + *scop.AddColumnDefaultExpression + Default: + ColumnID: 2 + Expression: + Expr: unique_rowid() + TableID: 104 + *scop.MakeAbsentIndexBackfilling + Index: + ConstraintID: 2 + IndexID: 2 + IsUnique: true + SourceIndexID: 1 + TableID: 104 + TemporaryIndexID: 3 + *scop.AddColumnToIndex + ColumnID: 1 + IndexID: 2 + TableID: 104 + *scop.MakeAbsentTempIndexDeleteOnly + Index: + ConstraintID: 3 + IndexID: 3 + IsUnique: true + SourceIndexID: 1 + TableID: 104 + *scop.AddColumnToIndex + ColumnID: 1 + IndexID: 3 + TableID: 104 + *scop.AddColumnToIndex + ColumnID: 2 + IndexID: 2 + Kind: 2 + TableID: 104 + *scop.AddColumnToIndex + ColumnID: 2 + IndexID: 3 + Kind: 2 + TableID: 104 +PreCommitPhase stage 1 of 2 with 1 MutationType op + transitions: + [[Column:{DescID: 104, ColumnID: 2}, PUBLIC], DELETE_ONLY] -> ABSENT + [[ColumnName:{DescID: 104, Name: serial_id, ColumnID: 2}, PUBLIC], PUBLIC] -> ABSENT + [[ColumnType:{DescID: 104, ColumnFamilyID: 0, ColumnID: 2, TypeName: INT8}, PUBLIC], PUBLIC] -> ABSENT + [[ColumnDefaultExpression:{DescID: 104, ColumnID: 2, Expr: unique_rowid()}, PUBLIC], PUBLIC] -> ABSENT + [[PrimaryIndex:{DescID: 104, IndexID: 2, ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1}, PUBLIC], BACKFILL_ONLY] -> ABSENT + [[IndexColumn:{DescID: 104, ColumnID: 1, IndexID: 2}, PUBLIC], PUBLIC] -> ABSENT + [[IndexData:{DescID: 104, IndexID: 2}, PUBLIC], PUBLIC] -> ABSENT + [[TemporaryIndex:{DescID: 104, IndexID: 3, ConstraintID: 3, SourceIndexID: 1}, TRANSIENT_ABSENT], DELETE_ONLY] -> ABSENT + [[IndexColumn:{DescID: 104, ColumnID: 1, IndexID: 3}, TRANSIENT_ABSENT], PUBLIC] -> ABSENT + [[IndexColumn:{DescID: 104, ColumnID: 2, IndexID: 2}, PUBLIC], PUBLIC] -> ABSENT + [[IndexColumn:{DescID: 104, ColumnID: 2, IndexID: 3}, TRANSIENT_ABSENT], PUBLIC] -> ABSENT + ops: + *scop.UndoAllInTxnImmediateMutationOpSideEffects + {} +PreCommitPhase stage 2 of 2 with 14 MutationType ops + transitions: + [[Column:{DescID: 104, ColumnID: 2}, PUBLIC], ABSENT] -> DELETE_ONLY + [[ColumnName:{DescID: 104, Name: serial_id, ColumnID: 2}, PUBLIC], ABSENT] -> PUBLIC + [[ColumnType:{DescID: 104, ColumnFamilyID: 0, ColumnID: 2, TypeName: INT8}, PUBLIC], ABSENT] -> PUBLIC + [[ColumnDefaultExpression:{DescID: 104, ColumnID: 2, Expr: unique_rowid()}, PUBLIC], ABSENT] -> PUBLIC + [[PrimaryIndex:{DescID: 104, IndexID: 2, ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1}, PUBLIC], ABSENT] -> BACKFILL_ONLY + [[IndexColumn:{DescID: 104, ColumnID: 1, IndexID: 2}, PUBLIC], ABSENT] -> PUBLIC + [[IndexData:{DescID: 104, IndexID: 2}, PUBLIC], ABSENT] -> PUBLIC + [[TemporaryIndex:{DescID: 104, IndexID: 3, ConstraintID: 3, SourceIndexID: 1}, TRANSIENT_ABSENT], ABSENT] -> DELETE_ONLY + [[IndexColumn:{DescID: 104, ColumnID: 1, IndexID: 3}, TRANSIENT_ABSENT], ABSENT] -> PUBLIC + [[IndexColumn:{DescID: 104, ColumnID: 2, IndexID: 2}, PUBLIC], ABSENT] -> PUBLIC + [[IndexColumn:{DescID: 104, ColumnID: 2, IndexID: 3}, TRANSIENT_ABSENT], ABSENT] -> PUBLIC + ops: + *scop.MakeAbsentColumnDeleteOnly + Column: + ColumnID: 2 + TableID: 104 + *scop.SetColumnName + ColumnID: 2 + Name: serial_id + TableID: 104 + *scop.UpsertColumnType + ColumnType: + ColumnID: 2 + ElementCreationMetadata: + in231OrLater: true + in243OrLater: true + TableID: 104 + TypeT: + Type: + family: IntFamily + oid: 20 + width: 64 + TypeName: INT8 + *scop.AddColumnDefaultExpression + Default: + ColumnID: 2 + Expression: + Expr: unique_rowid() + TableID: 104 + *scop.MakeAbsentIndexBackfilling + Index: + ConstraintID: 2 + IndexID: 2 + IsUnique: true + SourceIndexID: 1 + TableID: 104 + TemporaryIndexID: 3 + *scop.MaybeAddSplitForIndex + IndexID: 2 + TableID: 104 + *scop.AddColumnToIndex + ColumnID: 1 + IndexID: 2 + TableID: 104 + *scop.MakeAbsentTempIndexDeleteOnly + Index: + ConstraintID: 3 + IndexID: 3 + IsUnique: true + SourceIndexID: 1 + TableID: 104 + *scop.MaybeAddSplitForIndex + IndexID: 3 + TableID: 104 + *scop.AddColumnToIndex + ColumnID: 1 + IndexID: 3 + TableID: 104 + *scop.AddColumnToIndex + ColumnID: 2 + IndexID: 2 + Kind: 2 + TableID: 104 + *scop.AddColumnToIndex + ColumnID: 2 + IndexID: 3 + Kind: 2 + TableID: 104 + *scop.SetJobStateOnDescriptor + DescriptorID: 104 + Initialize: true + *scop.CreateSchemaChangerJob + Authorization: + AppName: $ internal-test + UserName: root + DescriptorIDs: + - 104 + JobID: 1 + RunningStatus: PostCommitPhase stage 1 of 7 with 3 MutationType ops pending + Statements: + - statement: ALTER TABLE defaultdb.foo ADD COLUMN serial_id SERIAL8 + redactedstatement: ALTER TABLE ‹defaultdb›.public.‹foo› ADD COLUMN ‹serial_id› INT8 + statementtag: ALTER TABLE +PostCommitPhase stage 1 of 7 with 5 MutationType ops + transitions: + [[Column:{DescID: 104, ColumnID: 2}, PUBLIC], DELETE_ONLY] -> WRITE_ONLY + [[TemporaryIndex:{DescID: 104, IndexID: 3, ConstraintID: 3, SourceIndexID: 1}, TRANSIENT_ABSENT], DELETE_ONLY] -> WRITE_ONLY + [[IndexData:{DescID: 104, IndexID: 3}, TRANSIENT_ABSENT], ABSENT] -> PUBLIC + [[ColumnNotNull:{DescID: 104, ColumnID: 2, IndexID: 2}, PUBLIC], ABSENT] -> WRITE_ONLY + ops: + *scop.MakeDeleteOnlyColumnWriteOnly + ColumnID: 2 + TableID: 104 + *scop.MakeDeleteOnlyIndexWriteOnly + IndexID: 3 + TableID: 104 + *scop.MakeAbsentColumnNotNullWriteOnly + ColumnID: 2 + TableID: 104 + *scop.SetJobStateOnDescriptor + DescriptorID: 104 + *scop.UpdateSchemaChangerJob + JobID: 1 +PostCommitPhase stage 2 of 7 with 1 BackfillType op + transitions: + [[PrimaryIndex:{DescID: 104, IndexID: 2, ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1}, PUBLIC], BACKFILL_ONLY] -> BACKFILLED + ops: + *scop.BackfillIndex + IndexID: 2 + SourceIndexID: 1 + TableID: 104 +PostCommitPhase stage 3 of 7 with 3 MutationType ops + transitions: + [[PrimaryIndex:{DescID: 104, IndexID: 2, ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1}, PUBLIC], BACKFILLED] -> DELETE_ONLY + ops: + *scop.MakeBackfillingIndexDeleteOnly + IndexID: 2 + TableID: 104 + *scop.SetJobStateOnDescriptor + DescriptorID: 104 + *scop.UpdateSchemaChangerJob + JobID: 1 +PostCommitPhase stage 4 of 7 with 3 MutationType ops + transitions: + [[PrimaryIndex:{DescID: 104, IndexID: 2, ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1}, PUBLIC], DELETE_ONLY] -> MERGE_ONLY + ops: + *scop.MakeBackfilledIndexMerging + IndexID: 2 + TableID: 104 + *scop.SetJobStateOnDescriptor + DescriptorID: 104 + *scop.UpdateSchemaChangerJob + JobID: 1 +PostCommitPhase stage 5 of 7 with 1 BackfillType op + transitions: + [[PrimaryIndex:{DescID: 104, IndexID: 2, ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1}, PUBLIC], MERGE_ONLY] -> MERGED + ops: + *scop.MergeIndex + BackfilledIndexID: 2 + TableID: 104 + TemporaryIndexID: 3 +PostCommitPhase stage 6 of 7 with 4 MutationType ops + transitions: + [[PrimaryIndex:{DescID: 104, IndexID: 2, ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1}, PUBLIC], MERGED] -> WRITE_ONLY + [[TemporaryIndex:{DescID: 104, IndexID: 3, ConstraintID: 3, SourceIndexID: 1}, TRANSIENT_ABSENT], WRITE_ONLY] -> TRANSIENT_DELETE_ONLY + ops: + *scop.MakeWriteOnlyIndexDeleteOnly + IndexID: 3 + TableID: 104 + *scop.MakeMergedIndexWriteOnly + IndexID: 2 + TableID: 104 + *scop.SetJobStateOnDescriptor + DescriptorID: 104 + *scop.UpdateSchemaChangerJob + JobID: 1 +PostCommitPhase stage 7 of 7 with 2 ValidationType ops + transitions: + [[PrimaryIndex:{DescID: 104, IndexID: 2, ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1}, PUBLIC], WRITE_ONLY] -> VALIDATED + [[ColumnNotNull:{DescID: 104, ColumnID: 2, IndexID: 2}, PUBLIC], WRITE_ONLY] -> VALIDATED + ops: + *scop.ValidateIndex + IndexID: 2 + TableID: 104 + *scop.ValidateColumnNotNull + ColumnID: 2 + IndexIDForValidation: 2 + TableID: 104 +PostCommitNonRevertiblePhase stage 1 of 3 with 12 MutationType ops + transitions: + [[PrimaryIndex:{DescID: 104, IndexID: 1, ConstraintID: 1}, ABSENT], PUBLIC] -> VALIDATED + [[IndexName:{DescID: 104, Name: foo_pkey, IndexID: 1}, ABSENT], PUBLIC] -> ABSENT + [[Column:{DescID: 104, ColumnID: 2}, PUBLIC], WRITE_ONLY] -> PUBLIC + [[PrimaryIndex:{DescID: 104, IndexID: 2, ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1}, PUBLIC], VALIDATED] -> PUBLIC + [[IndexName:{DescID: 104, Name: foo_pkey, IndexID: 2}, PUBLIC], ABSENT] -> PUBLIC + [[TemporaryIndex:{DescID: 104, IndexID: 3, ConstraintID: 3, SourceIndexID: 1}, TRANSIENT_ABSENT], TRANSIENT_DELETE_ONLY] -> TRANSIENT_ABSENT + [[IndexColumn:{DescID: 104, ColumnID: 1, IndexID: 3}, TRANSIENT_ABSENT], PUBLIC] -> TRANSIENT_ABSENT + [[IndexColumn:{DescID: 104, ColumnID: 2, IndexID: 3}, TRANSIENT_ABSENT], PUBLIC] -> TRANSIENT_ABSENT + [[ColumnNotNull:{DescID: 104, ColumnID: 2, IndexID: 2}, PUBLIC], VALIDATED] -> PUBLIC + ops: + *scop.MakePublicPrimaryIndexWriteOnly + IndexID: 1 + TableID: 104 + *scop.SetIndexName + IndexID: 1 + Name: crdb_internal_index_1_name_placeholder + TableID: 104 + *scop.SetIndexName + IndexID: 2 + Name: foo_pkey + TableID: 104 + *scop.RemoveColumnFromIndex + ColumnID: 1 + IndexID: 3 + TableID: 104 + *scop.RemoveColumnFromIndex + ColumnID: 2 + IndexID: 3 + Kind: 2 + TableID: 104 + *scop.MakeValidatedColumnNotNullPublic + ColumnID: 2 + TableID: 104 + *scop.MakeValidatedPrimaryIndexPublic + IndexID: 2 + TableID: 104 + *scop.MakeIndexAbsent + IndexID: 3 + TableID: 104 + *scop.MakeWriteOnlyColumnPublic + ColumnID: 2 + TableID: 104 + *scop.RefreshStats + TableID: 104 + *scop.SetJobStateOnDescriptor + DescriptorID: 104 + *scop.UpdateSchemaChangerJob + IsNonCancelable: true + JobID: 1 +PostCommitNonRevertiblePhase stage 2 of 3 with 4 MutationType ops + transitions: + [[IndexColumn:{DescID: 104, ColumnID: 1, IndexID: 1}, ABSENT], PUBLIC] -> ABSENT + [[PrimaryIndex:{DescID: 104, IndexID: 1, ConstraintID: 1}, ABSENT], VALIDATED] -> DELETE_ONLY + ops: + *scop.MakeWriteOnlyIndexDeleteOnly + IndexID: 1 + TableID: 104 + *scop.RemoveColumnFromIndex + ColumnID: 1 + IndexID: 1 + TableID: 104 + *scop.SetJobStateOnDescriptor + DescriptorID: 104 + *scop.UpdateSchemaChangerJob + IsNonCancelable: true + JobID: 1 +PostCommitNonRevertiblePhase stage 3 of 3 with 5 MutationType ops + transitions: + [[PrimaryIndex:{DescID: 104, IndexID: 1, ConstraintID: 1}, ABSENT], DELETE_ONLY] -> ABSENT + [[IndexData:{DescID: 104, IndexID: 1}, ABSENT], PUBLIC] -> ABSENT + [[IndexData:{DescID: 104, IndexID: 3}, TRANSIENT_ABSENT], PUBLIC] -> TRANSIENT_ABSENT + ops: + *scop.MakeIndexAbsent + IndexID: 1 + TableID: 104 + *scop.CreateGCJobForIndex + IndexID: 1 + StatementForDropJob: + Statement: ALTER TABLE defaultdb.public.foo ADD COLUMN serial_id INT8 + TableID: 104 + *scop.CreateGCJobForIndex + IndexID: 3 + StatementForDropJob: + Statement: ALTER TABLE defaultdb.public.foo ADD COLUMN serial_id INT8 + TableID: 104 + *scop.RemoveJobStateFromDescriptor + DescriptorID: 104 + JobID: 1 + *scop.UpdateSchemaChangerJob + DescriptorIDsToRemove: + - 104 + IsNonCancelable: true + JobID: 1 setup CREATE TABLE defaultdb.bar (j INT); diff --git a/pkg/sql/schemachanger/sctest_generated_test.go b/pkg/sql/schemachanger/sctest_generated_test.go index 6ac77ba1a821..26cca79fa4df 100644 --- a/pkg/sql/schemachanger/sctest_generated_test.go +++ b/pkg/sql/schemachanger/sctest_generated_test.go @@ -55,6 +55,13 @@ func TestEndToEndSideEffects_add_column_no_default(t *testing.T) { sctest.EndToEndSideEffects(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestEndToEndSideEffects_add_column_serial(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/add_column_serial" + sctest.EndToEndSideEffects(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestEndToEndSideEffects_add_column_virtual_not_null(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -559,6 +566,13 @@ func TestExecuteWithDMLInjection_add_column_no_default(t *testing.T) { sctest.ExecuteWithDMLInjection(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestExecuteWithDMLInjection_add_column_serial(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/add_column_serial" + sctest.ExecuteWithDMLInjection(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestExecuteWithDMLInjection_add_column_virtual_not_null(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1063,6 +1077,13 @@ func TestGenerateSchemaChangeCorpus_add_column_no_default(t *testing.T) { sctest.GenerateSchemaChangeCorpus(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestGenerateSchemaChangeCorpus_add_column_serial(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/add_column_serial" + sctest.GenerateSchemaChangeCorpus(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestGenerateSchemaChangeCorpus_add_column_virtual_not_null(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1567,6 +1588,13 @@ func TestPause_add_column_no_default(t *testing.T) { sctest.Pause(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestPause_add_column_serial(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/add_column_serial" + sctest.Pause(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestPause_add_column_virtual_not_null(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -2071,6 +2099,13 @@ func TestPauseMixedVersion_add_column_no_default(t *testing.T) { sctest.PauseMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestPauseMixedVersion_add_column_serial(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/add_column_serial" + sctest.PauseMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestPauseMixedVersion_add_column_virtual_not_null(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -2575,6 +2610,13 @@ func TestRollback_add_column_no_default(t *testing.T) { sctest.Rollback(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestRollback_add_column_serial(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/add_column_serial" + sctest.Rollback(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestRollback_add_column_virtual_not_null(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) diff --git a/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial.definition b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial.definition new file mode 100644 index 000000000000..a72237f7ddb4 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial.definition @@ -0,0 +1,33 @@ +setup +CREATE DATABASE db; +CREATE TABLE db.public.tbl (i INT PRIMARY KEY); +---- + +stage-exec phase=PostCommitPhase stage=: +INSERT INTO db.public.tbl VALUES($stageKey); +INSERT INTO db.public.tbl VALUES($stageKey + 1); +---- + +# Each insert will be injected twice per stage, so we should always, +# see a count of 2. +stage-query phase=PostCommitPhase stage=: +SELECT count(*)=$successfulStageCount*2 FROM db.public.tbl; +---- +true + + +stage-exec phase=PostCommitNonRevertiblePhase stage=: +INSERT INTO db.public.tbl VALUES($stageKey); +INSERT INTO db.public.tbl VALUES($stageKey + 1); +---- + +# Each insert will be injected twice per stage, so we should always, +# see a count of 2. +stage-query phase=PostCommitNonRevertiblePhase stage=: +SELECT count(*)=$successfulStageCount*2 FROM db.public.tbl; +---- +true + +test +ALTER TABLE db.public.tbl ADD COLUMN serial_id SERIAL +---- diff --git a/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial.explain b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial.explain new file mode 100644 index 000000000000..7a0a68f11976 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial.explain @@ -0,0 +1,183 @@ +/* setup */ +CREATE DATABASE db; +CREATE TABLE db.public.tbl (i INT PRIMARY KEY); + +/* test */ +EXPLAIN (DDL) ALTER TABLE db.public.tbl ADD COLUMN serial_id SERIAL; +---- +Schema change plan for ALTER TABLE ‹db›.‹public›.‹tbl› ADD COLUMN ‹serial_id› INT8; + ├── StatementPhase + │ └── Stage 1 of 1 in StatementPhase + │ ├── 8 elements transitioning toward PUBLIC + │ │ ├── ABSENT → DELETE_ONLY Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id+)} + │ │ ├── ABSENT → PUBLIC ColumnName:{DescID: 106 (tbl), Name: "serial_id", ColumnID: 2 (serial_id+)} + │ │ ├── ABSENT → PUBLIC ColumnType:{DescID: 106 (tbl), ColumnFamilyID: 0 (primary), ColumnID: 2 (serial_id+), TypeName: "INT8"} + │ │ ├── ABSENT → PUBLIC ColumnDefaultExpression:{DescID: 106 (tbl), ColumnID: 2 (serial_id+), Expr: unique_rowid()} + │ │ ├── ABSENT → BACKFILL_ONLY PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey-)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 2 (tbl_pkey+)} + │ │ ├── ABSENT → PUBLIC IndexData:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey+)} + │ │ └── ABSENT → PUBLIC IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id+), IndexID: 2 (tbl_pkey+)} + │ ├── 3 elements transitioning toward TRANSIENT_ABSENT + │ │ ├── ABSENT → DELETE_ONLY TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey-)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 3} + │ │ └── ABSENT → PUBLIC IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id+), IndexID: 3} + │ └── 10 Mutation operations + │ ├── MakeAbsentColumnDeleteOnly {"Column":{"ColumnID":2,"TableID":106}} + │ ├── SetColumnName {"ColumnID":2,"Name":"serial_id","TableID":106} + │ ├── UpsertColumnType {"ColumnType":{"ColumnID":2,"TableID":106}} + │ ├── AddColumnDefaultExpression {"Default":{"ColumnID":2,"TableID":106}} + │ ├── MakeAbsentIndexBackfilling {"Index":{"ConstraintID":2,"IndexID":2,"IsUnique":true,"SourceIndexID":1,"TableID":106,"TemporaryIndexID":3}} + │ ├── AddColumnToIndex {"ColumnID":1,"IndexID":2,"TableID":106} + │ ├── MakeAbsentTempIndexDeleteOnly {"Index":{"ConstraintID":3,"IndexID":3,"IsUnique":true,"SourceIndexID":1,"TableID":106}} + │ ├── AddColumnToIndex {"ColumnID":1,"IndexID":3,"TableID":106} + │ ├── AddColumnToIndex {"ColumnID":2,"IndexID":2,"Kind":2,"TableID":106} + │ └── AddColumnToIndex {"ColumnID":2,"IndexID":3,"Kind":2,"TableID":106} + ├── PreCommitPhase + │ ├── Stage 1 of 2 in PreCommitPhase + │ │ ├── 8 elements transitioning toward PUBLIC + │ │ │ ├── DELETE_ONLY → ABSENT Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id+)} + │ │ │ ├── PUBLIC → ABSENT ColumnName:{DescID: 106 (tbl), Name: "serial_id", ColumnID: 2 (serial_id+)} + │ │ │ ├── PUBLIC → ABSENT ColumnType:{DescID: 106 (tbl), ColumnFamilyID: 0 (primary), ColumnID: 2 (serial_id+), TypeName: "INT8"} + │ │ │ ├── PUBLIC → ABSENT ColumnDefaultExpression:{DescID: 106 (tbl), ColumnID: 2 (serial_id+), Expr: unique_rowid()} + │ │ │ ├── BACKFILL_ONLY → ABSENT PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey-)} + │ │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 2 (tbl_pkey+)} + │ │ │ ├── PUBLIC → ABSENT IndexData:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey+)} + │ │ │ └── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id+), IndexID: 2 (tbl_pkey+)} + │ │ ├── 3 elements transitioning toward TRANSIENT_ABSENT + │ │ │ ├── DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey-)} + │ │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 3} + │ │ │ └── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id+), IndexID: 3} + │ │ └── 1 Mutation operation + │ │ └── UndoAllInTxnImmediateMutationOpSideEffects + │ └── Stage 2 of 2 in PreCommitPhase + │ ├── 8 elements transitioning toward PUBLIC + │ │ ├── ABSENT → DELETE_ONLY Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id+)} + │ │ ├── ABSENT → PUBLIC ColumnName:{DescID: 106 (tbl), Name: "serial_id", ColumnID: 2 (serial_id+)} + │ │ ├── ABSENT → PUBLIC ColumnType:{DescID: 106 (tbl), ColumnFamilyID: 0 (primary), ColumnID: 2 (serial_id+), TypeName: "INT8"} + │ │ ├── ABSENT → PUBLIC ColumnDefaultExpression:{DescID: 106 (tbl), ColumnID: 2 (serial_id+), Expr: unique_rowid()} + │ │ ├── ABSENT → BACKFILL_ONLY PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey-)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 2 (tbl_pkey+)} + │ │ ├── ABSENT → PUBLIC IndexData:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey+)} + │ │ └── ABSENT → PUBLIC IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id+), IndexID: 2 (tbl_pkey+)} + │ ├── 3 elements transitioning toward TRANSIENT_ABSENT + │ │ ├── ABSENT → DELETE_ONLY TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey-)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 3} + │ │ └── ABSENT → PUBLIC IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id+), IndexID: 3} + │ └── 14 Mutation operations + │ ├── MakeAbsentColumnDeleteOnly {"Column":{"ColumnID":2,"TableID":106}} + │ ├── SetColumnName {"ColumnID":2,"Name":"serial_id","TableID":106} + │ ├── UpsertColumnType {"ColumnType":{"ColumnID":2,"TableID":106}} + │ ├── AddColumnDefaultExpression {"Default":{"ColumnID":2,"TableID":106}} + │ ├── MakeAbsentIndexBackfilling {"Index":{"ConstraintID":2,"IndexID":2,"IsUnique":true,"SourceIndexID":1,"TableID":106,"TemporaryIndexID":3}} + │ ├── MaybeAddSplitForIndex {"IndexID":2,"TableID":106} + │ ├── AddColumnToIndex {"ColumnID":1,"IndexID":2,"TableID":106} + │ ├── MakeAbsentTempIndexDeleteOnly {"Index":{"ConstraintID":3,"IndexID":3,"IsUnique":true,"SourceIndexID":1,"TableID":106}} + │ ├── MaybeAddSplitForIndex {"IndexID":3,"TableID":106} + │ ├── AddColumnToIndex {"ColumnID":1,"IndexID":3,"TableID":106} + │ ├── AddColumnToIndex {"ColumnID":2,"IndexID":2,"Kind":2,"TableID":106} + │ ├── AddColumnToIndex {"ColumnID":2,"IndexID":3,"Kind":2,"TableID":106} + │ ├── SetJobStateOnDescriptor {"DescriptorID":106,"Initialize":true} + │ └── CreateSchemaChangerJob {"RunningStatus":"PostCommitPhase ..."} + ├── PostCommitPhase + │ ├── Stage 1 of 7 in PostCommitPhase + │ │ ├── 2 elements transitioning toward PUBLIC + │ │ │ ├── DELETE_ONLY → WRITE_ONLY Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id+)} + │ │ │ └── ABSENT → WRITE_ONLY ColumnNotNull:{DescID: 106 (tbl), ColumnID: 2 (serial_id+), IndexID: 2 (tbl_pkey+)} + │ │ ├── 2 elements transitioning toward TRANSIENT_ABSENT + │ │ │ ├── DELETE_ONLY → WRITE_ONLY TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey-)} + │ │ │ └── ABSENT → PUBLIC IndexData:{DescID: 106 (tbl), IndexID: 3} + │ │ └── 5 Mutation operations + │ │ ├── MakeDeleteOnlyColumnWriteOnly {"ColumnID":2,"TableID":106} + │ │ ├── MakeDeleteOnlyIndexWriteOnly {"IndexID":3,"TableID":106} + │ │ ├── MakeAbsentColumnNotNullWriteOnly {"ColumnID":2,"TableID":106} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ │ └── UpdateSchemaChangerJob {"RunningStatus":"PostCommitPhase ..."} + │ ├── Stage 2 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── BACKFILL_ONLY → BACKFILLED PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey-)} + │ │ └── 1 Backfill operation + │ │ └── BackfillIndex {"IndexID":2,"SourceIndexID":1,"TableID":106} + │ ├── Stage 3 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── BACKFILLED → DELETE_ONLY PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey-)} + │ │ └── 3 Mutation operations + │ │ ├── MakeBackfillingIndexDeleteOnly {"IndexID":2,"TableID":106} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ │ └── UpdateSchemaChangerJob {"RunningStatus":"PostCommitPhase ..."} + │ ├── Stage 4 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── DELETE_ONLY → MERGE_ONLY PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey-)} + │ │ └── 3 Mutation operations + │ │ ├── MakeBackfilledIndexMerging {"IndexID":2,"TableID":106} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ │ └── UpdateSchemaChangerJob {"RunningStatus":"PostCommitPhase ..."} + │ ├── Stage 5 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── MERGE_ONLY → MERGED PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey-)} + │ │ └── 1 Backfill operation + │ │ └── MergeIndex {"BackfilledIndexID":2,"TableID":106,"TemporaryIndexID":3} + │ ├── Stage 6 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── MERGED → WRITE_ONLY PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey-)} + │ │ ├── 1 element transitioning toward TRANSIENT_ABSENT + │ │ │ └── WRITE_ONLY → TRANSIENT_DELETE_ONLY TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey-)} + │ │ └── 4 Mutation operations + │ │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":106} + │ │ ├── MakeMergedIndexWriteOnly {"IndexID":2,"TableID":106} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ │ └── UpdateSchemaChangerJob {"RunningStatus":"PostCommitPhase ..."} + │ └── Stage 7 of 7 in PostCommitPhase + │ ├── 2 elements transitioning toward PUBLIC + │ │ ├── WRITE_ONLY → VALIDATED PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey-)} + │ │ └── WRITE_ONLY → VALIDATED ColumnNotNull:{DescID: 106 (tbl), ColumnID: 2 (serial_id+), IndexID: 2 (tbl_pkey+)} + │ └── 2 Validation operations + │ ├── ValidateIndex {"IndexID":2,"TableID":106} + │ └── ValidateColumnNotNull {"ColumnID":2,"IndexIDForValidation":2,"TableID":106} + └── PostCommitNonRevertiblePhase + ├── Stage 1 of 3 in PostCommitNonRevertiblePhase + │ ├── 4 elements transitioning toward PUBLIC + │ │ ├── WRITE_ONLY → PUBLIC Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id+)} + │ │ ├── VALIDATED → PUBLIC PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey-)} + │ │ ├── ABSENT → PUBLIC IndexName:{DescID: 106 (tbl), Name: "tbl_pkey", IndexID: 2 (tbl_pkey+)} + │ │ └── VALIDATED → PUBLIC ColumnNotNull:{DescID: 106 (tbl), ColumnID: 2 (serial_id+), IndexID: 2 (tbl_pkey+)} + │ ├── 3 elements transitioning toward TRANSIENT_ABSENT + │ │ ├── TRANSIENT_DELETE_ONLY → TRANSIENT_ABSENT TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey-)} + │ │ ├── PUBLIC → TRANSIENT_ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 3} + │ │ └── PUBLIC → TRANSIENT_ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id+), IndexID: 3} + │ ├── 2 elements transitioning toward ABSENT + │ │ ├── PUBLIC → VALIDATED PrimaryIndex:{DescID: 106 (tbl), IndexID: 1 (tbl_pkey-), ConstraintID: 1} + │ │ └── PUBLIC → ABSENT IndexName:{DescID: 106 (tbl), Name: "tbl_pkey", IndexID: 1 (tbl_pkey-)} + │ └── 12 Mutation operations + │ ├── MakePublicPrimaryIndexWriteOnly {"IndexID":1,"TableID":106} + │ ├── SetIndexName {"IndexID":1,"Name":"crdb_internal_in...","TableID":106} + │ ├── SetIndexName {"IndexID":2,"Name":"tbl_pkey","TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"Kind":2,"TableID":106} + │ ├── MakeValidatedColumnNotNullPublic {"ColumnID":2,"TableID":106} + │ ├── MakeValidatedPrimaryIndexPublic {"IndexID":2,"TableID":106} + │ ├── MakeIndexAbsent {"IndexID":3,"TableID":106} + │ ├── MakeWriteOnlyColumnPublic {"ColumnID":2,"TableID":106} + │ ├── RefreshStats {"TableID":106} + │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"PostCommitNonRev..."} + ├── Stage 2 of 3 in PostCommitNonRevertiblePhase + │ ├── 2 elements transitioning toward ABSENT + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 1 (tbl_pkey-)} + │ │ └── VALIDATED → DELETE_ONLY PrimaryIndex:{DescID: 106 (tbl), IndexID: 1 (tbl_pkey-), ConstraintID: 1} + │ └── 4 Mutation operations + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":1,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":1,"TableID":106} + │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"PostCommitNonRev..."} + └── Stage 3 of 3 in PostCommitNonRevertiblePhase + ├── 1 element transitioning toward TRANSIENT_ABSENT + │ └── PUBLIC → TRANSIENT_ABSENT IndexData:{DescID: 106 (tbl), IndexID: 3} + ├── 2 elements transitioning toward ABSENT + │ ├── DELETE_ONLY → ABSENT PrimaryIndex:{DescID: 106 (tbl), IndexID: 1 (tbl_pkey-), ConstraintID: 1} + │ └── PUBLIC → ABSENT IndexData:{DescID: 106 (tbl), IndexID: 1 (tbl_pkey-)} + └── 5 Mutation operations + ├── MakeIndexAbsent {"IndexID":1,"TableID":106} + ├── CreateGCJobForIndex {"IndexID":1,"TableID":106} + ├── CreateGCJobForIndex {"IndexID":3,"TableID":106} + ├── RemoveJobStateFromDescriptor {"DescriptorID":106} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial.explain_shape b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial.explain_shape new file mode 100644 index 000000000000..9253f0462df0 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial.explain_shape @@ -0,0 +1,18 @@ +/* setup */ +CREATE DATABASE db; +CREATE TABLE db.public.tbl (i INT PRIMARY KEY); + +/* test */ +EXPLAIN (DDL, SHAPE) ALTER TABLE db.public.tbl ADD COLUMN serial_id SERIAL; +---- +Schema change plan for ALTER TABLE ‹db›.‹public›.‹tbl› ADD COLUMN ‹serial_id› INT8; + ├── execute 2 system table mutations transactions + ├── backfill using primary index tbl_pkey- in relation tbl + │ └── into tbl_pkey+ (i; serial_id+) + ├── execute 2 system table mutations transactions + ├── merge temporary indexes into backfilled indexes in relation tbl + │ └── from tbl@[3] into tbl_pkey+ + ├── execute 1 system table mutations transaction + ├── validate UNIQUE constraint backed by index tbl_pkey+ in relation tbl + ├── validate NOT NULL constraint on column serial_id+ in index tbl_pkey+ in relation tbl + └── execute 3 system table mutations transactions diff --git a/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial.side_effects b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial.side_effects new file mode 100644 index 000000000000..9faac8131640 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial.side_effects @@ -0,0 +1,634 @@ +/* setup */ +CREATE DATABASE db; +CREATE TABLE db.public.tbl (i INT PRIMARY KEY); +---- +... ++database {0 0 db} -> 104 ++schema {104 0 public} -> 105 ++object {104 105 tbl} -> 106 + +/* test */ +ALTER TABLE db.public.tbl ADD COLUMN serial_id SERIAL; +---- +begin transaction #1 +# begin StatementPhase +checking for feature: ALTER TABLE +increment telemetry for sql.schema.alter_table +increment telemetry for sql.schema.alter_table.add_column +increment telemetry for sql.schema.qualifcation.default_expr +increment telemetry for sql.schema.new_column_type.int8 +write *eventpb.AlterTable to event log: + mutationId: 1 + sql: + descriptorId: 106 + statement: ALTER TABLE ‹db›.‹public›.‹tbl› ADD COLUMN ‹serial_id› INT8 + tag: ALTER TABLE + user: root + tableName: db.public.tbl +## StatementPhase stage 1 of 1 with 10 MutationType ops +upsert descriptor #106 + ... + - columnIds: + - 1 + + - 2 + columnNames: + - i + + - serial_id + + defaultColumnId: 2 + name: primary + formatVersion: 3 + id: 106 + modificationTime: {} + + mutations: + + - column: + + defaultExpr: unique_rowid() + + id: 2 + + name: serial_id + + nullable: true + + type: + + family: IntFamily + + oid: 20 + + width: 64 + + direction: ADD + + mutationId: 1 + + state: DELETE_ONLY + + - direction: ADD + + index: + + constraintId: 2 + + 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 + + storeColumnNames: + + - serial_id + + unique: true + + version: 4 + + mutationId: 1 + + state: BACKFILLING + + - direction: ADD + + index: + + constraintId: 3 + + 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 + + storeColumnNames: + + - serial_id + + unique: true + + useDeletePreservingEncoding: true + + version: 4 + + mutationId: 1 + + state: DELETE_ONLY + name: tbl + - nextColumnId: 2 + - nextConstraintId: 2 + + nextColumnId: 3 + + nextConstraintId: 4 + nextFamilyId: 1 + - nextIndexId: 2 + + nextIndexId: 4 + nextMutationId: 1 + parentId: 104 + ... + time: {} + unexposedParentSchemaId: 105 + - 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 14 MutationType ops +upsert descriptor #106 + ... + createAsOfTime: + wallTime: "1640995200000000000" + + declarativeSchemaChangerState: + + authorization: + + userName: root + + currentStatuses: + + jobId: "1" + + nameMapping: + + columns: + + "1": i + + "2": serial_id + + "4294967294": tableoid + + "4294967295": crdb_internal_mvcc_timestamp + + families: + + "0": primary + + id: 106 + + indexes: + + "2": tbl_pkey + + name: tbl + + relevantStatements: + + - statement: + + redactedStatement: ALTER TABLE ‹db›.‹public›.‹tbl› ADD COLUMN ‹serial_id› INT8 + + statement: ALTER TABLE db.public.tbl ADD COLUMN serial_id SERIAL8 + + statementTag: ALTER TABLE + + revertible: true + + targetRanks: + + targets: + families: + - columnIds: + - 1 + + - 2 + columnNames: + - i + + - serial_id + + defaultColumnId: 2 + name: primary + formatVersion: 3 + id: 106 + modificationTime: {} + + mutations: + + - column: + + defaultExpr: unique_rowid() + + id: 2 + + name: serial_id + + nullable: true + + type: + + family: IntFamily + + oid: 20 + + width: 64 + + direction: ADD + + mutationId: 1 + + state: DELETE_ONLY + + - direction: ADD + + index: + + constraintId: 2 + + 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 + + storeColumnNames: + + - serial_id + + unique: true + + version: 4 + + mutationId: 1 + + state: BACKFILLING + + - direction: ADD + + index: + + constraintId: 3 + + 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 + + storeColumnNames: + + - serial_id + + unique: true + + useDeletePreservingEncoding: true + + version: 4 + + mutationId: 1 + + state: DELETE_ONLY + name: tbl + - nextColumnId: 2 + - nextConstraintId: 2 + + nextColumnId: 3 + + nextConstraintId: 4 + nextFamilyId: 1 + - nextIndexId: 2 + + nextIndexId: 4 + nextMutationId: 1 + parentId: 104 + ... + time: {} + unexposedParentSchemaId: 105 + - version: "1" + + version: "2" +persist all catalog changes to storage +create job #1 (non-cancelable: false): "ALTER TABLE db.public.tbl ADD COLUMN serial_id INT8" + descriptor IDs: [106] +# 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 5 MutationType ops +upsert descriptor #106 + table: + + checks: + + - columnIds: + + - 2 + + expr: serial_id IS NOT NULL + + isNonNullConstraint: true + + name: serial_id_auto_not_null + + validity: Validating + columns: + - id: 1 + ... + direction: ADD + mutationId: 1 + - state: DELETE_ONLY + + state: WRITE_ONLY + - direction: ADD + index: + ... + version: 4 + mutationId: 1 + - state: DELETE_ONLY + + state: WRITE_ONLY + + - constraint: + + check: + + columnIds: + + - 2 + + expr: serial_id IS NOT NULL + + isNonNullConstraint: true + + name: serial_id_auto_not_null + + validity: Validating + + constraintType: NOT_NULL + + foreignKey: {} + + name: serial_id_auto_not_null + + notNullColumn: 2 + + uniqueWithoutIndexConstraint: {} + + direction: ADD + + mutationId: 1 + + state: WRITE_ONLY + name: tbl + nextColumnId: 3 + ... + time: {} + unexposedParentSchemaId: 105 + - version: "2" + + version: "3" +persist all catalog changes to storage +update progress of schema change job #1: "PostCommitPhase stage 2 of 7 with 1 BackfillType op pending" +commit transaction #3 +begin transaction #4 +## PostCommitPhase stage 2 of 7 with 1 BackfillType op +backfill indexes [2] from index #1 in table #106 +commit transaction #4 +begin transaction #5 +## PostCommitPhase stage 3 of 7 with 3 MutationType ops +upsert descriptor #106 + ... + version: 4 + mutationId: 1 + - state: BACKFILLING + + state: DELETE_ONLY + - direction: ADD + index: + ... + time: {} + unexposedParentSchemaId: 105 + - version: "3" + + version: "4" +persist all catalog changes to storage +update progress of schema change job #1: "PostCommitPhase stage 4 of 7 with 1 MutationType op pending" +commit transaction #5 +begin transaction #6 +## PostCommitPhase stage 4 of 7 with 3 MutationType ops +upsert descriptor #106 + ... + version: 4 + mutationId: 1 + - state: DELETE_ONLY + + state: MERGING + - direction: ADD + index: + ... + time: {} + unexposedParentSchemaId: 105 + - version: "4" + + version: "5" +persist all catalog changes to storage +update progress of schema change job #1: "PostCommitPhase stage 5 of 7 with 1 BackfillType op pending" +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 #106 +commit transaction #7 +begin transaction #8 +## PostCommitPhase stage 6 of 7 with 4 MutationType ops +upsert descriptor #106 + ... + version: 4 + mutationId: 1 + - state: MERGING + - - direction: ADD + + state: WRITE_ONLY + + - direction: DROP + index: + constraintId: 3 + ... + version: 4 + mutationId: 1 + - state: WRITE_ONLY + + state: DELETE_ONLY + - constraint: + check: + ... + time: {} + unexposedParentSchemaId: 105 + - version: "5" + + version: "6" +persist all catalog changes to storage +update progress of schema change job #1: "PostCommitPhase stage 7 of 7 with 2 ValidationType ops pending" +commit transaction #8 +begin transaction #9 +## PostCommitPhase stage 7 of 7 with 2 ValidationType ops +validate forward indexes [2] in table #106 +validate CHECK constraint serial_id_auto_not_null in table #106 +commit transaction #9 +begin transaction #10 +## PostCommitNonRevertiblePhase stage 1 of 3 with 12 MutationType ops +upsert descriptor #106 + table: + - checks: + - - columnIds: + - - 2 + - expr: serial_id IS NOT NULL + - isNonNullConstraint: true + - name: serial_id_auto_not_null + - validity: Validating + + checks: [] + columns: + - id: 1 + ... + oid: 20 + width: 64 + + - defaultExpr: unique_rowid() + + id: 2 + + name: serial_id + + type: + + family: IntFamily + + oid: 20 + + width: 64 + createAsOfTime: + wallTime: "1640995200000000000" + ... + statement: ALTER TABLE db.public.tbl ADD COLUMN serial_id SERIAL8 + statementTag: ALTER TABLE + - revertible: true + targetRanks: + targets: + ... + modificationTime: {} + mutations: + - - column: + - defaultExpr: unique_rowid() + - id: 2 + - name: serial_id + - nullable: true + - type: + - family: IntFamily + - oid: 20 + - width: 64 + - direction: ADD + - mutationId: 1 + - state: WRITE_ONLY + - - direction: ADD + - index: + - constraintId: 2 + - 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 + - storeColumnNames: + - - serial_id + - unique: true + - version: 4 + - mutationId: 1 + - state: WRITE_ONLY + - direction: DROP + index: + - constraintId: 3 + - 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: {} + - storeColumnIds: + - - 2 + - storeColumnNames: + - - serial_id + unique: true + - useDeletePreservingEncoding: true + version: 4 + mutationId: 1 + - state: DELETE_ONLY + - - constraint: + - check: + - columnIds: + - - 2 + - expr: serial_id IS NOT NULL + - isNonNullConstraint: true + - name: serial_id_auto_not_null + - validity: Validating + - constraintType: NOT_NULL + - foreignKey: {} + - name: serial_id_auto_not_null + - notNullColumn: 2 + - uniqueWithoutIndexConstraint: {} + - direction: ADD + - mutationId: 1 + state: WRITE_ONLY + name: tbl + ... + parentId: 104 + primaryIndex: + - constraintId: 1 + - createdAtNanos: "1640995200000000000" + + constraintId: 2 + + createdExplicitly: true + encodingType: 1 + foreignKey: {} + geoConfig: {} + - id: 1 + + id: 2 + interleave: {} + keyColumnDirections: + ... + partitioning: {} + sharded: {} + + storeColumnIds: + + - 2 + + storeColumnNames: + + - serial_id + unique: true + version: 4 + ... + time: {} + unexposedParentSchemaId: 105 + - version: "6" + + version: "7" +persist all catalog changes to storage +adding table for stats refresh: 106 +update progress of schema change job #1: "PostCommitNonRevertiblePhase stage 2 of 3 with 2 MutationType ops pending" +set schema change job #1 to non-cancellable +commit transaction #10 +begin transaction #11 +## PostCommitNonRevertiblePhase stage 2 of 3 with 4 MutationType ops +upsert descriptor #106 + ... + version: 4 + mutationId: 1 + - state: WRITE_ONLY + + state: DELETE_ONLY + name: tbl + nextColumnId: 3 + ... + time: {} + unexposedParentSchemaId: 105 + - version: "7" + + version: "8" +persist all catalog changes to storage +update progress of schema change job #1: "PostCommitNonRevertiblePhase stage 3 of 3 with 3 MutationType ops pending" +commit transaction #11 +begin transaction #12 +## PostCommitNonRevertiblePhase stage 3 of 3 with 5 MutationType ops +upsert descriptor #106 + ... + createAsOfTime: + wallTime: "1640995200000000000" + - declarativeSchemaChangerState: + - authorization: + - userName: root + - currentStatuses: + - jobId: "1" + - nameMapping: + - columns: + - "1": i + - "2": serial_id + - "4294967294": tableoid + - "4294967295": crdb_internal_mvcc_timestamp + - families: + - "0": primary + - id: 106 + - indexes: + - "2": tbl_pkey + - name: tbl + - relevantStatements: + - - statement: + - redactedStatement: ALTER TABLE ‹db›.‹public›.‹tbl› ADD COLUMN ‹serial_id› INT8 + - statement: ALTER TABLE db.public.tbl ADD COLUMN serial_id SERIAL8 + - statementTag: ALTER TABLE + - targetRanks: + - targets: + families: + - columnIds: + ... + id: 106 + 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: {} + - unique: true + - version: 4 + - mutationId: 1 + - state: DELETE_ONLY + + mutations: [] + name: tbl + nextColumnId: 3 + ... + time: {} + unexposedParentSchemaId: 105 + - version: "8" + + version: "9" +persist all catalog changes to storage +create job #2 (non-cancelable: true): "GC for ALTER TABLE db.public.tbl ADD COLUMN serial_id INT8" + descriptor IDs: [106] +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: 106 +commit transaction #12 +notified job registry to adopt jobs: [2] +# end PostCommitPhase diff --git a/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_1_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_1_of_7.explain new file mode 100644 index 000000000000..1110227fae5a --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_1_of_7.explain @@ -0,0 +1,36 @@ +/* setup */ +CREATE DATABASE db; +CREATE TABLE db.public.tbl (i INT PRIMARY KEY); + +/* test */ +ALTER TABLE db.public.tbl ADD COLUMN serial_id SERIAL; +EXPLAIN (DDL) rollback at post-commit stage 1 of 7; +---- +Schema change plan for rolling back ALTER TABLE ‹db›.public.‹tbl› ADD COLUMN ‹serial_id› INT8; + └── PostCommitNonRevertiblePhase + └── Stage 1 of 1 in PostCommitNonRevertiblePhase + ├── 11 elements transitioning toward ABSENT + │ ├── DELETE_ONLY → ABSENT Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id-)} + │ ├── PUBLIC → ABSENT ColumnName:{DescID: 106 (tbl), Name: "serial_id", ColumnID: 2 (serial_id-)} + │ ├── PUBLIC → ABSENT ColumnType:{DescID: 106 (tbl), ColumnFamilyID: 0 (primary), ColumnID: 2 (serial_id-), TypeName: "INT8"} + │ ├── PUBLIC → ABSENT ColumnDefaultExpression:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), Expr: unique_rowid()} + │ ├── BACKFILL_ONLY → ABSENT PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey-), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 2 (tbl_pkey-)} + │ ├── PUBLIC → ABSENT IndexData:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey-)} + │ ├── DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 3} + │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 2 (tbl_pkey-)} + │ └── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 3} + └── 12 Mutation operations + ├── SetColumnName {"ColumnID":2,"Name":"crdb_internal_co...","TableID":106} + ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":2,"TableID":106} + ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"TableID":106} + ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"Kind":2,"TableID":106} + ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"Kind":2,"TableID":106} + ├── RemoveColumnDefaultExpression {"ColumnID":2,"TableID":106} + ├── MakeIndexAbsent {"IndexID":2,"TableID":106} + ├── CreateGCJobForIndex {"IndexID":2,"TableID":106} + ├── MakeIndexAbsent {"IndexID":3,"TableID":106} + ├── MakeDeleteOnlyColumnAbsent {"ColumnID":2,"TableID":106} + ├── RemoveJobStateFromDescriptor {"DescriptorID":106} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_2_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_2_of_7.explain new file mode 100644 index 000000000000..46fcbfbff31c --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_2_of_7.explain @@ -0,0 +1,49 @@ +/* setup */ +CREATE DATABASE db; +CREATE TABLE db.public.tbl (i INT PRIMARY KEY); + +/* test */ +ALTER TABLE db.public.tbl ADD COLUMN serial_id SERIAL; +EXPLAIN (DDL) rollback at post-commit stage 2 of 7; +---- +Schema change plan for rolling back ALTER TABLE ‹db›.public.‹tbl› ADD COLUMN ‹serial_id› INT8; + └── PostCommitNonRevertiblePhase + ├── Stage 1 of 2 in PostCommitNonRevertiblePhase + │ ├── 9 elements transitioning toward ABSENT + │ │ ├── WRITE_ONLY → DELETE_ONLY Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id-)} + │ │ ├── PUBLIC → ABSENT ColumnName:{DescID: 106 (tbl), Name: "serial_id", ColumnID: 2 (serial_id-)} + │ │ ├── BACKFILL_ONLY → ABSENT PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey-), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 2 (tbl_pkey-)} + │ │ ├── WRITE_ONLY → DELETE_ONLY TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 3} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 2 (tbl_pkey-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 3} + │ │ └── WRITE_ONLY → ABSENT ColumnNotNull:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 2 (tbl_pkey-)} + │ └── 11 Mutation operations + │ ├── MakeWriteOnlyColumnDeleteOnly {"ColumnID":2,"TableID":106} + │ ├── SetColumnName {"ColumnID":2,"Name":"crdb_internal_co...","TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":2,"TableID":106} + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"Kind":2,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"Kind":2,"TableID":106} + │ ├── MakeIndexAbsent {"IndexID":2,"TableID":106} + │ ├── RemoveColumnNotNull {"ColumnID":2,"TableID":106} + │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"PostCommitNonRev..."} + └── Stage 2 of 2 in PostCommitNonRevertiblePhase + ├── 6 elements transitioning toward ABSENT + │ ├── DELETE_ONLY → ABSENT Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id-)} + │ ├── PUBLIC → ABSENT ColumnType:{DescID: 106 (tbl), ColumnFamilyID: 0 (primary), ColumnID: 2 (serial_id-), TypeName: "INT8"} + │ ├── PUBLIC → ABSENT ColumnDefaultExpression:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), Expr: unique_rowid()} + │ ├── PUBLIC → ABSENT IndexData:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey-)} + │ ├── DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ └── PUBLIC → ABSENT IndexData:{DescID: 106 (tbl), IndexID: 3} + └── 7 Mutation operations + ├── RemoveColumnDefaultExpression {"ColumnID":2,"TableID":106} + ├── CreateGCJobForIndex {"IndexID":2,"TableID":106} + ├── MakeIndexAbsent {"IndexID":3,"TableID":106} + ├── CreateGCJobForIndex {"IndexID":3,"TableID":106} + ├── MakeDeleteOnlyColumnAbsent {"ColumnID":2,"TableID":106} + ├── RemoveJobStateFromDescriptor {"DescriptorID":106} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_3_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_3_of_7.explain new file mode 100644 index 000000000000..343fb79a2d6e --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_3_of_7.explain @@ -0,0 +1,49 @@ +/* setup */ +CREATE DATABASE db; +CREATE TABLE db.public.tbl (i INT PRIMARY KEY); + +/* test */ +ALTER TABLE db.public.tbl ADD COLUMN serial_id SERIAL; +EXPLAIN (DDL) rollback at post-commit stage 3 of 7; +---- +Schema change plan for rolling back ALTER TABLE ‹db›.public.‹tbl› ADD COLUMN ‹serial_id› INT8; + └── PostCommitNonRevertiblePhase + ├── Stage 1 of 2 in PostCommitNonRevertiblePhase + │ ├── 9 elements transitioning toward ABSENT + │ │ ├── WRITE_ONLY → DELETE_ONLY Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id-)} + │ │ ├── PUBLIC → ABSENT ColumnName:{DescID: 106 (tbl), Name: "serial_id", ColumnID: 2 (serial_id-)} + │ │ ├── BACKFILL_ONLY → ABSENT PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey-), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 2 (tbl_pkey-)} + │ │ ├── WRITE_ONLY → DELETE_ONLY TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 3} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 2 (tbl_pkey-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 3} + │ │ └── WRITE_ONLY → ABSENT ColumnNotNull:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 2 (tbl_pkey-)} + │ └── 11 Mutation operations + │ ├── MakeWriteOnlyColumnDeleteOnly {"ColumnID":2,"TableID":106} + │ ├── SetColumnName {"ColumnID":2,"Name":"crdb_internal_co...","TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":2,"TableID":106} + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"Kind":2,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"Kind":2,"TableID":106} + │ ├── MakeIndexAbsent {"IndexID":2,"TableID":106} + │ ├── RemoveColumnNotNull {"ColumnID":2,"TableID":106} + │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"PostCommitNonRev..."} + └── Stage 2 of 2 in PostCommitNonRevertiblePhase + ├── 6 elements transitioning toward ABSENT + │ ├── DELETE_ONLY → ABSENT Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id-)} + │ ├── PUBLIC → ABSENT ColumnType:{DescID: 106 (tbl), ColumnFamilyID: 0 (primary), ColumnID: 2 (serial_id-), TypeName: "INT8"} + │ ├── PUBLIC → ABSENT ColumnDefaultExpression:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), Expr: unique_rowid()} + │ ├── PUBLIC → ABSENT IndexData:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey-)} + │ ├── DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ └── PUBLIC → ABSENT IndexData:{DescID: 106 (tbl), IndexID: 3} + └── 7 Mutation operations + ├── RemoveColumnDefaultExpression {"ColumnID":2,"TableID":106} + ├── CreateGCJobForIndex {"IndexID":2,"TableID":106} + ├── MakeIndexAbsent {"IndexID":3,"TableID":106} + ├── CreateGCJobForIndex {"IndexID":3,"TableID":106} + ├── MakeDeleteOnlyColumnAbsent {"ColumnID":2,"TableID":106} + ├── RemoveJobStateFromDescriptor {"DescriptorID":106} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_4_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_4_of_7.explain new file mode 100644 index 000000000000..ebd1507bad1a --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_4_of_7.explain @@ -0,0 +1,49 @@ +/* setup */ +CREATE DATABASE db; +CREATE TABLE db.public.tbl (i INT PRIMARY KEY); + +/* test */ +ALTER TABLE db.public.tbl ADD COLUMN serial_id SERIAL; +EXPLAIN (DDL) rollback at post-commit stage 4 of 7; +---- +Schema change plan for rolling back ALTER TABLE ‹db›.public.‹tbl› ADD COLUMN ‹serial_id› INT8; + └── PostCommitNonRevertiblePhase + ├── Stage 1 of 2 in PostCommitNonRevertiblePhase + │ ├── 9 elements transitioning toward ABSENT + │ │ ├── WRITE_ONLY → DELETE_ONLY Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id-)} + │ │ ├── PUBLIC → ABSENT ColumnName:{DescID: 106 (tbl), Name: "serial_id", ColumnID: 2 (serial_id-)} + │ │ ├── DELETE_ONLY → ABSENT PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey-), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 2 (tbl_pkey-)} + │ │ ├── WRITE_ONLY → DELETE_ONLY TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 3} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 2 (tbl_pkey-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 3} + │ │ └── WRITE_ONLY → ABSENT ColumnNotNull:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 2 (tbl_pkey-)} + │ └── 11 Mutation operations + │ ├── MakeWriteOnlyColumnDeleteOnly {"ColumnID":2,"TableID":106} + │ ├── SetColumnName {"ColumnID":2,"Name":"crdb_internal_co...","TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":2,"TableID":106} + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"Kind":2,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"Kind":2,"TableID":106} + │ ├── MakeIndexAbsent {"IndexID":2,"TableID":106} + │ ├── RemoveColumnNotNull {"ColumnID":2,"TableID":106} + │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"PostCommitNonRev..."} + └── Stage 2 of 2 in PostCommitNonRevertiblePhase + ├── 6 elements transitioning toward ABSENT + │ ├── DELETE_ONLY → ABSENT Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id-)} + │ ├── PUBLIC → ABSENT ColumnType:{DescID: 106 (tbl), ColumnFamilyID: 0 (primary), ColumnID: 2 (serial_id-), TypeName: "INT8"} + │ ├── PUBLIC → ABSENT ColumnDefaultExpression:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), Expr: unique_rowid()} + │ ├── PUBLIC → ABSENT IndexData:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey-)} + │ ├── DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ └── PUBLIC → ABSENT IndexData:{DescID: 106 (tbl), IndexID: 3} + └── 7 Mutation operations + ├── RemoveColumnDefaultExpression {"ColumnID":2,"TableID":106} + ├── CreateGCJobForIndex {"IndexID":2,"TableID":106} + ├── MakeIndexAbsent {"IndexID":3,"TableID":106} + ├── CreateGCJobForIndex {"IndexID":3,"TableID":106} + ├── MakeDeleteOnlyColumnAbsent {"ColumnID":2,"TableID":106} + ├── RemoveJobStateFromDescriptor {"DescriptorID":106} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_5_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_5_of_7.explain new file mode 100644 index 000000000000..c18d7bb02917 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_5_of_7.explain @@ -0,0 +1,51 @@ +/* setup */ +CREATE DATABASE db; +CREATE TABLE db.public.tbl (i INT PRIMARY KEY); + +/* test */ +ALTER TABLE db.public.tbl ADD COLUMN serial_id SERIAL; +EXPLAIN (DDL) rollback at post-commit stage 5 of 7; +---- +Schema change plan for rolling back ALTER TABLE ‹db›.public.‹tbl› ADD COLUMN ‹serial_id› INT8; + └── PostCommitNonRevertiblePhase + ├── Stage 1 of 2 in PostCommitNonRevertiblePhase + │ ├── 9 elements transitioning toward ABSENT + │ │ ├── WRITE_ONLY → DELETE_ONLY Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id-)} + │ │ ├── PUBLIC → ABSENT ColumnName:{DescID: 106 (tbl), Name: "serial_id", ColumnID: 2 (serial_id-)} + │ │ ├── MERGE_ONLY → DELETE_ONLY PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey-), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 2 (tbl_pkey-)} + │ │ ├── WRITE_ONLY → DELETE_ONLY TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 3} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 2 (tbl_pkey-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 3} + │ │ └── WRITE_ONLY → ABSENT ColumnNotNull:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 2 (tbl_pkey-)} + │ └── 11 Mutation operations + │ ├── MakeWriteOnlyColumnDeleteOnly {"ColumnID":2,"TableID":106} + │ ├── SetColumnName {"ColumnID":2,"Name":"crdb_internal_co...","TableID":106} + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"Kind":2,"TableID":106} + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":2,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":2,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"Kind":2,"TableID":106} + │ ├── RemoveColumnNotNull {"ColumnID":2,"TableID":106} + │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"PostCommitNonRev..."} + └── Stage 2 of 2 in PostCommitNonRevertiblePhase + ├── 7 elements transitioning toward ABSENT + │ ├── DELETE_ONLY → ABSENT Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id-)} + │ ├── PUBLIC → ABSENT ColumnType:{DescID: 106 (tbl), ColumnFamilyID: 0 (primary), ColumnID: 2 (serial_id-), TypeName: "INT8"} + │ ├── PUBLIC → ABSENT ColumnDefaultExpression:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), Expr: unique_rowid()} + │ ├── DELETE_ONLY → ABSENT PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey-), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ ├── PUBLIC → ABSENT IndexData:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey-)} + │ ├── DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ └── PUBLIC → ABSENT IndexData:{DescID: 106 (tbl), IndexID: 3} + └── 8 Mutation operations + ├── RemoveColumnDefaultExpression {"ColumnID":2,"TableID":106} + ├── MakeIndexAbsent {"IndexID":2,"TableID":106} + ├── CreateGCJobForIndex {"IndexID":2,"TableID":106} + ├── MakeIndexAbsent {"IndexID":3,"TableID":106} + ├── CreateGCJobForIndex {"IndexID":3,"TableID":106} + ├── MakeDeleteOnlyColumnAbsent {"ColumnID":2,"TableID":106} + ├── RemoveJobStateFromDescriptor {"DescriptorID":106} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_6_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_6_of_7.explain new file mode 100644 index 000000000000..d40517a05d1e --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_6_of_7.explain @@ -0,0 +1,51 @@ +/* setup */ +CREATE DATABASE db; +CREATE TABLE db.public.tbl (i INT PRIMARY KEY); + +/* test */ +ALTER TABLE db.public.tbl ADD COLUMN serial_id SERIAL; +EXPLAIN (DDL) rollback at post-commit stage 6 of 7; +---- +Schema change plan for rolling back ALTER TABLE ‹db›.public.‹tbl› ADD COLUMN ‹serial_id› INT8; + └── PostCommitNonRevertiblePhase + ├── Stage 1 of 2 in PostCommitNonRevertiblePhase + │ ├── 9 elements transitioning toward ABSENT + │ │ ├── WRITE_ONLY → DELETE_ONLY Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id-)} + │ │ ├── PUBLIC → ABSENT ColumnName:{DescID: 106 (tbl), Name: "serial_id", ColumnID: 2 (serial_id-)} + │ │ ├── MERGE_ONLY → DELETE_ONLY PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey-), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 2 (tbl_pkey-)} + │ │ ├── WRITE_ONLY → DELETE_ONLY TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 3} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 2 (tbl_pkey-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 3} + │ │ └── WRITE_ONLY → ABSENT ColumnNotNull:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 2 (tbl_pkey-)} + │ └── 11 Mutation operations + │ ├── MakeWriteOnlyColumnDeleteOnly {"ColumnID":2,"TableID":106} + │ ├── SetColumnName {"ColumnID":2,"Name":"crdb_internal_co...","TableID":106} + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"Kind":2,"TableID":106} + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":2,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":2,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"Kind":2,"TableID":106} + │ ├── RemoveColumnNotNull {"ColumnID":2,"TableID":106} + │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"PostCommitNonRev..."} + └── Stage 2 of 2 in PostCommitNonRevertiblePhase + ├── 7 elements transitioning toward ABSENT + │ ├── DELETE_ONLY → ABSENT Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id-)} + │ ├── PUBLIC → ABSENT ColumnType:{DescID: 106 (tbl), ColumnFamilyID: 0 (primary), ColumnID: 2 (serial_id-), TypeName: "INT8"} + │ ├── PUBLIC → ABSENT ColumnDefaultExpression:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), Expr: unique_rowid()} + │ ├── DELETE_ONLY → ABSENT PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey-), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ ├── PUBLIC → ABSENT IndexData:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey-)} + │ ├── DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ └── PUBLIC → ABSENT IndexData:{DescID: 106 (tbl), IndexID: 3} + └── 8 Mutation operations + ├── RemoveColumnDefaultExpression {"ColumnID":2,"TableID":106} + ├── MakeIndexAbsent {"IndexID":2,"TableID":106} + ├── CreateGCJobForIndex {"IndexID":2,"TableID":106} + ├── MakeIndexAbsent {"IndexID":3,"TableID":106} + ├── CreateGCJobForIndex {"IndexID":3,"TableID":106} + ├── MakeDeleteOnlyColumnAbsent {"ColumnID":2,"TableID":106} + ├── RemoveJobStateFromDescriptor {"DescriptorID":106} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_7_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_7_of_7.explain new file mode 100644 index 000000000000..e6f9a9498835 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/add_column_serial/add_column_serial__rollback_7_of_7.explain @@ -0,0 +1,49 @@ +/* setup */ +CREATE DATABASE db; +CREATE TABLE db.public.tbl (i INT PRIMARY KEY); + +/* test */ +ALTER TABLE db.public.tbl ADD COLUMN serial_id SERIAL; +EXPLAIN (DDL) rollback at post-commit stage 7 of 7; +---- +Schema change plan for rolling back ALTER TABLE ‹db›.public.‹tbl› ADD COLUMN ‹serial_id› INT8; + └── PostCommitNonRevertiblePhase + ├── Stage 1 of 2 in PostCommitNonRevertiblePhase + │ ├── 9 elements transitioning toward ABSENT + │ │ ├── WRITE_ONLY → DELETE_ONLY Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id-)} + │ │ ├── PUBLIC → ABSENT ColumnName:{DescID: 106 (tbl), Name: "serial_id", ColumnID: 2 (serial_id-)} + │ │ ├── WRITE_ONLY → DELETE_ONLY PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey-), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 2 (tbl_pkey-)} + │ │ ├── TRANSIENT_DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 106 (tbl), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 1 (i), IndexID: 3} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 2 (tbl_pkey-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 3} + │ │ └── WRITE_ONLY → ABSENT ColumnNotNull:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), IndexID: 2 (tbl_pkey-)} + │ └── 11 Mutation operations + │ ├── MakeWriteOnlyColumnDeleteOnly {"ColumnID":2,"TableID":106} + │ ├── SetColumnName {"ColumnID":2,"Name":"crdb_internal_co...","TableID":106} + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":2,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":2,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"Kind":2,"TableID":106} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"Kind":2,"TableID":106} + │ ├── MakeIndexAbsent {"IndexID":3,"TableID":106} + │ ├── RemoveColumnNotNull {"ColumnID":2,"TableID":106} + │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"PostCommitNonRev..."} + └── Stage 2 of 2 in PostCommitNonRevertiblePhase + ├── 6 elements transitioning toward ABSENT + │ ├── DELETE_ONLY → ABSENT Column:{DescID: 106 (tbl), ColumnID: 2 (serial_id-)} + │ ├── PUBLIC → ABSENT ColumnType:{DescID: 106 (tbl), ColumnFamilyID: 0 (primary), ColumnID: 2 (serial_id-), TypeName: "INT8"} + │ ├── PUBLIC → ABSENT ColumnDefaultExpression:{DescID: 106 (tbl), ColumnID: 2 (serial_id-), Expr: unique_rowid()} + │ ├── DELETE_ONLY → ABSENT PrimaryIndex:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey-), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (tbl_pkey+)} + │ ├── PUBLIC → ABSENT IndexData:{DescID: 106 (tbl), IndexID: 2 (tbl_pkey-)} + │ └── PUBLIC → ABSENT IndexData:{DescID: 106 (tbl), IndexID: 3} + └── 7 Mutation operations + ├── RemoveColumnDefaultExpression {"ColumnID":2,"TableID":106} + ├── MakeIndexAbsent {"IndexID":2,"TableID":106} + ├── CreateGCJobForIndex {"IndexID":2,"TableID":106} + ├── CreateGCJobForIndex {"IndexID":3,"TableID":106} + ├── MakeDeleteOnlyColumnAbsent {"ColumnID":2,"TableID":106} + ├── RemoveJobStateFromDescriptor {"DescriptorID":106} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/serial.go b/pkg/sql/serial.go index e5f4808aaf2f..76e94a1aea82 100644 --- a/pkg/sql/serial.go +++ b/pkg/sql/serial.go @@ -19,8 +19,6 @@ import ( "github.com/cockroachdb/cockroach/pkg/settings" "github.com/cockroachdb/cockroach/pkg/sql/catalog" "github.com/cockroachdb/cockroach/pkg/sql/catalog/resolver" - "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" - "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgnotice" "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" "github.com/cockroachdb/cockroach/pkg/sql/sessiondatapb" @@ -132,14 +130,13 @@ func (p *planner) generateSerialInColumnDef( error, ) { - if err := assertValidSerialColumnDef(d, tableName); err != nil { + if err := catalog.AssertValidSerialColumnDef(d, tableName); err != nil { return nil, nil, nil, nil, err } newSpec := *d - // Make the column non-nullable in all cases. PostgreSQL requires - // this. + // Column is non-nullable in all cases. PostgreSQL requires this. newSpec.Nullable.Nullability = tree.NotNull // Clear the IsSerial bit now that it's been remapped. @@ -356,7 +353,7 @@ func SimplifySerialInColumnDefWithRowID( return nil } - if err := assertValidSerialColumnDef(d, tableName); err != nil { + if err := catalog.AssertValidSerialColumnDef(d, tableName); err != nil { return err } @@ -374,30 +371,3 @@ func SimplifySerialInColumnDefWithRowID( return nil } - -func assertValidSerialColumnDef(d *tree.ColumnTableDef, tableName *tree.TableName) error { - if d.HasDefaultExpr() { - // SERIAL implies a new default expression, we can't have one to - // start with. This is the error produced by pg in such case. - return pgerror.Newf(pgcode.Syntax, - "multiple default values specified for column %q of table %q", - tree.ErrString(&d.Name), tree.ErrString(tableName)) - } - - if d.Nullable.Nullability == tree.Null { - // SERIAL implies a non-NULL column, we can't accept a nullability - // spec. This is the error produced by pg in such case. - return pgerror.Newf(pgcode.Syntax, - "conflicting NULL/NOT NULL declarations for column %q of table %q", - tree.ErrString(&d.Name), tree.ErrString(tableName)) - } - - if d.Computed.Expr != nil { - // SERIAL cannot be a computed column. - return pgerror.Newf(pgcode.Syntax, - "SERIAL column %q of table %q cannot be computed", - tree.ErrString(&d.Name), tree.ErrString(tableName)) - } - - return nil -}