From d05c9699d165ed760d5162640be2f635874aca31 Mon Sep 17 00:00:00 2001 From: Xiang Gu Date: Tue, 13 Dec 2022 13:33:00 -0500 Subject: [PATCH] schemachanger: Enable `ADD FOREIGN KEY` by default and add tests --- .../testdata/benchmark_expectations | 4 +- .../backup_base_generated_test.go | 5 + pkg/sql/logictest/testdata/logic_test/fk | 2 +- pkg/sql/schema_changer_test.go | 2 + .../internal/scbuildstmt/alter_table.go | 8 + .../schemachanger/scbuild/testdata/drop_table | 4 +- .../testdata/unimplemented_alter_table | 8 - .../scplan/internal/rules/assertions_test.go | 5 + .../scplan/internal/rules/helpers.go | 7 +- .../scplan/internal/rules/op_drop.go | 1 + .../scplan/internal/rules/testdata/deprules | 241 ++++++++++++------ .../scplan/internal/rules/testdata/oprules | 2 +- .../schemachanger/scplan/testdata/drop_table | 66 +++-- pkg/sql/schemachanger/screl/attr.go | 1 + pkg/sql/schemachanger/screl/query_test.go | 6 +- .../schemachanger/sctest_generated_test.go | 25 ++ .../end_to_end/alter_table_add_foreign_key | 208 +++++++++++++++ .../explain/alter_table_add_foreign_key | 36 +++ ...lter_table_add_foreign_key.rollback_1_of_2 | 19 ++ ...lter_table_add_foreign_key.rollback_2_of_2 | 19 ++ .../alter_table_add_foreign_key | 121 +++++++++ ...lter_table_add_foreign_key.rollback_1_of_2 | 51 ++++ ...lter_table_add_foreign_key.rollback_2_of_2 | 51 ++++ 23 files changed, 777 insertions(+), 115 deletions(-) create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/alter_table_add_foreign_key create mode 100644 pkg/sql/schemachanger/testdata/explain/alter_table_add_foreign_key create mode 100644 pkg/sql/schemachanger/testdata/explain/alter_table_add_foreign_key.rollback_1_of_2 create mode 100644 pkg/sql/schemachanger/testdata/explain/alter_table_add_foreign_key.rollback_2_of_2 create mode 100644 pkg/sql/schemachanger/testdata/explain_verbose/alter_table_add_foreign_key create mode 100644 pkg/sql/schemachanger/testdata/explain_verbose/alter_table_add_foreign_key.rollback_1_of_2 create mode 100644 pkg/sql/schemachanger/testdata/explain_verbose/alter_table_add_foreign_key.rollback_2_of_2 diff --git a/pkg/bench/rttanalysis/testdata/benchmark_expectations b/pkg/bench/rttanalysis/testdata/benchmark_expectations index 43805aa131a9..8ce14a971792 100644 --- a/pkg/bench/rttanalysis/testdata/benchmark_expectations +++ b/pkg/bench/rttanalysis/testdata/benchmark_expectations @@ -9,8 +9,8 @@ exp,benchmark 12,AlterTableAddColumn/alter_table_add_2_columns 12,AlterTableAddColumn/alter_table_add_3_columns 13,AlterTableAddForeignKey/alter_table_add_1_foreign_key -17,AlterTableAddForeignKey/alter_table_add_2_foreign_keys -21,AlterTableAddForeignKey/alter_table_add_3_foreign_keys +13,AlterTableAddForeignKey/alter_table_add_2_foreign_keys +13,AlterTableAddForeignKey/alter_table_add_3_foreign_keys 13,AlterTableAddForeignKey/alter_table_add_foreign_key_with_3_columns 8,AlterTableConfigureZone/alter_table_configure_zone_5_replicas 8,AlterTableConfigureZone/alter_table_configure_zone_7_replicas_ diff --git a/pkg/ccl/schemachangerccl/backup_base_generated_test.go b/pkg/ccl/schemachangerccl/backup_base_generated_test.go index 128b8172fd88..b66b7c6bf0a5 100644 --- a/pkg/ccl/schemachangerccl/backup_base_generated_test.go +++ b/pkg/ccl/schemachangerccl/backup_base_generated_test.go @@ -48,6 +48,11 @@ func TestBackupbase_alter_table_add_check_with_seq_and_udt(t *testing.T) { defer log.Scope(t).Close(t) sctest.Backup(t, "pkg/sql/schemachanger/testdata/end_to_end/alter_table_add_check_with_seq_and_udt", newCluster) } +func TestBackupbase_alter_table_add_foreign_key(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + sctest.Backup(t, "pkg/sql/schemachanger/testdata/end_to_end/alter_table_add_foreign_key", newCluster) +} func TestBackupbase_alter_table_add_primary_key_drop_rowid(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) diff --git a/pkg/sql/logictest/testdata/logic_test/fk b/pkg/sql/logictest/testdata/logic_test/fk index 0fa7277b8575..93dfa5dd1780 100644 --- a/pkg/sql/logictest/testdata/logic_test/fk +++ b/pkg/sql/logictest/testdata/logic_test/fk @@ -2715,7 +2715,7 @@ statement ok CREATE TABLE child_duplicate_cols (id INT, parent_id INT, PRIMARY KEY (id)) # The fk constraint is invalid because it has duplicate columns, so automatically adding the index fails -statement error foreign key contains duplicate column \"parent_id\" +statement error pgcode 42830 foreign key contains duplicate column ".*parent_id" ALTER TABLE child_duplicate_cols ADD CONSTRAINT fk FOREIGN KEY (parent_id, parent_id) references parent statement ok diff --git a/pkg/sql/schema_changer_test.go b/pkg/sql/schema_changer_test.go index 393c043a9d24..d537004d8214 100644 --- a/pkg/sql/schema_changer_test.go +++ b/pkg/sql/schema_changer_test.go @@ -5544,6 +5544,7 @@ func TestTableValidityWhileAddingFK(t *testing.T) { CREATE DATABASE t; CREATE TABLE t.child (a INT PRIMARY KEY, b INT, INDEX (b)); CREATE TABLE t.parent (a INT PRIMARY KEY); +SET use_declarative_schema_changer = off; `); err != nil { t.Fatal(err) } @@ -6763,6 +6764,7 @@ func TestRollbackForeignKeyAddition(t *testing.T) { tdb.Exec(t, `CREATE DATABASE db`) tdb.Exec(t, `CREATE TABLE db.t (a INT PRIMARY KEY)`) tdb.Exec(t, `CREATE TABLE db.t2 (a INT)`) + tdb.Exec(t, `SET use_declarative_schema_changer = off`) g := ctxgroup.WithContext(ctx) g.GoCtx(func(ctx context.Context) error { diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table.go index b7db499073b3..644499dfcac7 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table.go @@ -61,6 +61,11 @@ var supportedAlterTableStatements = map[reflect.Type]supportedAlterTableCommand{ return true } + // Support ALTER TABLE ... ADD CONSTRAINT FOREIGN KEY + if _, ok := t.ConstraintDef.(*tree.ForeignKeyConstraintTableDef); ok && t.ValidationBehavior == tree.ValidationDefault { + return true + } + return false }}, } @@ -72,6 +77,7 @@ var supportedAlterTableStatements = map[reflect.Type]supportedAlterTableCommand{ var alterTableAddConstraintMinSupportedClusterVersion = map[string]clusterversion.Key{ "ADD_PRIMARY_KEY_DEFAULT": clusterversion.V22_2Start, "ADD_CHECK_DEFAULT": clusterversion.V23_1Start, + "ADD_FOREIGN_KEY_DEFAULT": clusterversion.V23_1Start, } func init() { @@ -163,6 +169,8 @@ func alterTableAddConstraintSupportedInCurrentClusterVersion( } case *tree.CheckConstraintTableDef: cmdKey = "ADD_CHECK" + case *tree.ForeignKeyConstraintTableDef: + cmdKey = "ADD_FOREIGN_KEY" } // Figure out command validation behavior: DEFAULT or SKIP if constraint.ValidationBehavior == tree.ValidationDefault { diff --git a/pkg/sql/schemachanger/scbuild/testdata/drop_table b/pkg/sql/schemachanger/scbuild/testdata/drop_table index 9fdbfc406b9c..8f2f39c57854 100644 --- a/pkg/sql/schemachanger/scbuild/testdata/drop_table +++ b/pkg/sql/schemachanger/scbuild/testdata/drop_table @@ -121,13 +121,13 @@ DROP TABLE defaultdb.shipments CASCADE; {comment: pkey is good, indexId: 1, tableId: 109} - [[IndexData:{DescID: 109, IndexID: 1}, ABSENT], PUBLIC] {indexId: 1, tableId: 109} -- [[ForeignKeyConstraint:{DescID: 109, ConstraintID: 2, ReferencedDescID: 104}, ABSENT], PUBLIC] +- [[ForeignKeyConstraint:{DescID: 109, IndexID: 0, ConstraintID: 2, ReferencedDescID: 104}, ABSENT], PUBLIC] {columnIds: [4], constraintId: 2, referencedColumnIds: [1], referencedTableId: 104, tableId: 109} - [[ConstraintWithoutIndexName:{DescID: 109, Name: fk_customers, ConstraintID: 2}, ABSENT], PUBLIC] {constraintId: 2, name: fk_customers, tableId: 109} - [[ConstraintComment:{DescID: 109, ConstraintID: 2, Comment: customer is important}, ABSENT], PUBLIC] {comment: customer is important, constraintId: 2, tableId: 109} -- [[ForeignKeyConstraint:{DescID: 109, ConstraintID: 3, ReferencedDescID: 105}, ABSENT], PUBLIC] +- [[ForeignKeyConstraint:{DescID: 109, IndexID: 0, ConstraintID: 3, ReferencedDescID: 105}, ABSENT], PUBLIC] {columnIds: [4], constraintId: 3, referencedColumnIds: [2], referencedTableId: 105, tableId: 109} - [[ConstraintWithoutIndexName:{DescID: 109, Name: fk_orders, ConstraintID: 3}, ABSENT], PUBLIC] {constraintId: 3, name: fk_orders, tableId: 109} diff --git a/pkg/sql/schemachanger/scbuild/testdata/unimplemented_alter_table b/pkg/sql/schemachanger/scbuild/testdata/unimplemented_alter_table index 9c0de7b4c51d..8d66b2c247cc 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 INT REFERENCES defaultdb.foo(i) ----- - unimplemented ALTER TABLE defaultdb.foo ADD COLUMN j SERIAL ---- @@ -92,10 +88,6 @@ unimplemented ALTER TABLE defaultdb.foo ADD UNIQUE(i); ---- -unimplemented -ALTER TABLE defaultdb.foo ADD FOREIGN KEY (i) REFERENCES defaultdb.foo(i); ----- - unimplemented ALTER TABLE defaultdb.foo ADD PRIMARY KEY (l); ---- diff --git a/pkg/sql/schemachanger/scplan/internal/rules/assertions_test.go b/pkg/sql/schemachanger/scplan/internal/rules/assertions_test.go index a45781026769..54ea5de42c6c 100644 --- a/pkg/sql/schemachanger/scplan/internal/rules/assertions_test.go +++ b/pkg/sql/schemachanger/scplan/internal/rules/assertions_test.go @@ -58,10 +58,15 @@ func nonNilElement(element scpb.Element) scpb.Element { // Assert that only simple dependents (non-descriptor, non-index, non-column) // and data elements have screl.ReferencedDescID attributes. +// One exception is foreign key constraint, which is not simple dependent nor data +// element but it has a screl.ReferencedDescID attribute. func checkSimpleDependentsReferenceDescID(e scpb.Element) error { if isSimpleDependent(e) || isData(e) { return nil } + if _, ok := e.(*scpb.ForeignKeyConstraint); ok { + return nil + } if _, err := screl.Schema.GetAttribute(screl.ReferencedDescID, e); err == nil { return errors.New("unexpected screl.ReferencedDescID attr") } diff --git a/pkg/sql/schemachanger/scplan/internal/rules/helpers.go b/pkg/sql/schemachanger/scplan/internal/rules/helpers.go index c865493927cc..82fa65e55bb4 100644 --- a/pkg/sql/schemachanger/scplan/internal/rules/helpers.go +++ b/pkg/sql/schemachanger/scplan/internal/rules/helpers.go @@ -374,8 +374,11 @@ func isIndexDependent(e scpb.Element) bool { // TODO (xiang): Expand this predicate to include other non-index-backed constraints // when we properly support adding/dropping them in the new schema changer. func isSupportedNonIndexBackedConstraint(e scpb.Element) bool { - _, ok := e.(*scpb.CheckConstraint) - return ok + switch e.(type) { + case *scpb.CheckConstraint, *scpb.ForeignKeyConstraint: + return true + } + return false } func isConstraint(e scpb.Element) bool { diff --git a/pkg/sql/schemachanger/scplan/internal/rules/op_drop.go b/pkg/sql/schemachanger/scplan/internal/rules/op_drop.go index 783bc4481815..c7c565b0db23 100644 --- a/pkg/sql/schemachanger/scplan/internal/rules/op_drop.go +++ b/pkg/sql/schemachanger/scplan/internal/rules/op_drop.go @@ -169,6 +169,7 @@ func init() { ), constraint.Type( (*scpb.CheckConstraint)(nil), + (*scpb.ForeignKeyConstraint)(nil), (*scpb.UniqueWithoutIndexConstraint)(nil), ), diff --git a/pkg/sql/schemachanger/scplan/internal/rules/testdata/deprules b/pkg/sql/schemachanger/scplan/internal/rules/testdata/deprules index fcfb53ad617d..6644c695a33d 100644 --- a/pkg/sql/schemachanger/scplan/internal/rules/testdata/deprules +++ b/pkg/sql/schemachanger/scplan/internal/rules/testdata/deprules @@ -317,6 +317,103 @@ deprules - $column-node[CurrentStatus] = WRITE_ONLY - joinTargetNode($expr, $expr-target, $expr-node) - joinTargetNode($column, $column-target, $column-node) +- name: 'ForeignKeyConstraint transitions to ABSENT uphold 2-version invariant: PUBLIC->VALIDATED' + from: prev-node + kind: PreviousTransactionPrecedence + to: next-node + query: + - $prev[Type] = '*scpb.ForeignKeyConstraint' + - $next[Type] = '*scpb.ForeignKeyConstraint' + - $prev[DescID] = $_ + - $prev[Self] = $next + - $prev-target[Self] = $next-target + - $prev-target[TargetStatus] = ABSENT + - $prev-node[CurrentStatus] = PUBLIC + - $next-node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped($prev) + - joinTargetNode($prev, $prev-target, $prev-node) + - joinTargetNode($next, $next-target, $next-node) +- name: 'ForeignKeyConstraint transitions to ABSENT uphold 2-version invariant: VALIDATED->ABSENT' + from: prev-node + kind: PreviousTransactionPrecedence + to: next-node + query: + - $prev[Type] = '*scpb.ForeignKeyConstraint' + - $next[Type] = '*scpb.ForeignKeyConstraint' + - $prev[DescID] = $_ + - $prev[Self] = $next + - $prev-target[Self] = $next-target + - $prev-target[TargetStatus] = ABSENT + - $prev-node[CurrentStatus] = VALIDATED + - $next-node[CurrentStatus] = ABSENT + - descriptorIsNotBeingDropped($prev) + - nodeNotExistsWithStatusIn_WRITE_ONLY($prev-target) + - joinTargetNode($prev, $prev-target, $prev-node) + - joinTargetNode($next, $next-target, $next-node) +- name: 'ForeignKeyConstraint transitions to ABSENT uphold 2-version invariant: WRITE_ONLY->VALIDATED' + from: prev-node + kind: PreviousTransactionPrecedence + to: next-node + query: + - $prev[Type] = '*scpb.ForeignKeyConstraint' + - $next[Type] = '*scpb.ForeignKeyConstraint' + - $prev[DescID] = $_ + - $prev[Self] = $next + - $prev-target[Self] = $next-target + - $prev-target[TargetStatus] = ABSENT + - $prev-node[CurrentStatus] = WRITE_ONLY + - $next-node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped($prev) + - joinTargetNode($prev, $prev-target, $prev-node) + - joinTargetNode($next, $next-target, $next-node) +- name: 'ForeignKeyConstraint transitions to PUBLIC uphold 2-version invariant: ABSENT->WRITE_ONLY' + from: prev-node + kind: PreviousTransactionPrecedence + to: next-node + query: + - $prev[Type] = '*scpb.ForeignKeyConstraint' + - $next[Type] = '*scpb.ForeignKeyConstraint' + - $prev[DescID] = $_ + - $prev[Self] = $next + - $prev-target[Self] = $next-target + - $prev-target[TargetStatus] = PUBLIC + - $prev-node[CurrentStatus] = ABSENT + - $next-node[CurrentStatus] = WRITE_ONLY + - descriptorIsNotBeingDropped($prev) + - joinTargetNode($prev, $prev-target, $prev-node) + - joinTargetNode($next, $next-target, $next-node) +- name: 'ForeignKeyConstraint transitions to PUBLIC uphold 2-version invariant: VALIDATED->PUBLIC' + from: prev-node + kind: PreviousTransactionPrecedence + to: next-node + query: + - $prev[Type] = '*scpb.ForeignKeyConstraint' + - $next[Type] = '*scpb.ForeignKeyConstraint' + - $prev[DescID] = $_ + - $prev[Self] = $next + - $prev-target[Self] = $next-target + - $prev-target[TargetStatus] = PUBLIC + - $prev-node[CurrentStatus] = VALIDATED + - $next-node[CurrentStatus] = PUBLIC + - descriptorIsNotBeingDropped($prev) + - joinTargetNode($prev, $prev-target, $prev-node) + - joinTargetNode($next, $next-target, $next-node) +- name: 'ForeignKeyConstraint transitions to PUBLIC uphold 2-version invariant: WRITE_ONLY->VALIDATED' + from: prev-node + kind: PreviousTransactionPrecedence + to: next-node + query: + - $prev[Type] = '*scpb.ForeignKeyConstraint' + - $next[Type] = '*scpb.ForeignKeyConstraint' + - $prev[DescID] = $_ + - $prev[Self] = $next + - $prev-target[Self] = $next-target + - $prev-target[TargetStatus] = PUBLIC + - $prev-node[CurrentStatus] = WRITE_ONLY + - $next-node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped($prev) + - joinTargetNode($prev, $prev-target, $prev-node) + - joinTargetNode($next, $next-target, $next-node) - name: 'PrimaryIndex transitions to ABSENT uphold 2-version invariant: BACKFILLED->DELETE_ONLY' from: prev-node kind: PreviousTransactionPrecedence @@ -1438,10 +1535,9 @@ deprules - $column[Type] = '*scpb.Column' - $dependent[Type] IN ['*scpb.ColumnName', '*scpb.ColumnType', '*scpb.ColumnDefaultExpression', '*scpb.ColumnOnUpdateExpression', '*scpb.SequenceOwner', '*scpb.ColumnComment', '*scpb.IndexColumn'] - joinOnColumnID($column, $dependent, $table-id, $col-id) - - $column-target[TargetStatus] = ABSENT + - toAbsent($column-target, $dependent-target) - $column-node[CurrentStatus] = WRITE_ONLY - - $dependent-target[TargetStatus] = TRANSIENT_ABSENT - - $dependent-node[CurrentStatus] = TRANSIENT_ABSENT + - $dependent-node[CurrentStatus] = ABSENT - joinTargetNode($column, $column-target, $column-node) - joinTargetNode($dependent, $dependent-target, $dependent-node) - name: column no longer public before dependents @@ -1452,9 +1548,9 @@ deprules - $column[Type] = '*scpb.Column' - $dependent[Type] IN ['*scpb.ColumnName', '*scpb.ColumnType', '*scpb.ColumnDefaultExpression', '*scpb.ColumnOnUpdateExpression', '*scpb.SequenceOwner', '*scpb.ColumnComment', '*scpb.IndexColumn'] - joinOnColumnID($column, $dependent, $table-id, $col-id) - - toAbsent($column-target, $dependent-target) - - $column-node[CurrentStatus] = WRITE_ONLY - - $dependent-node[CurrentStatus] = ABSENT + - transient($column-target, $dependent-target) + - $column-node[CurrentStatus] = TRANSIENT_WRITE_ONLY + - $dependent-node[CurrentStatus] = TRANSIENT_ABSENT - joinTargetNode($column, $column-target, $column-node) - joinTargetNode($dependent, $dependent-target, $dependent-node) - name: column no longer public before dependents @@ -1465,9 +1561,10 @@ deprules - $column[Type] = '*scpb.Column' - $dependent[Type] IN ['*scpb.ColumnName', '*scpb.ColumnType', '*scpb.ColumnDefaultExpression', '*scpb.ColumnOnUpdateExpression', '*scpb.SequenceOwner', '*scpb.ColumnComment', '*scpb.IndexColumn'] - joinOnColumnID($column, $dependent, $table-id, $col-id) - - transient($column-target, $dependent-target) + - $column-target[TargetStatus] = TRANSIENT_ABSENT - $column-node[CurrentStatus] = TRANSIENT_WRITE_ONLY - - $dependent-node[CurrentStatus] = TRANSIENT_ABSENT + - $dependent-target[TargetStatus] = ABSENT + - $dependent-node[CurrentStatus] = ABSENT - joinTargetNode($column, $column-target, $column-node) - joinTargetNode($dependent, $dependent-target, $dependent-node) - name: column no longer public before dependents @@ -1478,10 +1575,10 @@ deprules - $column[Type] = '*scpb.Column' - $dependent[Type] IN ['*scpb.ColumnName', '*scpb.ColumnType', '*scpb.ColumnDefaultExpression', '*scpb.ColumnOnUpdateExpression', '*scpb.SequenceOwner', '*scpb.ColumnComment', '*scpb.IndexColumn'] - joinOnColumnID($column, $dependent, $table-id, $col-id) - - $column-target[TargetStatus] = TRANSIENT_ABSENT - - $column-node[CurrentStatus] = TRANSIENT_WRITE_ONLY - - $dependent-target[TargetStatus] = ABSENT - - $dependent-node[CurrentStatus] = ABSENT + - $column-target[TargetStatus] = ABSENT + - $column-node[CurrentStatus] = WRITE_ONLY + - $dependent-target[TargetStatus] = TRANSIENT_ABSENT + - $dependent-node[CurrentStatus] = TRANSIENT_ABSENT - joinTargetNode($column, $column-target, $column-node) - joinTargetNode($dependent, $dependent-target, $dependent-node) - name: column type dependents removed right before column type @@ -1529,12 +1626,11 @@ deprules kind: Precedence to: dependent-node query: - - $constraint[Type] = '*scpb.CheckConstraint' + - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.ForeignKeyConstraint'] - $dependent[Type] IN ['*scpb.ConstraintWithoutIndexName', '*scpb.ConstraintComment'] - joinOnConstraintID($constraint, $dependent, $table-id, $constraint-id) - - $constraint-target[TargetStatus] = ABSENT - - $constraint-node[CurrentStatus] = VALIDATED - - $dependent-target[TargetStatus] = TRANSIENT_ABSENT + - transient($constraint-target, $dependent-target) + - $constraint-node[CurrentStatus] = TRANSIENT_VALIDATED - $dependent-node[CurrentStatus] = TRANSIENT_ABSENT - joinTargetNode($constraint, $constraint-target, $constraint-node) - joinTargetNode($dependent, $dependent-target, $dependent-node) @@ -1543,11 +1639,12 @@ deprules kind: Precedence to: dependent-node query: - - $constraint[Type] = '*scpb.CheckConstraint' + - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.ForeignKeyConstraint'] - $dependent[Type] IN ['*scpb.ConstraintWithoutIndexName', '*scpb.ConstraintComment'] - joinOnConstraintID($constraint, $dependent, $table-id, $constraint-id) - - toAbsent($constraint-target, $dependent-target) - - $constraint-node[CurrentStatus] = VALIDATED + - $constraint-target[TargetStatus] = TRANSIENT_ABSENT + - $constraint-node[CurrentStatus] = TRANSIENT_VALIDATED + - $dependent-target[TargetStatus] = ABSENT - $dependent-node[CurrentStatus] = ABSENT - joinTargetNode($constraint, $constraint-target, $constraint-node) - joinTargetNode($dependent, $dependent-target, $dependent-node) @@ -1556,12 +1653,11 @@ deprules kind: Precedence to: dependent-node query: - - $constraint[Type] = '*scpb.CheckConstraint' + - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.ForeignKeyConstraint'] - $dependent[Type] IN ['*scpb.ConstraintWithoutIndexName', '*scpb.ConstraintComment'] - joinOnConstraintID($constraint, $dependent, $table-id, $constraint-id) - - $constraint-target[TargetStatus] = TRANSIENT_ABSENT - - $constraint-node[CurrentStatus] = TRANSIENT_VALIDATED - - $dependent-target[TargetStatus] = ABSENT + - toAbsent($constraint-target, $dependent-target) + - $constraint-node[CurrentStatus] = VALIDATED - $dependent-node[CurrentStatus] = ABSENT - joinTargetNode($constraint, $constraint-target, $constraint-node) - joinTargetNode($dependent, $dependent-target, $dependent-node) @@ -1570,11 +1666,12 @@ deprules kind: Precedence to: dependent-node query: - - $constraint[Type] = '*scpb.CheckConstraint' + - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.ForeignKeyConstraint'] - $dependent[Type] IN ['*scpb.ConstraintWithoutIndexName', '*scpb.ConstraintComment'] - joinOnConstraintID($constraint, $dependent, $table-id, $constraint-id) - - transient($constraint-target, $dependent-target) - - $constraint-node[CurrentStatus] = TRANSIENT_VALIDATED + - $constraint-target[TargetStatus] = ABSENT + - $constraint-node[CurrentStatus] = VALIDATED + - $dependent-target[TargetStatus] = TRANSIENT_ABSENT - $dependent-node[CurrentStatus] = TRANSIENT_ABSENT - joinTargetNode($constraint, $constraint-target, $constraint-node) - joinTargetNode($dependent, $dependent-target, $dependent-node) @@ -1586,8 +1683,9 @@ deprules - $view[Type] = '*scpb.View' - $index[Type] = '*scpb.SecondaryIndex' - viewReferencesIndex(*scpb.View, *scpb.SecondaryIndex)($view, $index) - - transient($view-target, $index-target) - - $view-node[CurrentStatus] = TRANSIENT_ABSENT + - $view-target[TargetStatus] = ABSENT + - $view-node[CurrentStatus] = ABSENT + - $index-target[TargetStatus] = TRANSIENT_ABSENT - $index-node[CurrentStatus] = TRANSIENT_ABSENT - joinTargetNode($view, $view-target, $view-node) - joinTargetNode($index, $index-target, $index-node) @@ -1599,8 +1697,9 @@ deprules - $view[Type] = '*scpb.View' - $index[Type] = '*scpb.SecondaryIndex' - viewReferencesIndex(*scpb.View, *scpb.SecondaryIndex)($view, $index) - - toAbsent($view-target, $index-target) - - $view-node[CurrentStatus] = ABSENT + - $view-target[TargetStatus] = TRANSIENT_ABSENT + - $view-node[CurrentStatus] = TRANSIENT_ABSENT + - $index-target[TargetStatus] = ABSENT - $index-node[CurrentStatus] = ABSENT - joinTargetNode($view, $view-target, $view-node) - joinTargetNode($index, $index-target, $index-node) @@ -1612,10 +1711,9 @@ deprules - $view[Type] = '*scpb.View' - $index[Type] = '*scpb.SecondaryIndex' - viewReferencesIndex(*scpb.View, *scpb.SecondaryIndex)($view, $index) - - $view-target[TargetStatus] = ABSENT + - toAbsent($view-target, $index-target) - $view-node[CurrentStatus] = ABSENT - - $index-target[TargetStatus] = TRANSIENT_ABSENT - - $index-node[CurrentStatus] = TRANSIENT_ABSENT + - $index-node[CurrentStatus] = ABSENT - joinTargetNode($view, $view-target, $view-node) - joinTargetNode($index, $index-target, $index-node) - name: dependent view absent before secondary index @@ -1626,10 +1724,9 @@ deprules - $view[Type] = '*scpb.View' - $index[Type] = '*scpb.SecondaryIndex' - viewReferencesIndex(*scpb.View, *scpb.SecondaryIndex)($view, $index) - - $view-target[TargetStatus] = TRANSIENT_ABSENT + - transient($view-target, $index-target) - $view-node[CurrentStatus] = TRANSIENT_ABSENT - - $index-target[TargetStatus] = ABSENT - - $index-node[CurrentStatus] = ABSENT + - $index-node[CurrentStatus] = TRANSIENT_ABSENT - joinTargetNode($view, $view-target, $view-node) - joinTargetNode($index, $index-target, $index-node) - name: dependent view no longer public before secondary index @@ -1667,10 +1764,9 @@ deprules - $view[Type] = '*scpb.View' - $index[Type] = '*scpb.SecondaryIndex' - viewReferencesIndex(*scpb.View, *scpb.SecondaryIndex)($view, $index) - - $view-target[TargetStatus] = TRANSIENT_ABSENT + - transient($view-target, $index-target) - $view-node[CurrentStatus] = TRANSIENT_DROPPED - - $index-target[TargetStatus] = ABSENT - - $index-node[CurrentStatus] = VALIDATED + - $index-node[CurrentStatus] = TRANSIENT_VALIDATED - joinTargetNode($view, $view-target, $view-node) - joinTargetNode($index, $index-target, $index-node) - name: dependent view no longer public before secondary index @@ -1681,9 +1777,10 @@ deprules - $view[Type] = '*scpb.View' - $index[Type] = '*scpb.SecondaryIndex' - viewReferencesIndex(*scpb.View, *scpb.SecondaryIndex)($view, $index) - - transient($view-target, $index-target) + - $view-target[TargetStatus] = TRANSIENT_ABSENT - $view-node[CurrentStatus] = TRANSIENT_DROPPED - - $index-node[CurrentStatus] = TRANSIENT_VALIDATED + - $index-target[TargetStatus] = ABSENT + - $index-node[CurrentStatus] = VALIDATED - joinTargetNode($view, $view-target, $view-node) - joinTargetNode($index, $index-target, $index-node) - name: dependents removed before column @@ -1694,9 +1791,9 @@ deprules - $dependent[Type] IN ['*scpb.ColumnName', '*scpb.ColumnType', '*scpb.ColumnDefaultExpression', '*scpb.ColumnOnUpdateExpression', '*scpb.SequenceOwner', '*scpb.ColumnComment', '*scpb.IndexColumn'] - $column[Type] = '*scpb.Column' - joinOnColumnID($dependent, $column, $table-id, $col-id) - - toAbsent($dependent-target, $column-target) - - $dependent-node[CurrentStatus] = ABSENT - - $column-node[CurrentStatus] = ABSENT + - transient($dependent-target, $column-target) + - $dependent-node[CurrentStatus] = TRANSIENT_ABSENT + - $column-node[CurrentStatus] = TRANSIENT_ABSENT - joinTargetNode($dependent, $dependent-target, $dependent-node) - joinTargetNode($column, $column-target, $column-node) - name: dependents removed before column @@ -1707,9 +1804,9 @@ deprules - $dependent[Type] IN ['*scpb.ColumnName', '*scpb.ColumnType', '*scpb.ColumnDefaultExpression', '*scpb.ColumnOnUpdateExpression', '*scpb.SequenceOwner', '*scpb.ColumnComment', '*scpb.IndexColumn'] - $column[Type] = '*scpb.Column' - joinOnColumnID($dependent, $column, $table-id, $col-id) - - transient($dependent-target, $column-target) - - $dependent-node[CurrentStatus] = TRANSIENT_ABSENT - - $column-node[CurrentStatus] = TRANSIENT_ABSENT + - toAbsent($dependent-target, $column-target) + - $dependent-node[CurrentStatus] = ABSENT + - $column-node[CurrentStatus] = ABSENT - joinTargetNode($dependent, $dependent-target, $dependent-node) - joinTargetNode($column, $column-target, $column-node) - name: dependents removed before column @@ -1720,10 +1817,10 @@ deprules - $dependent[Type] IN ['*scpb.ColumnName', '*scpb.ColumnType', '*scpb.ColumnDefaultExpression', '*scpb.ColumnOnUpdateExpression', '*scpb.SequenceOwner', '*scpb.ColumnComment', '*scpb.IndexColumn'] - $column[Type] = '*scpb.Column' - joinOnColumnID($dependent, $column, $table-id, $col-id) - - $dependent-target[TargetStatus] = ABSENT - - $dependent-node[CurrentStatus] = ABSENT - - $column-target[TargetStatus] = TRANSIENT_ABSENT - - $column-node[CurrentStatus] = TRANSIENT_ABSENT + - $dependent-target[TargetStatus] = TRANSIENT_ABSENT + - $dependent-node[CurrentStatus] = TRANSIENT_ABSENT + - $column-target[TargetStatus] = ABSENT + - $column-node[CurrentStatus] = ABSENT - joinTargetNode($dependent, $dependent-target, $dependent-node) - joinTargetNode($column, $column-target, $column-node) - name: dependents removed before column @@ -1734,10 +1831,10 @@ deprules - $dependent[Type] IN ['*scpb.ColumnName', '*scpb.ColumnType', '*scpb.ColumnDefaultExpression', '*scpb.ColumnOnUpdateExpression', '*scpb.SequenceOwner', '*scpb.ColumnComment', '*scpb.IndexColumn'] - $column[Type] = '*scpb.Column' - joinOnColumnID($dependent, $column, $table-id, $col-id) - - $dependent-target[TargetStatus] = TRANSIENT_ABSENT - - $dependent-node[CurrentStatus] = TRANSIENT_ABSENT - - $column-target[TargetStatus] = ABSENT - - $column-node[CurrentStatus] = ABSENT + - $dependent-target[TargetStatus] = ABSENT + - $dependent-node[CurrentStatus] = ABSENT + - $column-target[TargetStatus] = TRANSIENT_ABSENT + - $column-node[CurrentStatus] = TRANSIENT_ABSENT - joinTargetNode($dependent, $dependent-target, $dependent-node) - joinTargetNode($column, $column-target, $column-node) - name: dependents removed before constraint @@ -1746,11 +1843,10 @@ deprules to: constraint-node query: - $dependents[Type] IN ['*scpb.ConstraintWithoutIndexName', '*scpb.ConstraintComment'] - - $constraint[Type] = '*scpb.CheckConstraint' + - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.ForeignKeyConstraint'] - joinOnConstraintID($dependents, $constraint, $table-id, $constraint-id) - - $dependents-target[TargetStatus] = TRANSIENT_ABSENT - - $dependents-node[CurrentStatus] = TRANSIENT_ABSENT - - $constraint-target[TargetStatus] = ABSENT + - toAbsent($dependents-target, $constraint-target) + - $dependents-node[CurrentStatus] = ABSENT - $constraint-node[CurrentStatus] = ABSENT - joinTargetNode($dependents, $dependents-target, $dependents-node) - joinTargetNode($constraint, $constraint-target, $constraint-node) @@ -1760,7 +1856,7 @@ deprules to: constraint-node query: - $dependents[Type] IN ['*scpb.ConstraintWithoutIndexName', '*scpb.ConstraintComment'] - - $constraint[Type] = '*scpb.CheckConstraint' + - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.ForeignKeyConstraint'] - joinOnConstraintID($dependents, $constraint, $table-id, $constraint-id) - transient($dependents-target, $constraint-target) - $dependents-node[CurrentStatus] = TRANSIENT_ABSENT @@ -1773,10 +1869,11 @@ deprules to: constraint-node query: - $dependents[Type] IN ['*scpb.ConstraintWithoutIndexName', '*scpb.ConstraintComment'] - - $constraint[Type] = '*scpb.CheckConstraint' + - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.ForeignKeyConstraint'] - joinOnConstraintID($dependents, $constraint, $table-id, $constraint-id) - - toAbsent($dependents-target, $constraint-target) - - $dependents-node[CurrentStatus] = ABSENT + - $dependents-target[TargetStatus] = TRANSIENT_ABSENT + - $dependents-node[CurrentStatus] = TRANSIENT_ABSENT + - $constraint-target[TargetStatus] = ABSENT - $constraint-node[CurrentStatus] = ABSENT - joinTargetNode($dependents, $dependents-target, $dependents-node) - joinTargetNode($constraint, $constraint-target, $constraint-node) @@ -1786,7 +1883,7 @@ deprules to: constraint-node query: - $dependents[Type] IN ['*scpb.ConstraintWithoutIndexName', '*scpb.ConstraintComment'] - - $constraint[Type] = '*scpb.CheckConstraint' + - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.ForeignKeyConstraint'] - joinOnConstraintID($dependents, $constraint, $table-id, $constraint-id) - $dependents-target[TargetStatus] = ABSENT - $dependents-node[CurrentStatus] = ABSENT @@ -1802,9 +1899,10 @@ deprules - $dependent[Type] IN ['*scpb.IndexName', '*scpb.IndexPartitioning', '*scpb.SecondaryIndexPartial', '*scpb.IndexComment', '*scpb.IndexColumn'] - $index[Type] IN ['*scpb.PrimaryIndex', '*scpb.SecondaryIndex', '*scpb.TemporaryIndex'] - joinOnIndexID($dependent, $index, $table-id, $index-id) - - transient($dependent-target, $index-target) + - $dependent-target[TargetStatus] = TRANSIENT_ABSENT - $dependent-node[CurrentStatus] = TRANSIENT_ABSENT - - $index-node[CurrentStatus] = TRANSIENT_ABSENT + - $index-target[TargetStatus] = ABSENT + - $index-node[CurrentStatus] = ABSENT - joinTargetNode($dependent, $dependent-target, $dependent-node) - joinTargetNode($index, $index-target, $index-node) - name: dependents removed before index @@ -1828,10 +1926,9 @@ deprules - $dependent[Type] IN ['*scpb.IndexName', '*scpb.IndexPartitioning', '*scpb.SecondaryIndexPartial', '*scpb.IndexComment', '*scpb.IndexColumn'] - $index[Type] IN ['*scpb.PrimaryIndex', '*scpb.SecondaryIndex', '*scpb.TemporaryIndex'] - joinOnIndexID($dependent, $index, $table-id, $index-id) - - $dependent-target[TargetStatus] = TRANSIENT_ABSENT + - transient($dependent-target, $index-target) - $dependent-node[CurrentStatus] = TRANSIENT_ABSENT - - $index-target[TargetStatus] = ABSENT - - $index-node[CurrentStatus] = ABSENT + - $index-node[CurrentStatus] = TRANSIENT_ABSENT - joinTargetNode($dependent, $dependent-target, $dependent-node) - joinTargetNode($index, $index-target, $index-node) - name: dependents removed before index @@ -1880,7 +1977,7 @@ deprules to: dependent-node query: - $descriptor[Type] IN ['*scpb.Database', '*scpb.Schema', '*scpb.View', '*scpb.Sequence', '*scpb.Table', '*scpb.EnumType', '*scpb.AliasType', '*scpb.CompositeType'] - - $dependent[Type] IN ['*scpb.ColumnFamily', '*scpb.UniqueWithoutIndexConstraint', '*scpb.ForeignKeyConstraint', '*scpb.TableComment', '*scpb.RowLevelTTL', '*scpb.TableZoneConfig', '*scpb.TablePartitioning', '*scpb.TableLocalityGlobal', '*scpb.TableLocalityPrimaryRegion', '*scpb.TableLocalitySecondaryRegion', '*scpb.TableLocalityRegionalByRow', '*scpb.ColumnName', '*scpb.ColumnType', '*scpb.ColumnDefaultExpression', '*scpb.ColumnOnUpdateExpression', '*scpb.SequenceOwner', '*scpb.ColumnComment', '*scpb.IndexName', '*scpb.IndexPartitioning', '*scpb.SecondaryIndexPartial', '*scpb.IndexComment', '*scpb.IndexColumn', '*scpb.ConstraintWithoutIndexName', '*scpb.ConstraintComment', '*scpb.Namespace', '*scpb.Owner', '*scpb.UserPrivileges', '*scpb.DatabaseRegionConfig', '*scpb.DatabaseRoleSetting', '*scpb.DatabaseComment', '*scpb.SchemaParent', '*scpb.SchemaComment', '*scpb.ObjectParent', '*scpb.EnumTypeValue', '*scpb.CompositeTypeAttrType', '*scpb.CompositeTypeAttrName'] + - $dependent[Type] IN ['*scpb.ColumnFamily', '*scpb.UniqueWithoutIndexConstraint', '*scpb.TableComment', '*scpb.RowLevelTTL', '*scpb.TableZoneConfig', '*scpb.TablePartitioning', '*scpb.TableLocalityGlobal', '*scpb.TableLocalityPrimaryRegion', '*scpb.TableLocalitySecondaryRegion', '*scpb.TableLocalityRegionalByRow', '*scpb.ColumnName', '*scpb.ColumnType', '*scpb.ColumnDefaultExpression', '*scpb.ColumnOnUpdateExpression', '*scpb.SequenceOwner', '*scpb.ColumnComment', '*scpb.IndexName', '*scpb.IndexPartitioning', '*scpb.SecondaryIndexPartial', '*scpb.IndexComment', '*scpb.IndexColumn', '*scpb.ConstraintWithoutIndexName', '*scpb.ConstraintComment', '*scpb.Namespace', '*scpb.Owner', '*scpb.UserPrivileges', '*scpb.DatabaseRegionConfig', '*scpb.DatabaseRoleSetting', '*scpb.DatabaseComment', '*scpb.SchemaParent', '*scpb.SchemaComment', '*scpb.ObjectParent', '*scpb.EnumTypeValue', '*scpb.CompositeTypeAttrType', '*scpb.CompositeTypeAttrName'] - joinOnDescID($descriptor, $dependent, $desc-id) - toAbsent($descriptor-target, $dependent-target) - $descriptor-node[CurrentStatus] = DROPPED @@ -1894,7 +1991,7 @@ deprules to: referencing-via-attr-node query: - $referenced-descriptor[Type] IN ['*scpb.Database', '*scpb.Schema', '*scpb.View', '*scpb.Sequence', '*scpb.Table', '*scpb.EnumType', '*scpb.AliasType', '*scpb.CompositeType'] - - $referencing-via-attr[Type] IN ['*scpb.ColumnFamily', '*scpb.UniqueWithoutIndexConstraint', '*scpb.ForeignKeyConstraint', '*scpb.TableComment', '*scpb.RowLevelTTL', '*scpb.TableZoneConfig', '*scpb.TablePartitioning', '*scpb.TableLocalityGlobal', '*scpb.TableLocalityPrimaryRegion', '*scpb.TableLocalitySecondaryRegion', '*scpb.TableLocalityRegionalByRow', '*scpb.ColumnName', '*scpb.ColumnType', '*scpb.ColumnDefaultExpression', '*scpb.ColumnOnUpdateExpression', '*scpb.SequenceOwner', '*scpb.ColumnComment', '*scpb.IndexName', '*scpb.IndexPartitioning', '*scpb.SecondaryIndexPartial', '*scpb.IndexComment', '*scpb.IndexColumn', '*scpb.ConstraintWithoutIndexName', '*scpb.ConstraintComment', '*scpb.Namespace', '*scpb.Owner', '*scpb.UserPrivileges', '*scpb.DatabaseRegionConfig', '*scpb.DatabaseRoleSetting', '*scpb.DatabaseComment', '*scpb.SchemaParent', '*scpb.SchemaComment', '*scpb.ObjectParent', '*scpb.EnumTypeValue', '*scpb.CompositeTypeAttrType', '*scpb.CompositeTypeAttrName'] + - $referencing-via-attr[Type] IN ['*scpb.ColumnFamily', '*scpb.UniqueWithoutIndexConstraint', '*scpb.TableComment', '*scpb.RowLevelTTL', '*scpb.TableZoneConfig', '*scpb.TablePartitioning', '*scpb.TableLocalityGlobal', '*scpb.TableLocalityPrimaryRegion', '*scpb.TableLocalitySecondaryRegion', '*scpb.TableLocalityRegionalByRow', '*scpb.ColumnName', '*scpb.ColumnType', '*scpb.ColumnDefaultExpression', '*scpb.ColumnOnUpdateExpression', '*scpb.SequenceOwner', '*scpb.ColumnComment', '*scpb.IndexName', '*scpb.IndexPartitioning', '*scpb.SecondaryIndexPartial', '*scpb.IndexComment', '*scpb.IndexColumn', '*scpb.ConstraintWithoutIndexName', '*scpb.ConstraintComment', '*scpb.Namespace', '*scpb.Owner', '*scpb.UserPrivileges', '*scpb.DatabaseRegionConfig', '*scpb.DatabaseRoleSetting', '*scpb.DatabaseComment', '*scpb.SchemaParent', '*scpb.SchemaComment', '*scpb.ObjectParent', '*scpb.EnumTypeValue', '*scpb.CompositeTypeAttrType', '*scpb.CompositeTypeAttrName'] - joinReferencedDescID($referencing-via-attr, $referenced-descriptor, $desc-id) - toAbsent($referenced-descriptor-target, $referencing-via-attr-target) - $referenced-descriptor-node[CurrentStatus] = DROPPED @@ -2002,7 +2099,7 @@ deprules to: constraint-node query: - $index[Type] = '*scpb.PrimaryIndex' - - $constraint[Type] = '*scpb.CheckConstraint' + - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.ForeignKeyConstraint'] - joinOnDescID($index, $constraint, $table-id) - $index[IndexID] = $index-id-for-validation - $constraint[IndexID] = $index-id-for-validation diff --git a/pkg/sql/schemachanger/scplan/internal/rules/testdata/oprules b/pkg/sql/schemachanger/scplan/internal/rules/testdata/oprules index cc1257990463..cdccc24693da 100644 --- a/pkg/sql/schemachanger/scplan/internal/rules/testdata/oprules +++ b/pkg/sql/schemachanger/scplan/internal/rules/testdata/oprules @@ -154,7 +154,7 @@ oprules from: constraint-node query: - $relation[Type] IN ['*scpb.Table', '*scpb.View'] - - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.UniqueWithoutIndexConstraint'] + - $constraint[Type] IN ['*scpb.CheckConstraint', '*scpb.ForeignKeyConstraint', '*scpb.UniqueWithoutIndexConstraint'] - joinOnDescID($relation, $constraint, $relation-id) - joinTarget($relation, $relation-target) - $relation-target[TargetStatus] = ABSENT diff --git a/pkg/sql/schemachanger/scplan/testdata/drop_table b/pkg/sql/schemachanger/scplan/testdata/drop_table index b49356631f92..fb51ce462576 100644 --- a/pkg/sql/schemachanger/scplan/testdata/drop_table +++ b/pkg/sql/schemachanger/scplan/testdata/drop_table @@ -41,6 +41,8 @@ StatementPhase stage 1 of 1 with 3 MutationType ops [[Column:{DescID: 109, ColumnID: 4294967294}, ABSENT], PUBLIC] -> WRITE_ONLY [[PrimaryIndex:{DescID: 109, IndexID: 1, ConstraintID: 1}, ABSENT], PUBLIC] -> VALIDATED [[SecondaryIndex:{DescID: 109, IndexID: 2, ConstraintID: 0}, ABSENT], PUBLIC] -> VALIDATED + [[ForeignKeyConstraint:{DescID: 109, IndexID: 0, ConstraintID: 2, ReferencedDescID: 104}, ABSENT], PUBLIC] -> VALIDATED + [[ForeignKeyConstraint:{DescID: 109, IndexID: 0, ConstraintID: 3, ReferencedDescID: 105}, ABSENT], PUBLIC] -> VALIDATED [[Sequence:{DescID: 110}, ABSENT], PUBLIC] -> TXN_DROPPED [[View:{DescID: 111}, ABSENT], PUBLIC] -> TXN_DROPPED [[Column:{DescID: 111, ColumnID: 1}, ABSENT], PUBLIC] -> WRITE_ONLY @@ -103,10 +105,10 @@ PreCommitPhase stage 1 of 1 with 42 MutationType ops [[SecondaryIndexPartial:{DescID: 109, IndexID: 2}, ABSENT], PUBLIC] -> ABSENT [[SecondaryIndex:{DescID: 109, IndexID: 2, ConstraintID: 0}, ABSENT], VALIDATED] -> ABSENT [[IndexName:{DescID: 109, Name: partialidx, IndexID: 2}, ABSENT], PUBLIC] -> ABSENT - [[ForeignKeyConstraint:{DescID: 109, ConstraintID: 2, ReferencedDescID: 104}, ABSENT], PUBLIC] -> ABSENT + [[ForeignKeyConstraint:{DescID: 109, IndexID: 0, ConstraintID: 2, ReferencedDescID: 104}, ABSENT], VALIDATED] -> ABSENT [[ConstraintWithoutIndexName:{DescID: 109, Name: fk_customers, ConstraintID: 2}, ABSENT], PUBLIC] -> ABSENT [[ConstraintComment:{DescID: 109, ConstraintID: 2, Comment: customer is not god}, ABSENT], PUBLIC] -> ABSENT - [[ForeignKeyConstraint:{DescID: 109, ConstraintID: 3, ReferencedDescID: 105}, ABSENT], PUBLIC] -> ABSENT + [[ForeignKeyConstraint:{DescID: 109, IndexID: 0, ConstraintID: 3, ReferencedDescID: 105}, ABSENT], VALIDATED] -> ABSENT [[ConstraintWithoutIndexName:{DescID: 109, Name: fk_orders, ConstraintID: 3}, ABSENT], PUBLIC] -> ABSENT [[Namespace:{DescID: 110, Name: sq1, ReferencedDescID: 100}, ABSENT], PUBLIC] -> ABSENT [[Owner:{DescID: 110}, ABSENT], PUBLIC] -> ABSENT @@ -159,20 +161,6 @@ PreCommitPhase stage 1 of 1 with 42 MutationType ops *scop.RemoveDroppedIndexPartialPredicate IndexID: 2 TableID: 109 - *scop.RemoveForeignKeyBackReference - OriginConstraintID: 2 - OriginTableID: 109 - ReferencedTableID: 104 - *scop.RemoveForeignKeyConstraint - ConstraintID: 2 - TableID: 109 - *scop.RemoveForeignKeyBackReference - OriginConstraintID: 3 - OriginTableID: 109 - ReferencedTableID: 105 - *scop.RemoveForeignKeyConstraint - ConstraintID: 3 - TableID: 109 *scop.MarkDescriptorAsDropped DescriptorID: 110 *scop.RemoveAllTableComments @@ -241,6 +229,20 @@ PreCommitPhase stage 1 of 1 with 42 MutationType ops SourceElementID: 1 SubWorkID: 1 TableID: 109 + *scop.RemoveForeignKeyBackReference + OriginConstraintID: 2 + OriginTableID: 109 + ReferencedTableID: 104 + *scop.RemoveForeignKeyConstraint + ConstraintID: 2 + TableID: 109 + *scop.RemoveForeignKeyBackReference + OriginConstraintID: 3 + OriginTableID: 109 + ReferencedTableID: 105 + *scop.RemoveForeignKeyConstraint + ConstraintID: 3 + TableID: 109 *scop.DrainDescriptorName Namespace: DatabaseID: 100 @@ -735,6 +737,30 @@ DROP TABLE defaultdb.shipments CASCADE; to: [Column:{DescID: 111, ColumnID: 4294967295}, ABSENT] kind: Precedence rule: dependents removed before column +- from: [ConstraintComment:{DescID: 109, ConstraintID: 2, Comment: customer is not god}, ABSENT] + to: [ForeignKeyConstraint:{DescID: 109, IndexID: 0, ConstraintID: 2, ReferencedDescID: 104}, ABSENT] + kind: Precedence + rule: dependents removed before constraint +- from: [ConstraintWithoutIndexName:{DescID: 109, Name: fk_customers, ConstraintID: 2}, ABSENT] + to: [ForeignKeyConstraint:{DescID: 109, IndexID: 0, ConstraintID: 2, ReferencedDescID: 104}, ABSENT] + kind: Precedence + rule: dependents removed before constraint +- from: [ConstraintWithoutIndexName:{DescID: 109, Name: fk_orders, ConstraintID: 3}, ABSENT] + to: [ForeignKeyConstraint:{DescID: 109, IndexID: 0, ConstraintID: 3, ReferencedDescID: 105}, ABSENT] + kind: Precedence + rule: dependents removed before constraint +- from: [ForeignKeyConstraint:{DescID: 109, IndexID: 0, ConstraintID: 2, ReferencedDescID: 104}, VALIDATED] + to: [ConstraintComment:{DescID: 109, ConstraintID: 2, Comment: customer is not god}, ABSENT] + kind: Precedence + rule: constraint no longer public before dependents +- from: [ForeignKeyConstraint:{DescID: 109, IndexID: 0, ConstraintID: 2, ReferencedDescID: 104}, VALIDATED] + to: [ConstraintWithoutIndexName:{DescID: 109, Name: fk_customers, ConstraintID: 2}, ABSENT] + kind: Precedence + rule: constraint no longer public before dependents +- from: [ForeignKeyConstraint:{DescID: 109, IndexID: 0, ConstraintID: 3, ReferencedDescID: 105}, VALIDATED] + to: [ConstraintWithoutIndexName:{DescID: 109, Name: fk_orders, ConstraintID: 3}, ABSENT] + kind: Precedence + rule: constraint no longer public before dependents - from: [IndexColumn:{DescID: 109, ColumnID: 1, IndexID: 1}, ABSENT] to: [Column:{DescID: 109, ColumnID: 1}, ABSENT] kind: Precedence @@ -1011,14 +1037,6 @@ DROP TABLE defaultdb.shipments CASCADE; to: [ConstraintWithoutIndexName:{DescID: 109, Name: fk_orders, ConstraintID: 3}, ABSENT] kind: Precedence rule: descriptor drop right before dependent element removal -- from: [Table:{DescID: 109}, DROPPED] - to: [ForeignKeyConstraint:{DescID: 109, ConstraintID: 2, ReferencedDescID: 104}, ABSENT] - kind: Precedence - rule: descriptor drop right before dependent element removal -- from: [Table:{DescID: 109}, DROPPED] - to: [ForeignKeyConstraint:{DescID: 109, ConstraintID: 3, ReferencedDescID: 105}, ABSENT] - kind: Precedence - rule: descriptor drop right before dependent element removal - from: [Table:{DescID: 109}, DROPPED] to: [IndexColumn:{DescID: 109, ColumnID: 1, IndexID: 1}, ABSENT] kind: Precedence diff --git a/pkg/sql/schemachanger/screl/attr.go b/pkg/sql/schemachanger/screl/attr.go index d7afad361c0b..68a50141b17e 100644 --- a/pkg/sql/schemachanger/screl/attr.go +++ b/pkg/sql/schemachanger/screl/attr.go @@ -189,6 +189,7 @@ var elementSchemaOptions = []rel.SchemaOption{ rel.EntityAttr(DescID, "TableID"), rel.EntityAttr(ReferencedDescID, "ReferencedTableID"), rel.EntityAttr(ConstraintID, "ConstraintID"), + rel.EntityAttr(IndexID, "IndexIDForValidation"), ), rel.EntityMapping(t((*scpb.RowLevelTTL)(nil)), rel.EntityAttr(DescID, "TableID"), diff --git a/pkg/sql/schemachanger/screl/query_test.go b/pkg/sql/schemachanger/screl/query_test.go index 212f2c7a1b17..fea2133c30fe 100644 --- a/pkg/sql/schemachanger/screl/query_test.go +++ b/pkg/sql/schemachanger/screl/query_test.go @@ -131,13 +131,13 @@ func TestQueryBasic(t *testing.T) { exp: []string{` [[Table:{DescID: 2}, PUBLIC], ABSENT] [[Sequence:{DescID: 1}, PUBLIC], ABSENT] -[[ForeignKeyConstraint:{DescID: 2, ConstraintID: 0, ReferencedDescID: 1}, PUBLIC], ABSENT]`, ` +[[ForeignKeyConstraint:{DescID: 2, IndexID: 0, ConstraintID: 0, ReferencedDescID: 1}, PUBLIC], ABSENT]`, ` [[Table:{DescID: 2}, PUBLIC], PUBLIC] [[Sequence:{DescID: 1}, PUBLIC], PUBLIC] -[[ForeignKeyConstraint:{DescID: 2, ConstraintID: 0, ReferencedDescID: 1}, PUBLIC], PUBLIC]`, ` +[[ForeignKeyConstraint:{DescID: 2, IndexID: 0, ConstraintID: 0, ReferencedDescID: 1}, PUBLIC], PUBLIC]`, ` [[Table:{DescID: 4}, PUBLIC], ABSENT] [[Sequence:{DescID: 3}, PUBLIC], ABSENT] -[[ForeignKeyConstraint:{DescID: 4, ConstraintID: 0, ReferencedDescID: 3}, PUBLIC], ABSENT]`, +[[ForeignKeyConstraint:{DescID: 4, IndexID: 0, ConstraintID: 0, ReferencedDescID: 3}, PUBLIC], ABSENT]`, }, }, }, diff --git a/pkg/sql/schemachanger/sctest_generated_test.go b/pkg/sql/schemachanger/sctest_generated_test.go index f096688e360e..236392efb499 100644 --- a/pkg/sql/schemachanger/sctest_generated_test.go +++ b/pkg/sql/schemachanger/sctest_generated_test.go @@ -170,6 +170,31 @@ func TestRollback_alter_table_add_check_with_seq_and_udt(t *testing.T) { defer log.Scope(t).Close(t) sctest.Rollback(t, "pkg/sql/schemachanger/testdata/end_to_end/alter_table_add_check_with_seq_and_udt", sctest.SingleNodeCluster) } +func TestEndToEndSideEffects_alter_table_add_foreign_key(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + sctest.EndToEndSideEffects(t, "pkg/sql/schemachanger/testdata/end_to_end/alter_table_add_foreign_key", sctest.SingleNodeCluster) +} +func TestExecuteWithDMLInjection_alter_table_add_foreign_key(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + sctest.ExecuteWithDMLInjection(t, "pkg/sql/schemachanger/testdata/end_to_end/alter_table_add_foreign_key", sctest.SingleNodeCluster) +} +func TestGenerateSchemaChangeCorpus_alter_table_add_foreign_key(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + sctest.GenerateSchemaChangeCorpus(t, "pkg/sql/schemachanger/testdata/end_to_end/alter_table_add_foreign_key", sctest.SingleNodeCluster) +} +func TestPause_alter_table_add_foreign_key(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + sctest.Pause(t, "pkg/sql/schemachanger/testdata/end_to_end/alter_table_add_foreign_key", sctest.SingleNodeCluster) +} +func TestRollback_alter_table_add_foreign_key(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + sctest.Rollback(t, "pkg/sql/schemachanger/testdata/end_to_end/alter_table_add_foreign_key", sctest.SingleNodeCluster) +} func TestEndToEndSideEffects_alter_table_add_primary_key_drop_rowid(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) diff --git a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_add_foreign_key b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_add_foreign_key new file mode 100644 index 000000000000..7e9587d48380 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_add_foreign_key @@ -0,0 +1,208 @@ +setup +CREATE TABLE t1 (i INT PRIMARY KEY); +CREATE TABLE t2 (i INT PRIMARY KEY) +---- +... ++object {100 101 t1} -> 104 ++object {100 101 t2} -> 105 + +test +ALTER TABLE t1 ADD FOREIGN KEY (i) REFERENCES t2(i) +---- +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_constraint +## StatementPhase stage 1 of 1 with 1 MutationType op +upsert descriptor #104 + ... + id: 104 + modificationTime: {} + + mutations: + + - constraint: + + check: {} + + constraintType: FOREIGN_KEY + + foreignKey: + + constraintId: 2 + + name: crdb_internal_constraint_2_name_placeholder + + originColumnIds: + + - 1 + + originTableId: 104 + + referencedColumnIds: + + - 1 + + referencedTableId: 105 + + validity: Validating + + name: crdb_internal_constraint_2_name_placeholder + + uniqueWithoutIndexConstraint: {} + + direction: ADD + + mutationId: 1 + + state: WRITE_ONLY + name: t1 + nextColumnId: 2 + - nextConstraintId: 2 + + nextConstraintId: 3 + nextFamilyId: 1 + nextIndexId: 2 + ... + time: {} + unexposedParentSchemaId: 101 + - version: "1" + + version: "2" +# end StatementPhase +# begin PreCommitPhase +## PreCommitPhase stage 1 of 1 with 3 MutationType ops +upsert descriptor #104 + ... + createAsOfTime: + wallTime: "1640995200000000000" + + declarativeSchemaChangerState: + + authorization: + + userName: root + + currentStatuses: + + jobId: "1" + + relevantStatements: + + - statement: + + redactedStatement: ALTER TABLE ‹defaultdb›.‹public›.‹t1› ADD CONSTRAINT ‹t1_i_fkey› + + FOREIGN KEY (‹i›) REFERENCES ‹defaultdb›.‹public›.‹t2› (‹i›) + + statement: ALTER TABLE t1 ADD FOREIGN KEY (i) REFERENCES t2 (i) + + statementTag: ALTER TABLE + + revertible: true + + targetRanks: + + targets: + families: + - columnIds: + ... + time: {} + unexposedParentSchemaId: 101 + - version: "1" + + version: "2" +upsert descriptor #105 + ... + createAsOfTime: + wallTime: "1640995200000000000" + + declarativeSchemaChangerState: + + authorization: + + userName: root + + jobId: "1" + + revertible: true + families: + - columnIds: + ... + time: {} + unexposedParentSchemaId: 101 + - version: "1" + + version: "2" +create job #1 (non-cancelable: false): "ALTER TABLE defaultdb.public.t1 ADD CONSTRAINT t1_i_fkey FOREIGN KEY (i) REFERENCES defaultdb.public.t2 (i)" + descriptor IDs: [104 105] +# 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 2 with 1 ValidationType op +validate FOREIGN KEY constraint crdb_internal_constraint_2_name_placeholder in table #104 +commit transaction #3 +begin transaction #4 +## PostCommitPhase stage 2 of 2 with 5 MutationType ops +upsert descriptor #104 + ... + createAsOfTime: + wallTime: "1640995200000000000" + - declarativeSchemaChangerState: + - authorization: + - userName: root + - currentStatuses: + - jobId: "1" + - relevantStatements: + - - statement: + - redactedStatement: ALTER TABLE ‹defaultdb›.‹public›.‹t1› ADD CONSTRAINT ‹t1_i_fkey› + - FOREIGN KEY (‹i›) REFERENCES ‹defaultdb›.‹public›.‹t2› (‹i›) + - statement: ALTER TABLE t1 ADD FOREIGN KEY (i) REFERENCES t2 (i) + - statementTag: ALTER TABLE + - revertible: true + - targetRanks: + - targets: + families: + - columnIds: + ... + id: 104 + modificationTime: {} + - mutations: + - - constraint: + - check: {} + - constraintType: FOREIGN_KEY + - foreignKey: + - constraintId: 2 + - name: crdb_internal_constraint_2_name_placeholder + - originColumnIds: + - - 1 + - originTableId: 104 + - referencedColumnIds: + - - 1 + - referencedTableId: 105 + - validity: Validating + - name: crdb_internal_constraint_2_name_placeholder + - uniqueWithoutIndexConstraint: {} + - direction: ADD + - mutationId: 1 + - state: WRITE_ONLY + name: t1 + nextColumnId: 2 + ... + nextIndexId: 2 + nextMutationId: 1 + + outboundFks: + + - constraintId: 2 + + name: t1_i_fkey + + originColumnIds: + + - 1 + + originTableId: 104 + + referencedColumnIds: + + - 1 + + referencedTableId: 105 + parentId: 100 + primaryIndex: + ... + time: {} + unexposedParentSchemaId: 101 + - version: "2" + + version: "3" +upsert descriptor #105 + ... + createAsOfTime: + wallTime: "1640995200000000000" + - declarativeSchemaChangerState: + - authorization: + - userName: root + - jobId: "1" + - revertible: true + families: + - columnIds: + ... + formatVersion: 3 + id: 105 + + inboundFks: + + - constraintId: 2 + + name: t1_i_fkey + + originColumnIds: + + - 1 + + originTableId: 104 + + referencedColumnIds: + + - 1 + + referencedTableId: 105 + + validity: Validating + modificationTime: {} + name: t2 + ... + time: {} + unexposedParentSchemaId: 101 + - version: "2" + + version: "3" +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 [] +commit transaction #4 +# end PostCommitPhase diff --git a/pkg/sql/schemachanger/testdata/explain/alter_table_add_foreign_key b/pkg/sql/schemachanger/testdata/explain/alter_table_add_foreign_key new file mode 100644 index 000000000000..f1e50a614857 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/explain/alter_table_add_foreign_key @@ -0,0 +1,36 @@ +/* setup */ +CREATE TABLE t1 (i INT PRIMARY KEY); +CREATE TABLE t2 (i INT PRIMARY KEY); + +/* test */ +EXPLAIN (ddl) ALTER TABLE t1 ADD FOREIGN KEY (i) REFERENCES t2(i); +---- +Schema change plan for ALTER TABLE ‹defaultdb›.‹public›.‹t1› ADD CONSTRAINT ‹t1_i_fkey› FOREIGN KEY (‹i›) REFERENCES ‹defaultdb›.‹public›.‹t2› (‹i›); + ├── StatementPhase + │ └── Stage 1 of 1 in StatementPhase + │ ├── 1 element transitioning toward PUBLIC + │ │ └── ABSENT → WRITE_ONLY ForeignKeyConstraint:{DescID: 104, IndexID: 0, ConstraintID: 2, ReferencedDescID: 105} + │ └── 1 Mutation operation + │ └── MakeAbsentForeignKeyConstraintWriteOnly {"ConstraintID":2,"ReferencedTableID":105,"TableID":104} + ├── PreCommitPhase + │ └── Stage 1 of 1 in PreCommitPhase + │ └── 3 Mutation operations + │ ├── SetJobStateOnDescriptor {"DescriptorID":104,"Initialize":true} + │ ├── SetJobStateOnDescriptor {"DescriptorID":105,"Initialize":true} + │ └── CreateSchemaChangerJob {"RunningStatus":"PostCommitPhase ..."} + └── PostCommitPhase + ├── Stage 1 of 2 in PostCommitPhase + │ ├── 1 element transitioning toward PUBLIC + │ │ └── WRITE_ONLY → VALIDATED ForeignKeyConstraint:{DescID: 104, IndexID: 0, ConstraintID: 2, ReferencedDescID: 105} + │ └── 1 Validation operation + │ └── ValidateConstraint {"ConstraintID":2,"TableID":104} + └── Stage 2 of 2 in PostCommitPhase + ├── 2 elements transitioning toward PUBLIC + │ ├── VALIDATED → PUBLIC ForeignKeyConstraint:{DescID: 104, IndexID: 0, ConstraintID: 2, ReferencedDescID: 105} + │ └── ABSENT → PUBLIC ConstraintWithoutIndexName:{DescID: 104, Name: t1_i_fkey, ConstraintID: 2} + └── 5 Mutation operations + ├── SetConstraintName {"ConstraintID":2,"Name":"t1_i_fkey","TableID":104} + ├── MakeValidatedForeignKeyConstraintPublic {"ConstraintID":2,"ReferencedTableID":105,"TableID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":105} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/explain/alter_table_add_foreign_key.rollback_1_of_2 b/pkg/sql/schemachanger/testdata/explain/alter_table_add_foreign_key.rollback_1_of_2 new file mode 100644 index 000000000000..f135aa1e6247 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/explain/alter_table_add_foreign_key.rollback_1_of_2 @@ -0,0 +1,19 @@ +/* setup */ +CREATE TABLE t1 (i INT PRIMARY KEY); +CREATE TABLE t2 (i INT PRIMARY KEY); + +/* test */ +ALTER TABLE t1 ADD FOREIGN KEY (i) REFERENCES t2(i); +EXPLAIN (ddl) rollback at post-commit stage 1 of 2; +---- +Schema change plan for rolling back ALTER TABLE ‹defaultdb›.public.‹t1› ADD CONSTRAINT ‹t1_i_fkey› FOREIGN KEY (‹i›) REFERENCES ‹defaultdb›.public.‹t2› (‹i›); + └── PostCommitNonRevertiblePhase + └── Stage 1 of 1 in PostCommitNonRevertiblePhase + ├── 1 element transitioning toward ABSENT + │ └── WRITE_ONLY → ABSENT ForeignKeyConstraint:{DescID: 104, IndexID: 0, ConstraintID: 2, ReferencedDescID: 105} + └── 5 Mutation operations + ├── RemoveForeignKeyBackReference {"OriginConstraintID":2,"OriginTableID":104,"ReferencedTableID":105} + ├── RemoveForeignKeyConstraint {"ConstraintID":2,"TableID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":105} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/explain/alter_table_add_foreign_key.rollback_2_of_2 b/pkg/sql/schemachanger/testdata/explain/alter_table_add_foreign_key.rollback_2_of_2 new file mode 100644 index 000000000000..66f0b3181bf8 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/explain/alter_table_add_foreign_key.rollback_2_of_2 @@ -0,0 +1,19 @@ +/* setup */ +CREATE TABLE t1 (i INT PRIMARY KEY); +CREATE TABLE t2 (i INT PRIMARY KEY); + +/* test */ +ALTER TABLE t1 ADD FOREIGN KEY (i) REFERENCES t2(i); +EXPLAIN (ddl) rollback at post-commit stage 2 of 2; +---- +Schema change plan for rolling back ALTER TABLE ‹defaultdb›.public.‹t1› ADD CONSTRAINT ‹t1_i_fkey› FOREIGN KEY (‹i›) REFERENCES ‹defaultdb›.public.‹t2› (‹i›); + └── PostCommitNonRevertiblePhase + └── Stage 1 of 1 in PostCommitNonRevertiblePhase + ├── 1 element transitioning toward ABSENT + │ └── WRITE_ONLY → ABSENT ForeignKeyConstraint:{DescID: 104, IndexID: 0, ConstraintID: 2, ReferencedDescID: 105} + └── 5 Mutation operations + ├── RemoveForeignKeyBackReference {"OriginConstraintID":2,"OriginTableID":104,"ReferencedTableID":105} + ├── RemoveForeignKeyConstraint {"ConstraintID":2,"TableID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":105} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/explain_verbose/alter_table_add_foreign_key b/pkg/sql/schemachanger/testdata/explain_verbose/alter_table_add_foreign_key new file mode 100644 index 000000000000..0ff6b0de9326 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/explain_verbose/alter_table_add_foreign_key @@ -0,0 +1,121 @@ +/* setup */ +CREATE TABLE t1 (i INT PRIMARY KEY); +CREATE TABLE t2 (i INT PRIMARY KEY); + +/* test */ +EXPLAIN (ddl, verbose) ALTER TABLE t1 ADD FOREIGN KEY (i) REFERENCES t2(i); +---- +• Schema change plan for ALTER TABLE ‹defaultdb›.‹public›.‹t1› ADD CONSTRAINT ‹t1_i_fkey› FOREIGN KEY (‹i›) REFERENCES ‹defaultdb›.‹public›.‹t2› (‹i›); +│ +├── • StatementPhase +│ │ +│ └── • Stage 1 of 1 in StatementPhase +│ │ +│ ├── • 1 element transitioning toward PUBLIC +│ │ │ +│ │ └── • ForeignKeyConstraint:{DescID: 104, IndexID: 0, ConstraintID: 2, ReferencedDescID: 105} +│ │ │ ABSENT → WRITE_ONLY +│ │ │ +│ │ └── • PreviousTransactionPrecedence dependency from ABSENT ForeignKeyConstraint:{DescID: 104, IndexID: 0, ConstraintID: 2, ReferencedDescID: 105} +│ │ rule: "ForeignKeyConstraint transitions to PUBLIC uphold 2-version invariant: ABSENT->WRITE_ONLY" +│ │ +│ └── • 1 Mutation operation +│ │ +│ └── • MakeAbsentForeignKeyConstraintWriteOnly +│ ColumnIDs: +│ - 1 +│ ConstraintID: 2 +│ ReferencedColumnIDs: +│ - 1 +│ ReferencedTableID: 105 +│ TableID: 104 +│ +├── • PreCommitPhase +│ │ +│ └── • Stage 1 of 1 in PreCommitPhase +│ │ +│ └── • 3 Mutation operations +│ │ +│ ├── • SetJobStateOnDescriptor +│ │ DescriptorID: 104 +│ │ Initialize: true +│ │ +│ ├── • SetJobStateOnDescriptor +│ │ DescriptorID: 105 +│ │ Initialize: true +│ │ +│ └── • CreateSchemaChangerJob +│ Authorization: +│ UserName: root +│ DescriptorIDs: +│ - 104 +│ - 105 +│ JobID: 1 +│ RunningStatus: PostCommitPhase stage 1 of 2 with 1 ValidationType op pending +│ Statements: +│ - statement: ALTER TABLE t1 ADD FOREIGN KEY (i) REFERENCES t2 (i) +│ redactedstatement: ALTER TABLE ‹defaultdb›.‹public›.‹t1› ADD CONSTRAINT ‹t1_i_fkey› +│ FOREIGN KEY (‹i›) REFERENCES ‹defaultdb›.‹public›.‹t2› (‹i›) +│ statementtag: ALTER TABLE +│ +└── • PostCommitPhase + │ + ├── • Stage 1 of 2 in PostCommitPhase + │ │ + │ ├── • 1 element transitioning toward PUBLIC + │ │ │ + │ │ └── • ForeignKeyConstraint:{DescID: 104, IndexID: 0, ConstraintID: 2, ReferencedDescID: 105} + │ │ │ WRITE_ONLY → VALIDATED + │ │ │ + │ │ └── • PreviousTransactionPrecedence dependency from WRITE_ONLY ForeignKeyConstraint:{DescID: 104, IndexID: 0, ConstraintID: 2, ReferencedDescID: 105} + │ │ rule: "ForeignKeyConstraint transitions to PUBLIC uphold 2-version invariant: WRITE_ONLY->VALIDATED" + │ │ + │ └── • 1 Validation operation + │ │ + │ └── • ValidateConstraint + │ ConstraintID: 2 + │ TableID: 104 + │ + └── • Stage 2 of 2 in PostCommitPhase + │ + ├── • 2 elements transitioning toward PUBLIC + │ │ + │ ├── • ForeignKeyConstraint:{DescID: 104, IndexID: 0, ConstraintID: 2, ReferencedDescID: 105} + │ │ │ VALIDATED → PUBLIC + │ │ │ + │ │ ├── • PreviousTransactionPrecedence dependency from VALIDATED ForeignKeyConstraint:{DescID: 104, IndexID: 0, ConstraintID: 2, ReferencedDescID: 105} + │ │ │ rule: "ForeignKeyConstraint transitions to PUBLIC uphold 2-version invariant: VALIDATED->PUBLIC" + │ │ │ + │ │ └── • SameStagePrecedence dependency from PUBLIC ConstraintWithoutIndexName:{DescID: 104, Name: t1_i_fkey, ConstraintID: 2} + │ │ rule: "constraint dependent public right before constraint" + │ │ + │ └── • ConstraintWithoutIndexName:{DescID: 104, Name: t1_i_fkey, ConstraintID: 2} + │ ABSENT → PUBLIC + │ + └── • 5 Mutation operations + │ + ├── • SetConstraintName + │ ConstraintID: 2 + │ Name: t1_i_fkey + │ TableID: 104 + │ + ├── • MakeValidatedForeignKeyConstraintPublic + │ ConstraintID: 2 + │ ReferencedTableID: 105 + │ TableID: 104 + │ + ├── • RemoveJobStateFromDescriptor + │ DescriptorID: 104 + │ JobID: 1 + │ + ├── • RemoveJobStateFromDescriptor + │ DescriptorID: 105 + │ JobID: 1 + │ + └── • UpdateSchemaChangerJob + DescriptorIDsToRemove: + - 104 + - 105 + IsNonCancelable: true + JobID: 1 + RunningStatus: all stages completed diff --git a/pkg/sql/schemachanger/testdata/explain_verbose/alter_table_add_foreign_key.rollback_1_of_2 b/pkg/sql/schemachanger/testdata/explain_verbose/alter_table_add_foreign_key.rollback_1_of_2 new file mode 100644 index 000000000000..81ea88a930a3 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/explain_verbose/alter_table_add_foreign_key.rollback_1_of_2 @@ -0,0 +1,51 @@ +/* setup */ +CREATE TABLE t1 (i INT PRIMARY KEY); +CREATE TABLE t2 (i INT PRIMARY KEY); + +/* test */ +ALTER TABLE t1 ADD FOREIGN KEY (i) REFERENCES t2(i); +EXPLAIN (ddl, verbose) rollback at post-commit stage 1 of 2; +---- +• Schema change plan for rolling back ALTER TABLE ‹defaultdb›.public.‹t1› ADD CONSTRAINT ‹t1_i_fkey› FOREIGN KEY (‹i›) REFERENCES ‹defaultdb›.public.‹t2› (‹i›); +│ +└── • PostCommitNonRevertiblePhase + │ + └── • Stage 1 of 1 in PostCommitNonRevertiblePhase + │ + ├── • 1 element transitioning toward ABSENT + │ │ + │ └── • ForeignKeyConstraint:{DescID: 104, IndexID: 0, ConstraintID: 2, ReferencedDescID: 105} + │ │ WRITE_ONLY → ABSENT + │ │ + │ ├── • PreviousTransactionPrecedence dependency from WRITE_ONLY ForeignKeyConstraint:{DescID: 104, IndexID: 0, ConstraintID: 2, ReferencedDescID: 105} + │ │ rule: "ForeignKeyConstraint transitions to ABSENT uphold 2-version invariant: WRITE_ONLY->VALIDATED" + │ │ + │ └── • Precedence dependency from ABSENT ConstraintWithoutIndexName:{DescID: 104, Name: t1_i_fkey, ConstraintID: 2} + │ rule: "dependents removed before constraint" + │ + └── • 5 Mutation operations + │ + ├── • RemoveForeignKeyBackReference + │ OriginConstraintID: 2 + │ OriginTableID: 104 + │ ReferencedTableID: 105 + │ + ├── • RemoveForeignKeyConstraint + │ ConstraintID: 2 + │ TableID: 104 + │ + ├── • RemoveJobStateFromDescriptor + │ DescriptorID: 104 + │ JobID: 1 + │ + ├── • RemoveJobStateFromDescriptor + │ DescriptorID: 105 + │ JobID: 1 + │ + └── • UpdateSchemaChangerJob + DescriptorIDsToRemove: + - 104 + - 105 + IsNonCancelable: true + JobID: 1 + RunningStatus: all stages completed diff --git a/pkg/sql/schemachanger/testdata/explain_verbose/alter_table_add_foreign_key.rollback_2_of_2 b/pkg/sql/schemachanger/testdata/explain_verbose/alter_table_add_foreign_key.rollback_2_of_2 new file mode 100644 index 000000000000..1c9c92f7a799 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/explain_verbose/alter_table_add_foreign_key.rollback_2_of_2 @@ -0,0 +1,51 @@ +/* setup */ +CREATE TABLE t1 (i INT PRIMARY KEY); +CREATE TABLE t2 (i INT PRIMARY KEY); + +/* test */ +ALTER TABLE t1 ADD FOREIGN KEY (i) REFERENCES t2(i); +EXPLAIN (ddl, verbose) rollback at post-commit stage 2 of 2; +---- +• Schema change plan for rolling back ALTER TABLE ‹defaultdb›.public.‹t1› ADD CONSTRAINT ‹t1_i_fkey› FOREIGN KEY (‹i›) REFERENCES ‹defaultdb›.public.‹t2› (‹i›); +│ +└── • PostCommitNonRevertiblePhase + │ + └── • Stage 1 of 1 in PostCommitNonRevertiblePhase + │ + ├── • 1 element transitioning toward ABSENT + │ │ + │ └── • ForeignKeyConstraint:{DescID: 104, IndexID: 0, ConstraintID: 2, ReferencedDescID: 105} + │ │ WRITE_ONLY → ABSENT + │ │ + │ ├── • PreviousTransactionPrecedence dependency from WRITE_ONLY ForeignKeyConstraint:{DescID: 104, IndexID: 0, ConstraintID: 2, ReferencedDescID: 105} + │ │ rule: "ForeignKeyConstraint transitions to ABSENT uphold 2-version invariant: WRITE_ONLY->VALIDATED" + │ │ + │ └── • Precedence dependency from ABSENT ConstraintWithoutIndexName:{DescID: 104, Name: t1_i_fkey, ConstraintID: 2} + │ rule: "dependents removed before constraint" + │ + └── • 5 Mutation operations + │ + ├── • RemoveForeignKeyBackReference + │ OriginConstraintID: 2 + │ OriginTableID: 104 + │ ReferencedTableID: 105 + │ + ├── • RemoveForeignKeyConstraint + │ ConstraintID: 2 + │ TableID: 104 + │ + ├── • RemoveJobStateFromDescriptor + │ DescriptorID: 104 + │ JobID: 1 + │ + ├── • RemoveJobStateFromDescriptor + │ DescriptorID: 105 + │ JobID: 1 + │ + └── • UpdateSchemaChangerJob + DescriptorIDsToRemove: + - 104 + - 105 + IsNonCancelable: true + JobID: 1 + RunningStatus: all stages completed