From c22dd0a7d7bfe6589d6a96233f5471d90f12ab2b Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Fri, 2 Aug 2024 11:08:31 -0300 Subject: [PATCH] sql/schemachanger: Validate ALTER TABLE .. TYPE in the DSC When altering the data type of a column, some changes only require validating the existing data. For example, when changing from `CHAR(20)` to `CHAR(10)`, we don't need to rewrite the data; we only need to ensure all existing data fits within `CHAR(10)`. This change implements that validation logic in the declarative schema changer. The validation logic uses a temporary check constraint. This constraint is added transiently so that it never transitions to PUBLIC and is automatically removed. The check constraint casts the column to the new type and then back to the old type. If the value matches its original value after these casts, the row is deemed valid. To add a schema changer test, I disabled the `enable_experimental_alter_column_type_general` setting for validation. It remains enabled for column type alterations requiring a rewrite and for validation-only changes in the legacy schema changer. I updated the dependency rules to allow the check constraint to be added transiently. I think this is fine even for older releases because I'm not introducing new elements or attributes for the check constraint; I'm just allowing a state transition to transient. When validation occurs, it will look something like this: ``` demo@127.0.0.1:26257/demoapp/movr> ALTER TABLE t1 ALTER COLUMN c1 SET DATA TYPE CHAR(3); ERROR: validation of CHECK "CAST(CAST(c1 AS CHAR(3)) AS CHAR(20)) = c1" failed on row: c1='123456789', rowid=990187907647504385 SQLSTATE: 23514 ``` Epic: CRDB-25314 Closes: #127516 Release note: None --- pkg/ccl/changefeedccl/cdcevent/event_test.go | 46 +- .../backup_base_generated_test.go | 28 ++ pkg/cli/testdata/declarative-rules/deprules | 192 +++++++- pkg/sql/create_table.go | 2 +- .../testdata/logic_test/alter_column_type | 131 +++--- pkg/sql/logictest/testdata/logic_test/fk | 51 ++- .../scbuildstmt/alter_table_add_column.go | 7 +- .../scbuildstmt/alter_table_add_constraint.go | 4 +- .../alter_table_alter_column_type.go | 96 +++- .../scbuild/internal/scbuildstmt/helpers.go | 12 + .../testdata/alter_table_alter_column_type | 14 + .../scexec/scmutationexec/column.go | 16 +- .../internal/opgen/opgen_check_constraint.go | 1 + .../rules/current/dep_alter_column_type.go | 21 + .../internal/rules/current/testdata/deprules | 416 +++++++++++++++++- .../rules/release_23_2/testdata/deprules | 348 ++++++++++++++- .../rules/release_24_1/testdata/deprules | 384 +++++++++++++++- .../scplan/internal/scstage/build.go | 9 +- .../schemachanger/sctest_generated_test.go | 42 ++ ...le_alter_column_type_validation.definition | 25 ++ ...table_alter_column_type_validation.explain | 64 +++ ...alter_column_type_validation.explain_shape | 11 + ..._alter_column_type_validation.side_effects | 313 +++++++++++++ ...n_type_validation__rollback_1_of_1.explain | 17 + 24 files changed, 2134 insertions(+), 116 deletions(-) create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation.definition create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation.explain create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation.explain_shape create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation.side_effects create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation__rollback_1_of_1.explain diff --git a/pkg/ccl/changefeedccl/cdcevent/event_test.go b/pkg/ccl/changefeedccl/cdcevent/event_test.go index 75f616167d70..ab82a3012872 100644 --- a/pkg/ccl/changefeedccl/cdcevent/event_test.go +++ b/pkg/ccl/changefeedccl/cdcevent/event_test.go @@ -460,26 +460,26 @@ func TestEventColumnOrderingWithSchemaChanges(t *testing.T) { testName: "main/main_cols", familyName: "main", actions: []string{ - "INSERT INTO foo (i,j,a,b) VALUES (0,1,'a0','b0')", - "ALTER TABLE foo ALTER COLUMN a SET DATA TYPE VARCHAR(16)", - "INSERT INTO foo (i,j,a,b) VALUES (1,2,'a1','b1')", + "INSERT INTO foo (i,j,a,b) VALUES (0,1,'2002-05-02','b0')", + "ALTER TABLE foo ALTER COLUMN a SET DATA TYPE DATE USING a::DATE", + "INSERT INTO foo (i,j,a,b) VALUES (1,2,'2021-01-01','b1')", }, expectMainFamily: []decodeExpectation{ { keyValues: []string{"1", "0"}, - allValues: []string{"0", "1", "a0", "b0"}, + allValues: []string{"0", "1", "2002-05-02", "b0"}, }, { keyValues: []string{"1", "0"}, - allValues: []string{"0", "1", "a0", "b0"}, + allValues: []string{"0", "1", "2002-05-02", "b0"}, }, { keyValues: []string{"1", "0"}, - allValues: []string{"0", "1", "a0", "b0"}, + allValues: []string{"0", "1", "2002-05-02", "b0"}, }, { keyValues: []string{"2", "1"}, - allValues: []string{"1", "2", "a1", "b1"}, + allValues: []string{"1", "2", "2021-01-01", "b1"}, }, }, }, @@ -487,9 +487,9 @@ func TestEventColumnOrderingWithSchemaChanges(t *testing.T) { testName: "ec/ec_cols", familyName: "ec", actions: []string{ - "INSERT INTO foo (i,j,e,c) VALUES (2,3,'e2','c2')", - "ALTER TABLE foo ALTER COLUMN c SET DATA TYPE VARCHAR(16)", - "INSERT INTO foo (i,j,e,c) VALUES (3,4,'e3','c3')", + "INSERT INTO foo (i,j,e,c) VALUES (2,3,'e2','2024-08-02')", + "ALTER TABLE foo ALTER COLUMN c SET DATA TYPE DATE USING c::DATE", + "INSERT INTO foo (i,j,e,c) VALUES (3,4,'e3','2024-05-21')", }, expectMainFamily: []decodeExpectation{ { @@ -502,19 +502,19 @@ func TestEventColumnOrderingWithSchemaChanges(t *testing.T) { expectECFamily: []decodeExpectation{ { keyValues: []string{"3", "2"}, - allValues: []string{"c2", "e2"}, + allValues: []string{"2024-08-02", "e2"}, }, { keyValues: []string{"3", "2"}, - allValues: []string{"c2", "e2"}, + allValues: []string{"2024-08-02", "e2"}, }, { keyValues: []string{"3", "2"}, - allValues: []string{"c2", "e2"}, + allValues: []string{"2024-08-02", "e2"}, }, { keyValues: []string{"4", "3"}, - allValues: []string{"c3", "e3"}, + allValues: []string{"2024-05-21", "e3"}, }, }, }, @@ -522,9 +522,9 @@ func TestEventColumnOrderingWithSchemaChanges(t *testing.T) { testName: "ec/ec_cols_with_virtual", familyName: "ec", actions: []string{ - "INSERT INTO foo (i,j,e,c) VALUES (4,5,'e4','c4')", - "ALTER TABLE foo ALTER COLUMN c SET DATA TYPE VARCHAR(16)", - "INSERT INTO foo (i,j,e,c) VALUES (5,6,'e5','c5')", + "INSERT INTO foo (i,j,e,c) VALUES (4,5,'e4','2012-11-06')", + "ALTER TABLE foo ALTER COLUMN c SET DATA TYPE DATE USING c::DATE", + "INSERT INTO foo (i,j,e,c) VALUES (5,6,'e5','2014-05-06')", }, includeVirtual: true, expectMainFamily: []decodeExpectation{ @@ -538,20 +538,20 @@ func TestEventColumnOrderingWithSchemaChanges(t *testing.T) { expectECFamily: []decodeExpectation{ { keyValues: []string{"5", "4"}, - allValues: []string{"c4", "NULL", "e4"}, + allValues: []string{"2012-11-06", "NULL", "e4"}, }, { keyValues: []string{"5", "4"}, - allValues: []string{"c4", "NULL", "e4"}, + allValues: []string{"2012-11-06", "NULL", "e4"}, refreshDescriptor: true, }, { keyValues: []string{"5", "4"}, - allValues: []string{"c4", "NULL", "e4"}, + allValues: []string{"2012-11-06", "NULL", "e4"}, }, { keyValues: []string{"6", "5"}, - allValues: []string{"c5", "NULL", "e5"}, + allValues: []string{"2014-05-06", "NULL", "e5"}, }, }, }, @@ -619,8 +619,8 @@ func TestEventColumnOrderingWithSchemaChanges(t *testing.T) { require.NoError(t, err) require.True(t, updatedRow.IsInitialized()) - require.Equal(t, expect.keyValues, slurpDatums(t, updatedRow.ForEachKeyColumn())) - require.Equal(t, expect.allValues, slurpDatums(t, updatedRow.ForEachColumn())) + require.Equal(t, expect.keyValues, slurpDatums(t, updatedRow.ForEachKeyColumn()), "row %d", i) + require.Equal(t, expect.allValues, slurpDatums(t, updatedRow.ForEachColumn()), "row %d", i) } sqlDB.Exec(t, `DROP TABLE foo`) }) diff --git a/pkg/ccl/schemachangerccl/backup_base_generated_test.go b/pkg/ccl/schemachangerccl/backup_base_generated_test.go index 3a4ffd607203..4e5e35c7ea38 100644 --- a/pkg/ccl/schemachangerccl/backup_base_generated_test.go +++ b/pkg/ccl/schemachangerccl/backup_base_generated_test.go @@ -179,6 +179,13 @@ func TestBackupRollbacks_base_alter_table_alter_column_type_trivial(t *testing.T sctest.BackupRollbacks(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupRollbacks_base_alter_table_alter_column_type_validation(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation" + sctest.BackupRollbacks(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupRollbacks_base_alter_table_alter_primary_key_drop_rowid(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -676,6 +683,13 @@ func TestBackupRollbacksMixedVersion_base_alter_table_alter_column_type_trivial( sctest.BackupRollbacksMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupRollbacksMixedVersion_base_alter_table_alter_column_type_validation(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation" + sctest.BackupRollbacksMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupRollbacksMixedVersion_base_alter_table_alter_primary_key_drop_rowid(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1173,6 +1187,13 @@ func TestBackupSuccess_base_alter_table_alter_column_type_trivial(t *testing.T) sctest.BackupSuccess(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupSuccess_base_alter_table_alter_column_type_validation(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation" + sctest.BackupSuccess(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupSuccess_base_alter_table_alter_primary_key_drop_rowid(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1670,6 +1691,13 @@ func TestBackupSuccessMixedVersion_base_alter_table_alter_column_type_trivial(t sctest.BackupSuccessMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupSuccessMixedVersion_base_alter_table_alter_column_type_validation(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation" + sctest.BackupSuccessMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupSuccessMixedVersion_base_alter_table_alter_primary_key_drop_rowid(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) diff --git a/pkg/cli/testdata/declarative-rules/deprules b/pkg/cli/testdata/declarative-rules/deprules index d54a122c10ce..660cd0fe4c67 100644 --- a/pkg/cli/testdata/declarative-rules/deprules +++ b/pkg/cli/testdata/declarative-rules/deprules @@ -24,6 +24,69 @@ deprules - descriptorIsDataNotBeingAdded-24.1($descID) - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_ABSENT->ABSENT' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_ABSENT + - $next-Node[CurrentStatus] = ABSENT + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_VALIDATED->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_VALIDATED + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_WRITE_ONLY->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_WRITE_ONLY + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) - name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: VALIDATED->ABSENT' from: prev-Node kind: PreviousTransactionPrecedence @@ -43,7 +106,7 @@ deprules - $descriptor-data-Node[CurrentStatus] = PUBLIC - $descriptor-data[DescID] = $descID - descriptorIsDataNotBeingAdded-24.1($descID) - - nodeNotExistsWithStatusIn_WRITE_ONLY($prev-Target) + - nodeNotExistsWithStatusIn_TRANSIENT_VALIDATED_WRITE_ONLY_TRANSIENT_WRITE_ONLY($prev-Target) - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) - name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: WRITE_ONLY->VALIDATED' @@ -130,6 +193,133 @@ deprules - descriptorIsDataNotBeingAdded-24.1($descID) - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: ABSENT->WRITE_ONLY' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = ABSENT + - $next-Node[CurrentStatus] = WRITE_ONLY + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: PUBLIC->TRANSIENT_VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = PUBLIC + - $next-Node[CurrentStatus] = TRANSIENT_VALIDATED + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: TRANSIENT_VALIDATED->TRANSIENT_ABSENT' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_VALIDATED + - $next-Node[CurrentStatus] = TRANSIENT_ABSENT + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - nodeNotExistsWithStatusIn_TRANSIENT_WRITE_ONLY($prev-Target) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: TRANSIENT_WRITE_ONLY->TRANSIENT_VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_WRITE_ONLY + - $next-Node[CurrentStatus] = TRANSIENT_VALIDATED + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: VALIDATED->PUBLIC' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = VALIDATED + - $next-Node[CurrentStatus] = PUBLIC + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: WRITE_ONLY->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = WRITE_ONLY + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) - name: 'Column transitions to ABSENT uphold 2-version invariant: DELETE_ONLY->ABSENT' from: prev-Node kind: PreviousTransactionPrecedence diff --git a/pkg/sql/create_table.go b/pkg/sql/create_table.go index adc79aefb5c2..2de1b29c4e1f 100644 --- a/pkg/sql/create_table.go +++ b/pkg/sql/create_table.go @@ -970,7 +970,7 @@ func ResolveFK( if s, t := originCols[i], referencedCols[i]; !s.GetType().Identical(t.GetType()) { notice := pgnotice.Newf( "type of foreign key column %q (%s) is not identical to referenced column %q.%q (%s)", - s.ColName(), s.GetType().String(), target.Name, t.GetName(), t.GetType().String()) + s.ColName(), s.GetType().SQLString(), target.Name, t.GetName(), t.GetType().SQLString()) evalCtx.ClientNoticeSender.BufferClientNotice(ctx, notice) } } diff --git a/pkg/sql/logictest/testdata/logic_test/alter_column_type b/pkg/sql/logictest/testdata/logic_test/alter_column_type index 44657597c5ca..c9bad55dd382 100644 --- a/pkg/sql/logictest/testdata/logic_test/alter_column_type +++ b/pkg/sql/logictest/testdata/logic_test/alter_column_type @@ -168,10 +168,10 @@ statement ok CREATE TABLE t1 (date string) statement ok -INSERT INTO t1 VALUES ('hello') +INSERT INTO t1 VALUES ('2024-07-26') -statement error pq: ALTER COLUMN TYPE from string to char is only supported experimentally -ALTER TABLE t1 ALTER COLUMN date TYPE CHAR(10) +statement error pq: ALTER COLUMN TYPE from string to date is only supported experimentally +ALTER TABLE t1 ALTER COLUMN date TYPE DATE USING date::DATE # After setting enable_experimental_alter_column_type_general, ALTER COLUMN TYPE should work. statement ok @@ -180,7 +180,7 @@ SET enable_experimental_alter_column_type_general = true statement error pq: column "date" cannot be cast automatically to type TIMESTAMP\nHINT: You might need to specify "USING date::TIMESTAMP". ALTER TABLE t1 ALTER COLUMN date TYPE timestamp -statement error pq: parsing as type timestamp: could not parse "hello" +statement ok ALTER TABLE t1 ALTER COLUMN date TYPE timestamp USING date::TIMESTAMP # Verify ALTER COLUMN TYPE from INT to STRING works correctly. @@ -907,24 +907,36 @@ hello world worldhello statement ok ALTER TABLE t_bytes ALTER COLUMN c1 SET DATA TYPE STRING; -# TODO(spilchen): This works in the legacy schema changer, but it ends up with -# wrong results. Once we query the table again we will see the data for c2 -# truncated. Leaving this here for now but will be addressed when we add -# validation only logic in the dsc. This will be done in issue #127516. -statement ok -ALTER TABLE t_bytes ALTER COLUMN c2 SET DATA TYPE CHAR(3); +# When the above alter is done in the legacy schema changer, the column is +# rewritten, but with different result. The correct one is from the +# declarative schema changer. So we skip when running the legacy schema changer. +skipif config local-legacy-schema-changer +skipif config local-mixed-23.2 +query T +SELECT c1 FROM t_bytes ORDER BY c1; +---- +NULL +hello -query TTT -SELECT * FROM t_bytes ORDER BY c1; +# The legacy schema changer doesn't properly handle this case. It will actually +# allow it, which is wrong. So we expect success for legacy, but correctly fail +# for dsc. +skipif config local-legacy-schema-changer +skipif config local-mixed-23.2 +statement error pq: validation of CHECK ".*" failed on row.* +ALTER TABLE t_bytes ALTER COLUMN c2 SET DATA TYPE CHAR(4); + +query TT +SELECT c2, c3 FROM t_bytes ORDER BY c1; ---- -NULL NULL NULL -\x68656c6c6f \x7 worldhello +NULL NULL +world worldhello statement ok UPDATE t_bytes SET c2 = 'w'; statement ok -ALTER TABLE t_bytes ALTER COLUMN c2 SET DATA TYPE CHAR(3); +ALTER TABLE t_bytes ALTER COLUMN c2 SET DATA TYPE CHAR(4); statement error pq: column "c3" cannot be cast automatically to type UUID\nHINT: You might need to specify "USING c3::UUID". ALTER TABLE t_bytes ALTER COLUMN c3 SET DATA TYPE UUID; @@ -938,18 +950,23 @@ UPDATE t_bytes SET c3='\x3b5692c80f7349ec91868f1478f3064a' WHERE c1 IS NOT NULL; statement ok ALTER TABLE t_bytes ALTER COLUMN c3 SET DATA TYPE UUID USING c3::UUID; -query TTT -SELECT * FROM t_bytes ORDER BY c1; +# The alter of C2 will produce different output depending on the schema changer. +# The output for the the dsc is correct, but wrong for legacy. So, skipping if +# legacy. +skipif config local-legacy-schema-changer +skipif config local-mixed-23.2 +query TT +SELECT c2,c3 FROM t_bytes ORDER BY c1; ---- -NULL w NULL -\x68656c6c6f w 3b5692c8-0f73-49ec-9186-8f1478f3064a +w NULL +w 3b5692c8-0f73-49ec-9186-8f1478f3064a query TT SHOW CREATE TABLE t_bytes; ---- t_bytes CREATE TABLE public.t_bytes ( c1 STRING NULL, - c2 CHAR(3) NULL, + c2 CHAR(4) NULL, c3 UUID NULL, rowid INT8 NOT VISIBLE NOT NULL DEFAULT unique_rowid(), CONSTRAINT t_bytes_pkey PRIMARY KEY (rowid ASC), @@ -975,7 +992,7 @@ NULL NULL 100012.34 4563.21 # Reduce the overall precision of the decimal -statement error pq: type DECIMAL\(7,2\): value with precision 7, scale 2 must round to an absolute value less than 10\^5 +statement error pq: .*value with precision 7, scale 2 must round to an absolute value less than 10\^5 ALTER TABLE t_decimal ALTER COLUMN c1 SET DATA TYPE DECIMAL(7,2); # Reduce the overall precision of the decimal so that the alter will work @@ -985,21 +1002,19 @@ UPDATE t_decimal SET c1 = 10012.34 WHERE c1 = 100012.34; statement ok ALTER TABLE t_decimal ALTER COLUMN c1 SET DATA TYPE DECIMAL(7,2); -# Reduce just the scale of the decimal -# -# TODO(spilchen): The legacy schema changer allows this, even though existing -# rows will not fit in the (10,2) decimal since the scale is too small for -# existing rows. It actually truncates the data, which doesn't seem right. This -# will get addressed when we add the validation only logic in #127516. -statement ok +# Reduce just the scale of the decimal. The legacy schema changer doesn't +# properly detect this case. +skipif config local-legacy-schema-changer +skipif config local-mixed-23.2 +statement error pq: validation of CHECK ".*" failed on row.* ALTER TABLE t_decimal ALTER COLUMN c2 SET DATA TYPE DECIMAL(10,2); query FF SELECT * FROM t_decimal ORDER BY c1; ---- -NULL NULL -10012.34 4563.21 -12345.6 1.23 +NULL NULL +10012.34000 4563.21000 +12345.60000 1.23456 statement ok UPDATE t_decimal SET c2 = 1.23 WHERE c1 = 12345.6; @@ -1042,33 +1057,33 @@ SELECT c1,c2,c3,c4,c5 FROM t_bit_string ORDER BY pk; 10101010 10101010 hello world worldhello NULL NULL NULL NULL NULL -statement error pq: unimplemented: ALTER COLUMN TYPE cannot be used in combination with other ALTER TABLE commands +# Skip for the legacy schema changer as it doesn't allow multiple alters in one statement. +skipif config local-legacy-schema-changer +skipif config local-mixed-23.2 +statement error pq: validation of CHECK ".*" failed on row.* ALTER TABLE t_bit_string ALTER COLUMN c1 SET DATA TYPE BIT(4), ALTER COLUMN c2 SET DATA TYPE VARBIT(4); -# TODO(spilchen): The legacy schema changer allows this, even though existing -# rows will not fit in the new type. The data of existing rows gets truncated, -# which isn't correct. This will get addressed when we add the validation -# only logic in #127516. statement ok -ALTER TABLE t_bit_string ALTER COLUMN c1 SET DATA TYPE BIT(4); +UPDATE t_bit_string SET C2=B'1010' WHERE pk = 1; +skipif config local-legacy-schema-changer +skipif config local-mixed-23.2 statement ok -ALTER TABLE t_bit_string ALTER COLUMN c2 SET DATA TYPE VARBIT(4); +ALTER TABLE t_bit_string ALTER COLUMN c1 SET DATA TYPE VARBIT(8), ALTER COLUMN c2 SET DATA TYPE VARBIT(4); -query TTTTT -SELECT c1,c2,c3,c4,c5 FROM t_bit_string ORDER BY pk; ----- -1010 1010 hello world worldhello -NULL NULL NULL NULL NULL +# Include the same alters above but in separate statements for the legacy schema changer. +statement ok +ALTER TABLE t_bit_string ALTER COLUMN c1 SET DATA TYPE VARBIT(8); statement ok -UPDATE t_bit_string SET c1 = B'1010', c2 = B'1010' WHERE pk = 1; +ALTER TABLE t_bit_string ALTER COLUMN c2 SET DATA TYPE VARBIT(4); +# Now that C1 is a VARBIT, shrink the size of C1 so that we can convert to a BIT statement ok -ALTER TABLE t_bit_string ALTER COLUMN c1 SET DATA TYPE BIT(4); +UPDATE t_bit_string SET C1=B'1010' WHERE pk = 1; statement ok -ALTER TABLE t_bit_string ALTER COLUMN c2 SET DATA TYPE VARBIT(4); +ALTER TABLE t_bit_string ALTER COLUMN c1 SET DATA TYPE BIT(4); query TTTTT SELECT c1,c2,c3,c4,c5 FROM t_bit_string ORDER BY pk; @@ -1082,15 +1097,17 @@ ALTER TABLE t_bit_string ALTER COLUMN c3 SET DATA TYPE BYTES; statement ok ALTER TABLE t_bit_string ALTER COLUMN c3 SET DATA TYPE BYTES USING C3::BYTES; -# TODO(spilchen): The legacy schema changer allows this, even though existing -# rows will not fit in the new type. We will address this in #127516. -statement ok +# Skipping this for legacy since it allows the data type conversion when it +# shouldn't be allowed. +skipif config local-legacy-schema-changer +skipif config local-mixed-23.2 +statement error pq: validation of CHECK ".*" failed on row.* ALTER TABLE t_bit_string ALTER COLUMN c4 SET DATA TYPE CHAR(4); query TTTTT SELECT c1,c2,c3,c4,c5 FROM t_bit_string ORDER BY pk; ---- -1010 1010 hello worl worldhello +1010 1010 hello world worldhello NULL NULL NULL NULL NULL statement ok @@ -1105,15 +1122,17 @@ SELECT c1,c2,c3,c4,c5 FROM t_bit_string ORDER BY pk; 1010 1010 hello worl worldhello NULL NULL NULL NULL NULL -# Change c5 from VARCHAR(30) to CHAR(6) -# TODO(spilchen): this should be blocked when we add validation-only logic in #127516. -statement ok +# Change c5 from VARCHAR(30) to CHAR(6). This is erroneously allowed in the +# legacy schema changer so skipping in that mode. +skipif config local-legacy-schema-changer +skipif config local-mixed-23.2 +statement error pq: validation of CHECK ".*" failed on row.* ALTER TABLE t_bit_string ALTER COLUMN c5 SET DATA TYPE CHAR(6); query TTTTT SELECT c1,c2,c3,c4,c5 FROM t_bit_string ORDER BY pk; ---- -1010 1010 hello worl worldh +1010 1010 hello worl worldhello NULL NULL NULL NULL NULL statement ok @@ -1153,7 +1172,7 @@ CREATE TABLE t_int (pk INT PRIMARY KEY, c1 INT8, FAMILY F1(pk,c1)); statement ok INSERT INTO t_int VALUES (1, 2147483648),(2,NULL); -statement error pq: integer out of range for type int4 +statement error pq: .*integer out of range for type int4 ALTER TABLE t_int ALTER COLUMN c1 SET DATA TYPE INT4; statement ok @@ -1168,7 +1187,7 @@ NULL statement ok ALTER TABLE t_int ALTER COLUMN c1 SET DATA TYPE INT4; -statement error pq: integer out of range for type int2 +statement error pq: .*integer out of range for type int2 ALTER TABLE t_int ALTER COLUMN c1 SET DATA TYPE INT2; statement ok diff --git a/pkg/sql/logictest/testdata/logic_test/fk b/pkg/sql/logictest/testdata/logic_test/fk index 5c4b83019cd2..fc24ba6f5a30 100644 --- a/pkg/sql/logictest/testdata/logic_test/fk +++ b/pkg/sql/logictest/testdata/logic_test/fk @@ -4071,7 +4071,7 @@ skipif config local-read-committed query T noticetrace CREATE TABLE db_type_test.public.child_1 (id INT8 PRIMARY KEY, parent_id INT4 NULL REFERENCES db_type_test.public.parent(id), name STRING NULL) ---- -NOTICE: type of foreign key column "parent_id" (int4) is not identical to referenced column "parent"."id" (int) +NOTICE: type of foreign key column "parent_id" (INT4) is not identical to referenced column "parent"."id" (INT8) onlyif config local-read-committed statement ok @@ -4085,7 +4085,7 @@ skipif config local-read-committed query T noticetrace ALTER TABLE db_type_test.public.child_2 ADD CONSTRAINT child_2_fk_parent_id FOREIGN KEY (parent_id) REFERENCES db_type_test.public.parent(id) ---- -NOTICE: type of foreign key column "parent_id" (int4) is not identical to referenced column "parent"."id" (int) +NOTICE: type of foreign key column "parent_id" (INT4) is not identical to referenced column "parent"."id" (INT8) onlyif config local-read-committed statement ok @@ -4213,3 +4213,50 @@ SELECT constraint_catalog, constraint_schema, constraint_name, unique_constraint FROM information_schema.referential_constraints WHERE unique_constraint_schema='sc1'; ---- test sc2 child_r_fkey test sc1 parent_pkey + +subtest ensure_notice_when_fk_type_not_equal_in_alter + +statement ok +CREATE TABLE t1_fk ( pk INT PRIMARY KEY, col1 CHAR(7), col2 INT4, UNIQUE (col1,col2), FAMILY f1 (pk,col1,col2) ); + +query T noticetrace +CREATE TABLE t2_fk ( pk INT PRIMARY KEY, t1_fk_col1 CHAR(8), t1_fk_col2 INT4, col3 INT, FOREIGN KEY (t1_fk_col1,t1_fk_col2) REFERENCES t1_fk(col1, col2), FAMILY f1 (pk,t1_fk_col1,t1_fk_col2) ); +---- +NOTICE: type of foreign key column "t1_fk_col1" \(CHAR\(8\)\) is not identical to referenced column "t1_fk"."col1" \(CHAR\(7\)\) + +# Test trivial data type change +skipif config local-legacy-schema-changer +skipif config local-mixed-23.2 +query T noticetrace +ALTER TABLE t2_fk ALTER COLUMN t1_fk_col2 SET DATA TYPE INT8 +---- +NOTICE: type of foreign key column "t1_fk_col2" \(INT8\) is not identical to referenced column "t1_fk"."col2" \(INT4\) + +# Test validation data type change +skipif config local-legacy-schema-changer +skipif config local-mixed-23.2 +query T noticetrace +ALTER TABLE t2_fk ALTER COLUMN t1_fk_col1 SET DATA TYPE CHAR(5) +---- +NOTICE: type of foreign key column "t1_fk_col1" \(CHAR\(5\)\) is not identical to referenced column "t1_fk"."col1" \(CHAR\(7\)\) + +skipif config local-legacy-schema-changer +skipif config local-mixed-23.2 +query TT +SHOW CREATE TABLE t2_fk +---- +t2_fk CREATE TABLE public.t2_fk ( + pk INT8 NOT NULL, + t1_fk_col1 CHAR(5) NULL, + t1_fk_col2 INT8 NULL, + col3 INT8 NULL, + CONSTRAINT t2_fk_pkey PRIMARY KEY (pk ASC), + CONSTRAINT t2_fk_t1_fk_col1_t1_fk_col2_fkey FOREIGN KEY (t1_fk_col1, t1_fk_col2) REFERENCES public.t1_fk(col1, col2), + FAMILY f1 (pk, t1_fk_col1, t1_fk_col2, col3) + ) + +statement ok +DROP TABLE t2_fk; +DROP TABLE t1_fk; + +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 6a20a73fd53c..759887adfe4c 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 @@ -303,12 +303,7 @@ func addColumn(b BuildCtx, spec addColumnSpec, n tree.NodeFormatter) (backing *s } // Don't need to modify primary indexes for virtual columns. if spec.colType.IsVirtual { - chain := getPrimaryIndexChain(b, spec.tbl.TableID) - if chain.finalSpec.primary != nil { - return chain.finalSpec.primary - } else { - return chain.oldSpec.primary - } + return getLatestPrimaryIndex(b, spec.tbl.TableID) } inflatedChain := getInflatedPrimaryIndexChain(b, spec.tbl.TableID) diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_add_constraint.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_add_constraint.go index 66a5bd0d617e..b0e9f5af14c5 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_add_constraint.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_add_constraint.go @@ -348,8 +348,8 @@ func alterTableAddForeignKey( b.EvalCtx().ClientNoticeSender.BufferClientNotice(b, pgnotice.Newf( "type of foreign key column %q (%s) is not identical to referenced column %q.%q (%s)", - originColName, originColType.String(), - referencedTableNamespaceElem.Name, referencedColName, referencedColType.String()), + originColName, originColType.SQLString(), + referencedTableNamespaceElem.Name, referencedColName, referencedColType.SQLString()), ) } } diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_column_type.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_column_type.go index aa4525ce31ed..0e328186f150 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_column_type.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_column_type.go @@ -11,10 +11,14 @@ package scbuildstmt import ( + "fmt" + "github.com/cockroachdb/cockroach/pkg/build" "github.com/cockroachdb/cockroach/pkg/sql/catalog/catpb" + "github.com/cockroachdb/cockroach/pkg/sql/parser" "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/schemachange" "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scerrors" "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scpb" @@ -89,9 +93,9 @@ func alterTableAlterColumnType( switch kind { case schemachange.ColumnConversionTrivial: - handleTrivialColumnConversion(b, oldColType, &newColType) + handleTrivialColumnConversion(b, col, oldColType, &newColType) case schemachange.ColumnConversionValidate: - handleValidationOnlyColumnConversion(b, t, oldColType, &newColType) + handleValidationOnlyColumnConversion(b, t, col, oldColType, &newColType) case schemachange.ColumnConversionGeneral: handleGeneralColumnConversion(b, t, col, oldColType, &newColType) default: @@ -160,24 +164,46 @@ func validateAutomaticCastForNewType( // handleTrivialColumnConversion is called to just change the type in-place without // no rewrite or validation required. -func handleTrivialColumnConversion(b BuildCtx, oldColType, newColType *scpb.ColumnType) { - // Add the new type and remove the old type. The removal of the old type is a - // no-op in opgen. But we need the drop here so that we only have 1 public - // type for the column. - b.Drop(oldColType) - b.Add(newColType) +func handleTrivialColumnConversion( + b BuildCtx, col *scpb.Column, oldColType, newColType *scpb.ColumnType, +) { + maybeWriteNoticeForFKColTypeMismatch(b, col, newColType) + updateColumnType(b, oldColType, newColType) } // handleValidationOnlyColumnConversion is called when we don't need to rewrite // data, only validate the existing data is compatible with the type. func handleValidationOnlyColumnConversion( - b BuildCtx, t *tree.AlterTableAlterColumnType, oldColType, newColType *scpb.ColumnType, + b BuildCtx, + t *tree.AlterTableAlterColumnType, + col *scpb.Column, + oldColType, newColType *scpb.ColumnType, ) { - failIfExperimentalSettingNotSet(b, oldColType, newColType) + maybeWriteNoticeForFKColTypeMismatch(b, col, newColType) + updateColumnType(b, oldColType, newColType) - // TODO(spilchen): Implement the validation-only logic in #127516 - panic(scerrors.NotImplementedErrorf(t, - "alter type conversion that requires validation only is not supported in the declarative schema changer")) + // To validate, we add a transient check constraint. It casts the column to the + // new type and then back to the old type. If the cast back doesn't match the + // original value, the check fails. This constraint is temporary and doesn't + // need to persist beyond the ALTER operation. + expr, err := parser.ParseExpr(fmt.Sprintf("(CAST(CAST(%s AS %s) AS %s) = %s)", + t.Column.String(), newColType.Type.SQLString(), oldColType.Type.SQLString(), t.Column.String())) + if err != nil { + panic(err) + } + + // The constraint requires a backing index to use, which we will use the + // primary index. + indexID := getLatestPrimaryIndex(b, newColType.TableID).IndexID + + chk := scpb.CheckConstraint{ + TableID: newColType.TableID, + Expression: *b.WrapExpression(newColType.TableID, expr), + ConstraintID: b.NextTableConstraintID(newColType.TableID), + IndexIDForValidation: indexID, + ColumnIDs: []catid.ColumnID{newColType.ColumnID}, + } + b.AddTransient(&chk) // Adding it as transient ensures it doesn't survive past the ALTER. } // handleGeneralColumnConversion is called when we need to rewrite the data in order @@ -210,6 +236,14 @@ func handleGeneralColumnConversion( panic(scerrors.NotImplementedErrorf(t, "general alter type conversion not supported in the declarative schema changer")) } +func updateColumnType(b BuildCtx, oldColType, newColType *scpb.ColumnType) { + // Add the new type and remove the old type. The removal of the old type is a + // no-op in opgen. But we need the drop here so that we only have 1 public + // type for the column. + b.Drop(oldColType) + b.Add(newColType) +} + // failIfExperimentalSettingNotSet checks if the setting that allows altering // types is enabled. If the setting is not enabled, this function will panic. func failIfExperimentalSettingNotSet(b BuildCtx, oldColType, newColType *scpb.ColumnType) { @@ -226,3 +260,39 @@ func failIfExperimentalSettingNotSet(b BuildCtx, oldColType, newColType *scpb.Co pgcode.ExperimentalFeature)) } } + +// maybeWriteNoticeForFKColTypeMismatch will find any FK cols, and if the column +// that we are changing doesn't match the column in the referenced table, we +// will write a notice. This is a similar notice that is written when a table +// has a FK constraint added to it. +func maybeWriteNoticeForFKColTypeMismatch(b BuildCtx, col *scpb.Column, colType *scpb.ColumnType) { + writeNoticeHelper := func(columnIDs, referencedColumnIDs []catid.ColumnID, referencedTableID catid.DescID) { + // Find the corresponding column type in the referenced table + for i := range columnIDs { + // We only need to check a single column, then one we are altering. + if columnIDs[i] != col.ColumnID { + continue + } + refColType := mustRetrieveColumnTypeElem(b, referencedTableID, referencedColumnIDs[i]) + if !colType.Type.Identical(refColType.Type) { + colName := mustRetrieveColumnNameElem(b, col.TableID, col.ColumnID) + refColName := mustRetrieveColumnNameElem(b, referencedTableID, referencedColumnIDs[i]) + referencedTableNamespaceElem := mustRetrieveNamespaceElem(b, referencedTableID) + notice := pgnotice.Newf( + "type of foreign key column %q (%s) is not identical to referenced column %q.%q (%s)", + colName.Name, colType.Type.SQLString(), referencedTableNamespaceElem.Name, + refColName.Name, refColType.Type.SQLString()) + b.EvalCtx().ClientNoticeSender.BufferClientNotice(b, notice) + } + } + } + + walkColumnDependencies(b, col, "alter type of", "column", func(e scpb.Element, op, objType string) { + switch e := e.(type) { + case *scpb.ForeignKeyConstraint: + writeNoticeHelper(e.ColumnIDs, e.ReferencedColumnIDs, e.ReferencedTableID) + case *scpb.ForeignKeyConstraintUnvalidated: + writeNoticeHelper(e.ColumnIDs, e.ReferencedColumnIDs, e.ReferencedTableID) + } + }) +} diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/helpers.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/helpers.go index c303cd5af3ce..7b46aa7076ae 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/helpers.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/helpers.go @@ -1142,6 +1142,18 @@ func getPrimaryIndexChain(b BuildCtx, tableID catid.DescID) *primaryIndexChain { return NewPrimaryIndexChain(b, old, inter1, inter2, final) } +// getPrimaryIndexID finds and returns the PrimaryIndex. If there were changes +// to the primary index in this transaction, it returns pointer to the modified +// index. +func getLatestPrimaryIndex(b BuildCtx, tableID catid.DescID) *scpb.PrimaryIndex { + chain := getPrimaryIndexChain(b, tableID) + if chain.finalSpec.primary != nil { + return chain.finalSpec.primary + } else { + return chain.oldSpec.primary + } +} + // addASwapInIndexByCloningFromSource adds a primary index `in` that is going // to swap out `out` yet `in`'s columns are cloned from `source`. // diff --git a/pkg/sql/schemachanger/scbuild/testdata/alter_table_alter_column_type b/pkg/sql/schemachanger/scbuild/testdata/alter_table_alter_column_type index 6972b5bdb743..3addd7fff180 100644 --- a/pkg/sql/schemachanger/scbuild/testdata/alter_table_alter_column_type +++ b/pkg/sql/schemachanger/scbuild/testdata/alter_table_alter_column_type @@ -13,3 +13,17 @@ ALTER TABLE t ALTER COLUMN c2 SET DATA TYPE CHAR(100) {databaseId: 100, tableId: 104} - [[ColumnType:{DescID: 104, ColumnFamilyID: 0, ColumnID: 2, TypeName: CHAR(100)}, PUBLIC], ABSENT] {columnId: 2, elementCreationMetadata: {in231OrLater: true}, isNullable: true, tableId: 104, type: {family: StringFamily, oid: 1042, visibleType: 8, width: 100}, typeName: CHAR(100)} + +build +ALTER TABLE t ALTER COLUMN c2 SET DATA TYPE CHAR(5) +---- +- [[ColumnType:{DescID: 104, ColumnFamilyID: 0, ColumnID: 2, TypeName: CHAR(10)}, ABSENT], PUBLIC] + {columnId: 2, elementCreationMetadata: {in231OrLater: true}, isNullable: true, tableId: 104, type: {family: StringFamily, oid: 1042, visibleType: 8, width: 10}, typeName: CHAR(10)} +- [[IndexData:{DescID: 104, IndexID: 1}, PUBLIC], PUBLIC] + {indexId: 1, tableId: 104} +- [[TableData:{DescID: 104, ReferencedDescID: 100}, PUBLIC], PUBLIC] + {databaseId: 100, tableId: 104} +- [[ColumnType:{DescID: 104, ColumnFamilyID: 0, ColumnID: 2, TypeName: CHAR(5)}, PUBLIC], ABSENT] + {columnId: 2, elementCreationMetadata: {in231OrLater: true}, isNullable: true, tableId: 104, type: {family: StringFamily, oid: 1042, visibleType: 8, width: 5}, typeName: CHAR(5)} +- [[CheckConstraint:{DescID: 104, IndexID: 1, ConstraintID: 2, ReferencedColumnIDs: [2]}, TRANSIENT_ABSENT], ABSENT] + {columnIds: [2], constraintId: 2, expr: (CAST(CAST(c2 AS CHAR(5)) AS CHAR(10)) = c2), indexIdForValidation: 1, referencedColumnIds: [2], tableId: 104} diff --git a/pkg/sql/schemachanger/scexec/scmutationexec/column.go b/pkg/sql/schemachanger/scexec/scmutationexec/column.go index 2e1a9aff4a57..98e8830e2358 100644 --- a/pkg/sql/schemachanger/scexec/scmutationexec/column.go +++ b/pkg/sql/schemachanger/scexec/scmutationexec/column.go @@ -68,8 +68,16 @@ func (i *immediateVisitor) UpsertColumnType(ctx context.Context, op scop.UpsertC if catCol.HasType() { return i.updateExistingColumnType(ctx, op, col) } + return i.addNewColumnType(ctx, op, tbl, col) +} - // Else, we are adding a new column. +// addNewColumnType is called when adding a ColumnType for a new column. +func (i *immediateVisitor) addNewColumnType( + ctx context.Context, + op scop.UpsertColumnType, + tbl *tabledesc.Mutable, + col *descpb.ColumnDescriptor, +) error { col.Type = op.ColumnType.Type if op.ColumnType.ElementCreationMetadata.In_23_1OrLater { col.Nullable = true @@ -376,9 +384,9 @@ func (i *immediateVisitor) updateExistingColumnType( return err } switch kind { - case schemachange.ColumnConversionTrivial: - // For trivial conversions, we can just update the column type. This is - // allowed because there is no backfill for this type conversion. + case schemachange.ColumnConversionTrivial, schemachange.ColumnConversionValidate: + // Tihs type of update are ones that don't do a backfill. So, we can simply + // update the column type and be done. desc.Type = op.ColumnType.Type default: return errors.AssertionFailedf("unsupported column type change %v -> %v (%v)", diff --git a/pkg/sql/schemachanger/scplan/internal/opgen/opgen_check_constraint.go b/pkg/sql/schemachanger/scplan/internal/opgen/opgen_check_constraint.go index 96a702fb4da3..ff91f57ae114 100644 --- a/pkg/sql/schemachanger/scplan/internal/opgen/opgen_check_constraint.go +++ b/pkg/sql/schemachanger/scplan/internal/opgen/opgen_check_constraint.go @@ -81,6 +81,7 @@ func init() { }), ), ), + toTransientAbsentLikePublic(), toAbsent( scpb.Status_PUBLIC, to(scpb.Status_VALIDATED, diff --git a/pkg/sql/schemachanger/scplan/internal/rules/current/dep_alter_column_type.go b/pkg/sql/schemachanger/scplan/internal/rules/current/dep_alter_column_type.go index a7610da09187..b88e9f36daee 100644 --- a/pkg/sql/schemachanger/scplan/internal/rules/current/dep_alter_column_type.go +++ b/pkg/sql/schemachanger/scplan/internal/rules/current/dep_alter_column_type.go @@ -15,6 +15,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scpb" . "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scplan/internal/rules" "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scplan/internal/scgraph" + "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/screl" ) // This rule ensures that when changing the column type, that the old column @@ -36,4 +37,24 @@ func init() { } }, ) + + registerDepRule( + "column type is changed to public after doing validation of a transient check constraint", + scgraph.SameStagePrecedence, + "transient-check-constraint", "column-type", + func(from, to NodeVars) rel.Clauses { + colID := rel.Var("columnID") + return rel.Clauses{ + from.Type((*scpb.CheckConstraint)(nil)), + to.Type((*scpb.ColumnType)(nil)), + JoinOnDescID(from, to, "table-id"), + to.El.AttrEqVar(screl.ColumnID, colID), + from.ReferencedColumnIDsContains(colID), + from.TargetStatus(scpb.Transient), + to.TargetStatus(scpb.ToPublic), + from.CurrentStatus(scpb.Status_TRANSIENT_VALIDATED), + to.CurrentStatus(scpb.Status_PUBLIC), + } + }, + ) } diff --git a/pkg/sql/schemachanger/scplan/internal/rules/current/testdata/deprules b/pkg/sql/schemachanger/scplan/internal/rules/current/testdata/deprules index ac15d662dea4..aee7dfb6c839 100644 --- a/pkg/sql/schemachanger/scplan/internal/rules/current/testdata/deprules +++ b/pkg/sql/schemachanger/scplan/internal/rules/current/testdata/deprules @@ -21,6 +21,69 @@ deprules - descriptorIsDataNotBeingAdded-24.2($descID) - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_ABSENT->ABSENT' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_ABSENT + - $next-Node[CurrentStatus] = ABSENT + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_VALIDATED->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_VALIDATED + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_WRITE_ONLY->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_WRITE_ONLY + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) - name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: VALIDATED->ABSENT' from: prev-Node kind: PreviousTransactionPrecedence @@ -40,7 +103,7 @@ deprules - $descriptor-data-Node[CurrentStatus] = PUBLIC - $descriptor-data[DescID] = $descID - descriptorIsDataNotBeingAdded-24.2($descID) - - nodeNotExistsWithStatusIn_WRITE_ONLY($prev-Target) + - nodeNotExistsWithStatusIn_TRANSIENT_VALIDATED_WRITE_ONLY_TRANSIENT_WRITE_ONLY($prev-Target) - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) - name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: WRITE_ONLY->VALIDATED' @@ -127,6 +190,133 @@ deprules - descriptorIsDataNotBeingAdded-24.2($descID) - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: ABSENT->WRITE_ONLY' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = ABSENT + - $next-Node[CurrentStatus] = WRITE_ONLY + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: PUBLIC->TRANSIENT_VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = PUBLIC + - $next-Node[CurrentStatus] = TRANSIENT_VALIDATED + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: TRANSIENT_VALIDATED->TRANSIENT_ABSENT' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_VALIDATED + - $next-Node[CurrentStatus] = TRANSIENT_ABSENT + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - nodeNotExistsWithStatusIn_TRANSIENT_WRITE_ONLY($prev-Target) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: TRANSIENT_WRITE_ONLY->TRANSIENT_VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_WRITE_ONLY + - $next-Node[CurrentStatus] = TRANSIENT_VALIDATED + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: VALIDATED->PUBLIC' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = VALIDATED + - $next-Node[CurrentStatus] = PUBLIC + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: WRITE_ONLY->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = WRITE_ONLY + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) - name: 'Column transitions to ABSENT uphold 2-version invariant: DELETE_ONLY->ABSENT' from: prev-Node kind: PreviousTransactionPrecedence @@ -2425,6 +2615,22 @@ deprules - $column-type-Node[CurrentStatus] = ABSENT - joinTargetNode($dependent, $dependent-Target, $dependent-Node) - joinTargetNode($column-type, $column-type-Target, $column-type-Node) +- name: column type is changed to public after doing validation of a transient check constraint + from: transient-check-constraint-Node + kind: SameStagePrecedence + to: column-type-Node + query: + - $transient-check-constraint[Type] = '*scpb.CheckConstraint' + - $column-type[Type] = '*scpb.ColumnType' + - joinOnDescID($transient-check-constraint, $column-type, $table-id) + - $column-type[ColumnID] = $columnID + - $transient-check-constraint[ReferencedColumnIDs] CONTAINS $columnID + - $transient-check-constraint-Target[TargetStatus] = TRANSIENT_ABSENT + - $column-type-Target[TargetStatus] = PUBLIC + - $transient-check-constraint-Node[CurrentStatus] = TRANSIENT_VALIDATED + - $column-type-Node[CurrentStatus] = PUBLIC + - joinTargetNode($transient-check-constraint, $transient-check-constraint-Target, $transient-check-constraint-Node) + - joinTargetNode($column-type, $column-type-Target, $column-type-Node) - name: column type removed before column family from: column-type-Node kind: Precedence @@ -4191,6 +4397,69 @@ deprules - descriptorIsDataNotBeingAdded-24.2($descID) - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_ABSENT->ABSENT' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_ABSENT + - $next-Node[CurrentStatus] = ABSENT + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_VALIDATED->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_VALIDATED + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_WRITE_ONLY->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_WRITE_ONLY + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) - name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: VALIDATED->ABSENT' from: prev-Node kind: PreviousTransactionPrecedence @@ -4210,7 +4479,7 @@ deprules - $descriptor-data-Node[CurrentStatus] = PUBLIC - $descriptor-data[DescID] = $descID - descriptorIsDataNotBeingAdded-24.2($descID) - - nodeNotExistsWithStatusIn_WRITE_ONLY($prev-Target) + - nodeNotExistsWithStatusIn_TRANSIENT_VALIDATED_WRITE_ONLY_TRANSIENT_WRITE_ONLY($prev-Target) - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) - name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: WRITE_ONLY->VALIDATED' @@ -4297,6 +4566,133 @@ deprules - descriptorIsDataNotBeingAdded-24.2($descID) - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: ABSENT->WRITE_ONLY' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = ABSENT + - $next-Node[CurrentStatus] = WRITE_ONLY + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: PUBLIC->TRANSIENT_VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = PUBLIC + - $next-Node[CurrentStatus] = TRANSIENT_VALIDATED + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: TRANSIENT_VALIDATED->TRANSIENT_ABSENT' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_VALIDATED + - $next-Node[CurrentStatus] = TRANSIENT_ABSENT + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - nodeNotExistsWithStatusIn_TRANSIENT_WRITE_ONLY($prev-Target) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: TRANSIENT_WRITE_ONLY->TRANSIENT_VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_WRITE_ONLY + - $next-Node[CurrentStatus] = TRANSIENT_VALIDATED + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: VALIDATED->PUBLIC' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = VALIDATED + - $next-Node[CurrentStatus] = PUBLIC + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: WRITE_ONLY->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = WRITE_ONLY + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-24.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.2($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) - name: 'Column transitions to ABSENT uphold 2-version invariant: DELETE_ONLY->ABSENT' from: prev-Node kind: PreviousTransactionPrecedence @@ -6595,6 +6991,22 @@ deprules - $column-type-Node[CurrentStatus] = ABSENT - joinTargetNode($dependent, $dependent-Target, $dependent-Node) - joinTargetNode($column-type, $column-type-Target, $column-type-Node) +- name: column type is changed to public after doing validation of a transient check constraint + from: transient-check-constraint-Node + kind: SameStagePrecedence + to: column-type-Node + query: + - $transient-check-constraint[Type] = '*scpb.CheckConstraint' + - $column-type[Type] = '*scpb.ColumnType' + - joinOnDescID($transient-check-constraint, $column-type, $table-id) + - $column-type[ColumnID] = $columnID + - $transient-check-constraint[ReferencedColumnIDs] CONTAINS $columnID + - $transient-check-constraint-Target[TargetStatus] = TRANSIENT_ABSENT + - $column-type-Target[TargetStatus] = PUBLIC + - $transient-check-constraint-Node[CurrentStatus] = TRANSIENT_VALIDATED + - $column-type-Node[CurrentStatus] = PUBLIC + - joinTargetNode($transient-check-constraint, $transient-check-constraint-Target, $transient-check-constraint-Node) + - joinTargetNode($column-type, $column-type-Target, $column-type-Node) - name: column type removed before column family from: column-type-Node kind: Precedence diff --git a/pkg/sql/schemachanger/scplan/internal/rules/release_23_2/testdata/deprules b/pkg/sql/schemachanger/scplan/internal/rules/release_23_2/testdata/deprules index a84bab7a2301..336baae197f3 100644 --- a/pkg/sql/schemachanger/scplan/internal/rules/release_23_2/testdata/deprules +++ b/pkg/sql/schemachanger/scplan/internal/rules/release_23_2/testdata/deprules @@ -19,6 +19,63 @@ deprules - $descriptor-data[DescID] = $descID - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_ABSENT->ABSENT' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_ABSENT + - $next-Node[CurrentStatus] = ABSENT + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_VALIDATED->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_VALIDATED + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_WRITE_ONLY->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_WRITE_ONLY + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) - name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: VALIDATED->ABSENT' from: prev-Node kind: PreviousTransactionPrecedence @@ -36,7 +93,7 @@ deprules - $descriptor-data[Type] = '*scpb.TableData' - joinTarget($descriptor-data, $descriptor-data-Target) - $descriptor-data[DescID] = $descID - - nodeNotExistsWithStatusIn_WRITE_ONLY($prev-Target) + - nodeNotExistsWithStatusIn_TRANSIENT_VALIDATED_WRITE_ONLY_TRANSIENT_WRITE_ONLY($prev-Target) - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) - name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: WRITE_ONLY->VALIDATED' @@ -115,6 +172,121 @@ deprules - $descriptor-data[DescID] = $descID - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: ABSENT->WRITE_ONLY' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = ABSENT + - $next-Node[CurrentStatus] = WRITE_ONLY + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: PUBLIC->TRANSIENT_VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = PUBLIC + - $next-Node[CurrentStatus] = TRANSIENT_VALIDATED + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: TRANSIENT_VALIDATED->TRANSIENT_ABSENT' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_VALIDATED + - $next-Node[CurrentStatus] = TRANSIENT_ABSENT + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - nodeNotExistsWithStatusIn_TRANSIENT_WRITE_ONLY($prev-Target) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: TRANSIENT_WRITE_ONLY->TRANSIENT_VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_WRITE_ONLY + - $next-Node[CurrentStatus] = TRANSIENT_VALIDATED + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: VALIDATED->PUBLIC' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = VALIDATED + - $next-Node[CurrentStatus] = PUBLIC + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: WRITE_ONLY->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = WRITE_ONLY + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) - name: 'Column transitions to ABSENT uphold 2-version invariant: DELETE_ONLY->ABSENT' from: prev-Node kind: PreviousTransactionPrecedence @@ -3888,6 +4060,63 @@ deprules - $descriptor-data[DescID] = $descID - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_ABSENT->ABSENT' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_ABSENT + - $next-Node[CurrentStatus] = ABSENT + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_VALIDATED->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_VALIDATED + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_WRITE_ONLY->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_WRITE_ONLY + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) - name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: VALIDATED->ABSENT' from: prev-Node kind: PreviousTransactionPrecedence @@ -3905,7 +4134,7 @@ deprules - $descriptor-data[Type] = '*scpb.TableData' - joinTarget($descriptor-data, $descriptor-data-Target) - $descriptor-data[DescID] = $descID - - nodeNotExistsWithStatusIn_WRITE_ONLY($prev-Target) + - nodeNotExistsWithStatusIn_TRANSIENT_VALIDATED_WRITE_ONLY_TRANSIENT_WRITE_ONLY($prev-Target) - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) - name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: WRITE_ONLY->VALIDATED' @@ -3984,6 +4213,121 @@ deprules - $descriptor-data[DescID] = $descID - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: ABSENT->WRITE_ONLY' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = ABSENT + - $next-Node[CurrentStatus] = WRITE_ONLY + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: PUBLIC->TRANSIENT_VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = PUBLIC + - $next-Node[CurrentStatus] = TRANSIENT_VALIDATED + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: TRANSIENT_VALIDATED->TRANSIENT_ABSENT' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_VALIDATED + - $next-Node[CurrentStatus] = TRANSIENT_ABSENT + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - nodeNotExistsWithStatusIn_TRANSIENT_WRITE_ONLY($prev-Target) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: TRANSIENT_WRITE_ONLY->TRANSIENT_VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_WRITE_ONLY + - $next-Node[CurrentStatus] = TRANSIENT_VALIDATED + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: VALIDATED->PUBLIC' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = VALIDATED + - $next-Node[CurrentStatus] = PUBLIC + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: WRITE_ONLY->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = WRITE_ONLY + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-23.2($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTarget($descriptor-data, $descriptor-data-Target) + - $descriptor-data[DescID] = $descID + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) - name: 'Column transitions to ABSENT uphold 2-version invariant: DELETE_ONLY->ABSENT' from: prev-Node kind: PreviousTransactionPrecedence diff --git a/pkg/sql/schemachanger/scplan/internal/rules/release_24_1/testdata/deprules b/pkg/sql/schemachanger/scplan/internal/rules/release_24_1/testdata/deprules index 31e9cdb4eac1..6d3f062cdb74 100644 --- a/pkg/sql/schemachanger/scplan/internal/rules/release_24_1/testdata/deprules +++ b/pkg/sql/schemachanger/scplan/internal/rules/release_24_1/testdata/deprules @@ -21,6 +21,69 @@ deprules - descriptorIsDataNotBeingAdded-24.1($descID) - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_ABSENT->ABSENT' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_ABSENT + - $next-Node[CurrentStatus] = ABSENT + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_VALIDATED->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_VALIDATED + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_WRITE_ONLY->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_WRITE_ONLY + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) - name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: VALIDATED->ABSENT' from: prev-Node kind: PreviousTransactionPrecedence @@ -40,7 +103,7 @@ deprules - $descriptor-data-Node[CurrentStatus] = PUBLIC - $descriptor-data[DescID] = $descID - descriptorIsDataNotBeingAdded-24.1($descID) - - nodeNotExistsWithStatusIn_WRITE_ONLY($prev-Target) + - nodeNotExistsWithStatusIn_TRANSIENT_VALIDATED_WRITE_ONLY_TRANSIENT_WRITE_ONLY($prev-Target) - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) - name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: WRITE_ONLY->VALIDATED' @@ -127,6 +190,133 @@ deprules - descriptorIsDataNotBeingAdded-24.1($descID) - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: ABSENT->WRITE_ONLY' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = ABSENT + - $next-Node[CurrentStatus] = WRITE_ONLY + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: PUBLIC->TRANSIENT_VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = PUBLIC + - $next-Node[CurrentStatus] = TRANSIENT_VALIDATED + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: TRANSIENT_VALIDATED->TRANSIENT_ABSENT' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_VALIDATED + - $next-Node[CurrentStatus] = TRANSIENT_ABSENT + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - nodeNotExistsWithStatusIn_TRANSIENT_WRITE_ONLY($prev-Target) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: TRANSIENT_WRITE_ONLY->TRANSIENT_VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_WRITE_ONLY + - $next-Node[CurrentStatus] = TRANSIENT_VALIDATED + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: VALIDATED->PUBLIC' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = VALIDATED + - $next-Node[CurrentStatus] = PUBLIC + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: WRITE_ONLY->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = WRITE_ONLY + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) - name: 'Column transitions to ABSENT uphold 2-version invariant: DELETE_ONLY->ABSENT' from: prev-Node kind: PreviousTransactionPrecedence @@ -4177,6 +4367,69 @@ deprules - descriptorIsDataNotBeingAdded-24.1($descID) - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_ABSENT->ABSENT' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_ABSENT + - $next-Node[CurrentStatus] = ABSENT + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_VALIDATED->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_VALIDATED + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: TRANSIENT_WRITE_ONLY->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_WRITE_ONLY + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) - name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: VALIDATED->ABSENT' from: prev-Node kind: PreviousTransactionPrecedence @@ -4196,7 +4449,7 @@ deprules - $descriptor-data-Node[CurrentStatus] = PUBLIC - $descriptor-data[DescID] = $descID - descriptorIsDataNotBeingAdded-24.1($descID) - - nodeNotExistsWithStatusIn_WRITE_ONLY($prev-Target) + - nodeNotExistsWithStatusIn_TRANSIENT_VALIDATED_WRITE_ONLY_TRANSIENT_WRITE_ONLY($prev-Target) - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) - name: 'CheckConstraint transitions to ABSENT uphold 2-version invariant: WRITE_ONLY->VALIDATED' @@ -4283,6 +4536,133 @@ deprules - descriptorIsDataNotBeingAdded-24.1($descID) - joinTargetNode($prev, $prev-Target, $prev-Node) - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: ABSENT->WRITE_ONLY' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = ABSENT + - $next-Node[CurrentStatus] = WRITE_ONLY + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: PUBLIC->TRANSIENT_VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = PUBLIC + - $next-Node[CurrentStatus] = TRANSIENT_VALIDATED + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: TRANSIENT_VALIDATED->TRANSIENT_ABSENT' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_VALIDATED + - $next-Node[CurrentStatus] = TRANSIENT_ABSENT + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - nodeNotExistsWithStatusIn_TRANSIENT_WRITE_ONLY($prev-Target) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: TRANSIENT_WRITE_ONLY->TRANSIENT_VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = TRANSIENT_WRITE_ONLY + - $next-Node[CurrentStatus] = TRANSIENT_VALIDATED + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: VALIDATED->PUBLIC' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = VALIDATED + - $next-Node[CurrentStatus] = PUBLIC + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) +- name: 'CheckConstraint transitions to TRANSIENT_ABSENT uphold 2-version invariant: WRITE_ONLY->VALIDATED' + from: prev-Node + kind: PreviousTransactionPrecedence + to: next-Node + query: + - $prev[Type] = '*scpb.CheckConstraint' + - $next[Type] = '*scpb.CheckConstraint' + - $prev[DescID] = $descID + - $prev[Self] = $next + - $prev-Target[Self] = $next-Target + - $prev-Target[TargetStatus] = TRANSIENT_ABSENT + - $prev-Node[CurrentStatus] = WRITE_ONLY + - $next-Node[CurrentStatus] = VALIDATED + - descriptorIsNotBeingDropped-24.1($prev) + - $descriptor-data[Type] = '*scpb.TableData' + - joinTargetNode($descriptor-data, $descriptor-data-Target, $descriptor-data-Node) + - $descriptor-data-Node[CurrentStatus] = PUBLIC + - $descriptor-data[DescID] = $descID + - descriptorIsDataNotBeingAdded-24.1($descID) + - joinTargetNode($prev, $prev-Target, $prev-Node) + - joinTargetNode($next, $next-Target, $next-Node) - name: 'Column transitions to ABSENT uphold 2-version invariant: DELETE_ONLY->ABSENT' from: prev-Node kind: PreviousTransactionPrecedence diff --git a/pkg/sql/schemachanger/scplan/internal/scstage/build.go b/pkg/sql/schemachanger/scplan/internal/scstage/build.go index 48ff449e7a2e..7b30d900bef5 100644 --- a/pkg/sql/schemachanger/scplan/internal/scstage/build.go +++ b/pkg/sql/schemachanger/scplan/internal/scstage/build.go @@ -634,8 +634,13 @@ func (sb stageBuilder) hasUnmeetableOutboundDeps(n *screl.Node) (ret bool) { // there are other nodes preceding it in the op-edge path that need to be // scheduled first. if sb.hasDebugTrace() { - sb.debugTracef(" - %s targeting %s hasn't reached %s yet", - screl.ElementString(t.n.Element()), t.n.TargetStatus, t.e.To().CurrentStatus) + if t.e == nil { + sb.debugTracef(" %s targeting %s does not have outbound edge yet", + screl.ElementString(t.n.Element()), t.n.TargetStatus) + } else { + sb.debugTracef(" %s targeting %s hasn't reached %s yet", + screl.ElementString(t.n.Element()), t.n.TargetStatus, t.e.To().CurrentStatus) + } } return true } diff --git a/pkg/sql/schemachanger/sctest_generated_test.go b/pkg/sql/schemachanger/sctest_generated_test.go index 21aa4ab86219..6ac77ba1a821 100644 --- a/pkg/sql/schemachanger/sctest_generated_test.go +++ b/pkg/sql/schemachanger/sctest_generated_test.go @@ -181,6 +181,13 @@ func TestEndToEndSideEffects_alter_table_alter_column_type_trivial(t *testing.T) sctest.EndToEndSideEffects(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestEndToEndSideEffects_alter_table_alter_column_type_validation(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation" + sctest.EndToEndSideEffects(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestEndToEndSideEffects_alter_table_alter_primary_key_drop_rowid(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -678,6 +685,13 @@ func TestExecuteWithDMLInjection_alter_table_alter_column_type_trivial(t *testin sctest.ExecuteWithDMLInjection(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestExecuteWithDMLInjection_alter_table_alter_column_type_validation(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation" + sctest.ExecuteWithDMLInjection(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestExecuteWithDMLInjection_alter_table_alter_primary_key_drop_rowid(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1175,6 +1189,13 @@ func TestGenerateSchemaChangeCorpus_alter_table_alter_column_type_trivial(t *tes sctest.GenerateSchemaChangeCorpus(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestGenerateSchemaChangeCorpus_alter_table_alter_column_type_validation(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation" + sctest.GenerateSchemaChangeCorpus(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestGenerateSchemaChangeCorpus_alter_table_alter_primary_key_drop_rowid(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1672,6 +1693,13 @@ func TestPause_alter_table_alter_column_type_trivial(t *testing.T) { sctest.Pause(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestPause_alter_table_alter_column_type_validation(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation" + sctest.Pause(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestPause_alter_table_alter_primary_key_drop_rowid(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -2169,6 +2197,13 @@ func TestPauseMixedVersion_alter_table_alter_column_type_trivial(t *testing.T) { sctest.PauseMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestPauseMixedVersion_alter_table_alter_column_type_validation(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation" + sctest.PauseMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestPauseMixedVersion_alter_table_alter_primary_key_drop_rowid(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -2666,6 +2701,13 @@ func TestRollback_alter_table_alter_column_type_trivial(t *testing.T) { sctest.Rollback(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestRollback_alter_table_alter_column_type_validation(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation" + sctest.Rollback(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestRollback_alter_table_alter_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_alter_column_type_validation/alter_table_alter_column_type_validation.definition b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation.definition new file mode 100644 index 000000000000..4c1df0474b0d --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation.definition @@ -0,0 +1,25 @@ +setup +CREATE TABLE t (i INT PRIMARY KEY, j TEXT); +INSERT INTO t VALUES (1,NULL),(2,'FIT1'),(3,'FIT11'); +---- + +# Ensure we cannot insert new rows that don't fit in the new size of the column +stage-exec phase=PostCommitPhase stage=: +INSERT INTO t VALUES (10+$stageKey, 'too big for char(5)'); +---- +pq: failed to satisfy CHECK constraint .* + +# Ensure we can insert new rows that do fit in the new size of the column +stage-exec phase=PostCommitPhase stage=: +INSERT INTO t VALUES (20+$stageKey, 'rite'); +---- + +# One row is expected to be added after each stage. +stage-query phase=PostCommitPhase stage=: +SELECT count(*)=$successfulStageCount FROM t WHERE i > 3; +---- +true + +test +ALTER TABLE t ALTER COLUMN j SET DATA TYPE CHAR(5); +---- diff --git a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation.explain b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation.explain new file mode 100644 index 000000000000..a664d1dbc6f4 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation.explain @@ -0,0 +1,64 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j TEXT); +INSERT INTO t VALUES (1,NULL),(2,'FIT1'),(3,'FIT11'); + +/* test */ +EXPLAIN (DDL) ALTER TABLE t ALTER COLUMN j SET DATA TYPE CHAR(5); +---- +Schema change plan for ALTER TABLE ‹defaultdb›.‹public›.‹t› ALTER COLUMN ‹j› SET DATA TYPE CHAR(5); + ├── StatementPhase + │ └── Stage 1 of 1 in StatementPhase + │ ├── 1 element transitioning toward TRANSIENT_ABSENT + │ │ └── ABSENT → WRITE_ONLY CheckConstraint:{DescID: 104 (t), IndexID: 1 (t_pkey), ConstraintID: 2, ReferencedColumnIDs: [2]} + │ ├── 1 element transitioning toward ABSENT + │ │ └── PUBLIC → ABSENT ColumnType:{DescID: 104 (t), ColumnFamilyID: 0 (primary), ColumnID: 2 (j), TypeName: "STRING"} + │ └── 1 Mutation operation + │ └── AddCheckConstraint {"CheckExpr":"(CAST(CAST(j AS ...","ConstraintID":2,"TableID":104,"Validity":2} + ├── PreCommitPhase + │ ├── Stage 1 of 2 in PreCommitPhase + │ │ ├── 1 element transitioning toward TRANSIENT_ABSENT + │ │ │ └── WRITE_ONLY → ABSENT CheckConstraint:{DescID: 104 (t), IndexID: 1 (t_pkey), ConstraintID: 2, ReferencedColumnIDs: [2]} + │ │ ├── 1 element transitioning toward ABSENT + │ │ │ └── ABSENT → PUBLIC ColumnType:{DescID: 104 (t), ColumnFamilyID: 0 (primary), ColumnID: 2 (j), TypeName: "STRING"} + │ │ └── 1 Mutation operation + │ │ └── UndoAllInTxnImmediateMutationOpSideEffects + │ └── Stage 2 of 2 in PreCommitPhase + │ ├── 1 element transitioning toward TRANSIENT_ABSENT + │ │ └── ABSENT → WRITE_ONLY CheckConstraint:{DescID: 104 (t), IndexID: 1 (t_pkey), ConstraintID: 2, ReferencedColumnIDs: [2]} + │ └── 3 Mutation operations + │ ├── AddCheckConstraint {"CheckExpr":"(CAST(CAST(j AS ...","ConstraintID":2,"TableID":104,"Validity":2} + │ ├── SetJobStateOnDescriptor {"DescriptorID":104,"Initialize":true} + │ └── CreateSchemaChangerJob {"RunningStatus":"PostCommitPhase ..."} + ├── PostCommitPhase + │ └── Stage 1 of 1 in PostCommitPhase + │ ├── 1 element transitioning toward TRANSIENT_ABSENT + │ │ └── WRITE_ONLY → VALIDATED CheckConstraint:{DescID: 104 (t), IndexID: 1 (t_pkey), ConstraintID: 2, ReferencedColumnIDs: [2]} + │ └── 1 Validation operation + │ └── ValidateConstraint {"ConstraintID":2,"IndexIDForValidation":1,"TableID":104} + └── PostCommitNonRevertiblePhase + ├── Stage 1 of 3 in PostCommitNonRevertiblePhase + │ ├── 1 element transitioning toward TRANSIENT_ABSENT + │ │ └── VALIDATED → PUBLIC CheckConstraint:{DescID: 104 (t), IndexID: 1 (t_pkey), ConstraintID: 2, ReferencedColumnIDs: [2]} + │ ├── 1 element transitioning toward ABSENT + │ │ └── PUBLIC → ABSENT ColumnType:{DescID: 104 (t), ColumnFamilyID: 0 (primary), ColumnID: 2 (j), TypeName: "STRING"} + │ └── 3 Mutation operations + │ ├── MakeValidatedCheckConstraintPublic {"ConstraintID":2,"TableID":104} + │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"PostCommitNonRev..."} + ├── Stage 2 of 3 in PostCommitNonRevertiblePhase + │ ├── 1 element transitioning toward PUBLIC + │ │ └── ABSENT → PUBLIC ColumnType:{DescID: 104 (t), ColumnFamilyID: 0 (primary), ColumnID: 2 (j), TypeName: "CHAR(5)"} + │ ├── 1 element transitioning toward TRANSIENT_ABSENT + │ │ └── PUBLIC → TRANSIENT_VALIDATED CheckConstraint:{DescID: 104 (t), IndexID: 1 (t_pkey), ConstraintID: 2, ReferencedColumnIDs: [2]} + │ └── 4 Mutation operations + │ ├── MakePublicCheckConstraintValidated {"ConstraintID":2,"TableID":104} + │ ├── UpsertColumnType {"ColumnType":{"ColumnID":2,"IsNullable":true,"TableID":104}} + │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"PostCommitNonRev..."} + └── Stage 3 of 3 in PostCommitNonRevertiblePhase + ├── 1 element transitioning toward TRANSIENT_ABSENT + │ └── TRANSIENT_VALIDATED → TRANSIENT_ABSENT CheckConstraint:{DescID: 104 (t), IndexID: 1 (t_pkey), ConstraintID: 2, ReferencedColumnIDs: [2]} + └── 3 Mutation operations + ├── RemoveCheckConstraint {"ConstraintID":2,"TableID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":104} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation.explain_shape b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation.explain_shape new file mode 100644 index 000000000000..68dbe5f12afe --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation.explain_shape @@ -0,0 +1,11 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j TEXT); +INSERT INTO t VALUES (1,NULL),(2,'FIT1'),(3,'FIT11'); + +/* test */ +EXPLAIN (DDL, SHAPE) ALTER TABLE t ALTER COLUMN j SET DATA TYPE CHAR(5); +---- +Schema change plan for ALTER TABLE ‹defaultdb›.‹public›.‹t› ALTER COLUMN ‹j› SET DATA TYPE CHAR(5); + ├── execute 1 system table mutations transaction + ├── validate non-index-backed constraint t.[constraint 2] in relation t + └── execute 3 system table mutations transactions diff --git a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation.side_effects b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation.side_effects new file mode 100644 index 000000000000..71e54d0f2af2 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation.side_effects @@ -0,0 +1,313 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j TEXT); +INSERT INTO t VALUES (1,NULL),(2,'FIT1'),(3,'FIT11'); +---- +... ++object {100 101 t} -> 104 + +/* test */ +ALTER TABLE t ALTER COLUMN j SET DATA TYPE CHAR(5); +---- +begin transaction #1 +# begin StatementPhase +checking for feature: ALTER TABLE +increment telemetry for sql.schema.alter_table +increment telemetry for sql.schema.alter_table.alter_column_type +## StatementPhase stage 1 of 1 with 1 MutationType op +upsert descriptor #104 + table: + + checks: + + - columnIds: + + - 2 + + constraintId: 2 + + expr: (CAST(CAST(j AS CHAR(5)) AS STRING) = j) + + name: crdb_internal_constraint_2_name_placeholder + + validity: Validating + columns: + - id: 1 + ... + id: 104 + modificationTime: {} + + mutations: + + - constraint: + + check: + + columnIds: + + - 2 + + constraintId: 2 + + expr: (CAST(CAST(j AS CHAR(5)) AS STRING) = j) + + name: crdb_internal_constraint_2_name_placeholder + + validity: Validating + + foreignKey: {} + + name: crdb_internal_constraint_2_name_placeholder + + uniqueWithoutIndexConstraint: {} + + direction: ADD + + mutationId: 1 + + state: WRITE_ONLY + name: t + nextColumnId: 3 + - nextConstraintId: 2 + + nextConstraintId: 3 + nextFamilyId: 1 + nextIndexId: 2 + ... + time: {} + unexposedParentSchemaId: 101 + - version: "1" + + version: "2" +# end StatementPhase +# begin PreCommitPhase +## PreCommitPhase stage 1 of 2 with 1 MutationType op +undo all catalog changes within txn #1 +persist all catalog changes to storage +## PreCommitPhase stage 2 of 2 with 3 MutationType ops +upsert descriptor #104 + table: + + checks: + + - columnIds: + + - 2 + + constraintId: 2 + + expr: (CAST(CAST(j AS CHAR(5)) AS STRING) = j) + + name: crdb_internal_constraint_2_name_placeholder + + validity: Validating + columns: + - id: 1 + ... + createAsOfTime: + wallTime: "1640995200000000000" + + declarativeSchemaChangerState: + + authorization: + + userName: root + + currentStatuses: + + jobId: "1" + + nameMapping: + + columns: + + "1": i + + "2": j + + "4294967294": tableoid + + "4294967295": crdb_internal_mvcc_timestamp + + families: + + "0": primary + + id: 104 + + indexes: + + "1": t_pkey + + name: t + + relevantStatements: + + - statement: + + redactedStatement: ALTER TABLE ‹defaultdb›.‹public›.‹t› ALTER COLUMN ‹j› SET DATA TYPE CHAR(5) + + statement: ALTER TABLE t ALTER COLUMN j SET DATA TYPE CHAR(5) + + statementTag: ALTER TABLE + + revertible: true + + targetRanks: + + targets: + families: + - columnIds: + ... + id: 104 + modificationTime: {} + + mutations: + + - constraint: + + check: + + columnIds: + + - 2 + + constraintId: 2 + + expr: (CAST(CAST(j AS CHAR(5)) AS STRING) = j) + + name: crdb_internal_constraint_2_name_placeholder + + validity: Validating + + foreignKey: {} + + name: crdb_internal_constraint_2_name_placeholder + + uniqueWithoutIndexConstraint: {} + + direction: ADD + + mutationId: 1 + + state: WRITE_ONLY + name: t + nextColumnId: 3 + - nextConstraintId: 2 + + nextConstraintId: 3 + nextFamilyId: 1 + nextIndexId: 2 + ... + time: {} + unexposedParentSchemaId: 101 + - version: "1" + + version: "2" +persist all catalog changes to storage +create job #1 (non-cancelable: false): "ALTER TABLE defaultdb.public.t ALTER COLUMN j SET DATA TYPE CHAR(5)" + descriptor IDs: [104] +# end PreCommitPhase +commit transaction #1 +notified job registry to adopt jobs: [1] +# begin PostCommitPhase +begin transaction #2 +commit transaction #2 +begin transaction #3 +## PostCommitPhase stage 1 of 1 with 1 ValidationType op +validate CHECK constraint crdb_internal_constraint_2_name_placeholder in table #104 +commit transaction #3 +begin transaction #4 +## PostCommitNonRevertiblePhase stage 1 of 3 with 3 MutationType ops +upsert descriptor #104 + ... + expr: (CAST(CAST(j AS CHAR(5)) AS STRING) = j) + name: crdb_internal_constraint_2_name_placeholder + - validity: Validating + columns: + - id: 1 + ... + statement: ALTER TABLE t ALTER COLUMN j SET DATA TYPE CHAR(5) + statementTag: ALTER TABLE + - revertible: true + targetRanks: + targets: + ... + id: 104 + modificationTime: {} + - mutations: + - - constraint: + - check: + - columnIds: + - - 2 + - constraintId: 2 + - expr: (CAST(CAST(j AS CHAR(5)) AS STRING) = j) + - name: crdb_internal_constraint_2_name_placeholder + - validity: Validating + - foreignKey: {} + - name: crdb_internal_constraint_2_name_placeholder + - uniqueWithoutIndexConstraint: {} + - direction: ADD + - mutationId: 1 + - state: WRITE_ONLY + name: t + nextColumnId: 3 + ... + time: {} + unexposedParentSchemaId: 101 + - version: "2" + + version: "3" +persist all catalog changes to storage +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 #4 +begin transaction #5 +## PostCommitNonRevertiblePhase stage 2 of 3 with 4 MutationType ops +upsert descriptor #104 + ... + expr: (CAST(CAST(j AS CHAR(5)) AS STRING) = j) + name: crdb_internal_constraint_2_name_placeholder + + validity: Dropping + columns: + - id: 1 + ... + type: + family: StringFamily + - oid: 25 + + oid: 1042 + + visibleType: 8 + + width: 5 + createAsOfTime: + wallTime: "1640995200000000000" + ... + id: 104 + modificationTime: {} + + mutations: + + - constraint: + + check: + + columnIds: + + - 2 + + constraintId: 2 + + expr: (CAST(CAST(j AS CHAR(5)) AS STRING) = j) + + name: crdb_internal_constraint_2_name_placeholder + + validity: Dropping + + foreignKey: {} + + name: crdb_internal_constraint_2_name_placeholder + + uniqueWithoutIndexConstraint: {} + + direction: DROP + + mutationId: 1 + + state: WRITE_ONLY + name: t + nextColumnId: 3 + ... + time: {} + unexposedParentSchemaId: 101 + - version: "3" + + version: "4" +persist all catalog changes to storage +update progress of schema change job #1: "PostCommitNonRevertiblePhase stage 3 of 3 with 1 MutationType op pending" +commit transaction #5 +begin transaction #6 +## PostCommitNonRevertiblePhase stage 3 of 3 with 3 MutationType ops +upsert descriptor #104 + table: + - checks: + - - columnIds: + - - 2 + - constraintId: 2 + - expr: (CAST(CAST(j AS CHAR(5)) AS STRING) = j) + - name: crdb_internal_constraint_2_name_placeholder + - validity: Dropping + + checks: [] + columns: + - id: 1 + ... + createAsOfTime: + wallTime: "1640995200000000000" + - declarativeSchemaChangerState: + - authorization: + - userName: root + - currentStatuses: + - jobId: "1" + - nameMapping: + - columns: + - "1": i + - "2": j + - "4294967294": tableoid + - "4294967295": crdb_internal_mvcc_timestamp + - families: + - "0": primary + - id: 104 + - indexes: + - "1": t_pkey + - name: t + - relevantStatements: + - - statement: + - redactedStatement: ALTER TABLE ‹defaultdb›.‹public›.‹t› ALTER COLUMN ‹j› SET DATA TYPE CHAR(5) + - statement: ALTER TABLE t ALTER COLUMN j SET DATA TYPE CHAR(5) + - statementTag: ALTER TABLE + - targetRanks: + - targets: + families: + - columnIds: + ... + id: 104 + modificationTime: {} + - mutations: + - - constraint: + - check: + - columnIds: + - - 2 + - constraintId: 2 + - expr: (CAST(CAST(j AS CHAR(5)) AS STRING) = j) + - name: crdb_internal_constraint_2_name_placeholder + - validity: Dropping + - foreignKey: {} + - name: crdb_internal_constraint_2_name_placeholder + - uniqueWithoutIndexConstraint: {} + - direction: DROP + - mutationId: 1 + - state: WRITE_ONLY + + mutations: [] + name: t + nextColumnId: 3 + ... + time: {} + unexposedParentSchemaId: 101 + - version: "4" + + version: "5" +persist all catalog changes to storage +update progress of schema change job #1: "all stages completed" +set schema change job #1 to non-cancellable +updated schema change job #1 descriptor IDs to [] +write *eventpb.FinishSchemaChange to event log: + sc: + descriptorId: 104 +commit transaction #6 +# end PostCommitPhase diff --git a/pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation__rollback_1_of_1.explain b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation__rollback_1_of_1.explain new file mode 100644 index 000000000000..6a32a1198d82 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_column_type_validation/alter_table_alter_column_type_validation__rollback_1_of_1.explain @@ -0,0 +1,17 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j TEXT); +INSERT INTO t VALUES (1,NULL),(2,'FIT1'),(3,'FIT11'); + +/* test */ +ALTER TABLE t ALTER COLUMN j SET DATA TYPE CHAR(5); +EXPLAIN (DDL) rollback at post-commit stage 1 of 1; +---- +Schema change plan for rolling back ALTER TABLE ‹defaultdb›.public.‹t› ALTER COLUMN ‹j› SET DATA TYPE CHAR(5); + └── PostCommitNonRevertiblePhase + └── Stage 1 of 1 in PostCommitNonRevertiblePhase + ├── 1 element transitioning toward ABSENT + │ └── WRITE_ONLY → ABSENT CheckConstraint:{DescID: 104 (t), IndexID: 1 (t_pkey), ConstraintID: 2, ReferencedColumnIDs: [2]} + └── 3 Mutation operations + ├── RemoveCheckConstraint {"ConstraintID":2,"TableID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":104} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."}