From 77372a6bf30657d3f49c56b5c7978984fe90b5df Mon Sep 17 00:00:00 2001 From: Xiang Gu Date: Thu, 18 May 2023 11:30:41 -0500 Subject: [PATCH] schemachanger: Implement CREATE DATABASE This commit supports CREATE DATABASE in declarative schema changer. It falls back to legacy schema changer if the database is requested to be multi-region. Release note: None --- .../logictestccl/testdata/logic_test/as_of | 8 +- .../backup_base_generated_test.go | 84 +++ pkg/internal/team/TEAMS.yaml | 122 ++++ pkg/sql/create_database.go | 4 +- pkg/sql/logictest/testdata/logic_test/bytes | 7 +- .../schemachanger/scbuild/builder_state.go | 14 + pkg/sql/schemachanger/scbuild/dependencies.go | 13 +- pkg/sql/schemachanger/scbuild/event_log.go | 4 +- .../scbuild/internal/scbuildstmt/BUILD.bazel | 3 + .../internal/scbuildstmt/create_database.go | 321 ++++++++ .../internal/scbuildstmt/dependencies.go | 9 +- .../scbuild/internal/scbuildstmt/helpers.go | 24 + .../scbuild/internal/scbuildstmt/process.go | 5 + .../scbuild/testdata/create_database | 35 + .../scbuild/testdata/unimplemented_create | 4 - .../scdeps/sctestdeps/database_state.go | 3 - .../scdeps/sctestdeps/test_deps.go | 15 + .../scexec/scmutationexec/BUILD.bazel | 2 + .../scexec/scmutationexec/database.go | 39 + .../scexec/scmutationexec/references.go | 3 + .../scexec/scmutationexec/schema.go | 4 +- .../schemachanger/scop/immediate_mutation.go | 5 + .../immediate_mutation_visitor_generated.go | 6 + pkg/sql/schemachanger/scpb/elements.proto | 2 +- .../scplan/internal/opgen/opgen_database.go | 10 +- .../scplan/testdata/create_database | 294 ++++++++ .../schemachanger/sctest_generated_test.go | 126 ++++ .../create_database.definition | 3 + .../create_database/create_database.explain | 94 +++ .../create_database.explain_shape | 7 + .../create_database.side_effects | 120 +++ ...op_database_separate_statements.definition | 5 + ..._database_separate_statements.side_effects | 208 ++++++ ...arate_statements__statement_1_of_3.explain | 94 +++ ...statements__statement_1_of_3.explain_shape | 7 + ...arate_statements__statement_2_of_3.explain | 52 ++ ...statements__statement_2_of_3.explain_shape | 8 + ...arate_statements__statement_3_of_3.explain | 104 +++ ...statements__statement_3_of_3.explain_shape | 9 + ...te_database_separate_statements.definition | 9 + ..._database_separate_statements.side_effects | 690 ++++++++++++++++++ ...parate_statements__rollback_1_of_7.explain | 75 ++ ...parate_statements__rollback_2_of_7.explain | 79 ++ ...parate_statements__rollback_3_of_7.explain | 79 ++ ...parate_statements__rollback_4_of_7.explain | 79 ++ ...parate_statements__rollback_5_of_7.explain | 82 +++ ...parate_statements__rollback_6_of_7.explain | 82 +++ ...parate_statements__rollback_7_of_7.explain | 80 ++ ...arate_statements__statement_1_of_2.explain | 135 ++++ ...statements__statement_1_of_2.explain_shape | 17 + ...arate_statements__statement_2_of_2.explain | 208 ++++++ ...statements__statement_2_of_2.explain_shape | 18 + pkg/sql/sem/tree/stmt.go | 1 + 53 files changed, 3488 insertions(+), 23 deletions(-) create mode 100644 pkg/internal/team/TEAMS.yaml create mode 100644 pkg/sql/schemachanger/scbuild/internal/scbuildstmt/create_database.go create mode 100644 pkg/sql/schemachanger/scbuild/testdata/create_database create mode 100644 pkg/sql/schemachanger/scexec/scmutationexec/database.go create mode 100644 pkg/sql/schemachanger/scplan/testdata/create_database create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_database/create_database.definition create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_database/create_database.explain create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_database/create_database.explain_shape create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_database/create_database.side_effects create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements.definition create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements.side_effects create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_1_of_3.explain create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_1_of_3.explain_shape create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_2_of_3.explain create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_2_of_3.explain_shape create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_3_of_3.explain create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_3_of_3.explain_shape create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements.definition create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements.side_effects create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_1_of_7.explain create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_2_of_7.explain create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_3_of_7.explain create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_4_of_7.explain create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_5_of_7.explain create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_6_of_7.explain create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_7_of_7.explain create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__statement_1_of_2.explain create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__statement_1_of_2.explain_shape create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__statement_2_of_2.explain create mode 100644 pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__statement_2_of_2.explain_shape diff --git a/pkg/ccl/logictestccl/testdata/logic_test/as_of b/pkg/ccl/logictestccl/testdata/logic_test/as_of index 36c96a94e299..327bd692a9cb 100644 --- a/pkg/ccl/logictestccl/testdata/logic_test/as_of +++ b/pkg/ccl/logictestccl/testdata/logic_test/as_of @@ -46,7 +46,9 @@ SET DEFAULT_TRANSACTION_USE_FOLLOWER_READS TO TRUE statement error pgcode 3D000 pq: database "test" does not exist SELECT * FROM t -statement error pq: cannot execute CREATE DATABASE in a read-only transaction +# LSC and DSC would return slightly different error message when attempting to create a +# database as of system time follower_read_timestamp() soon after a node has started. +statement error pq: (cannot execute CREATE DATABASE in a read-only transaction|referenced descriptor ID 1: looking up ID 1: descriptor not found) CREATE DATABASE IF NOT EXISTS d2 statement error pgcode 3D000 pq: database "test" does not exist @@ -88,7 +90,9 @@ SET SESSION CHARACTERISTICS AS TRANSACTION AS OF SYSTEM TIME follower_read_times statement error pgcode 3D000 pq: database "test" does not exist SELECT * FROM t -statement error pq: cannot execute CREATE DATABASE in a read-only transaction +# LSC and DSC would return slightly different error message when attempting to create a +# database as of system time follower_read_timestamp() soon after a node has started. +statement error pq: (cannot execute CREATE DATABASE in a read-only transaction|referenced descriptor ID 1: looking up ID 1: descriptor not found) CREATE DATABASE IF NOT EXISTS d2 statement error pgcode 3D000 pq: database "test" does not exist diff --git a/pkg/ccl/schemachangerccl/backup_base_generated_test.go b/pkg/ccl/schemachangerccl/backup_base_generated_test.go index d9da9ab4bac1..f4c90c1c514d 100644 --- a/pkg/ccl/schemachangerccl/backup_base_generated_test.go +++ b/pkg/ccl/schemachangerccl/backup_base_generated_test.go @@ -179,6 +179,20 @@ func TestBackupRollbacks_base_alter_table_validate_constraint(t *testing.T) { sctest.BackupRollbacks(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupRollbacks_base_create_database(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database" + sctest.BackupRollbacks(t, path, sctest.SingleNodeTestClusterFactory{}) +} + +func TestBackupRollbacks_base_create_database_drop_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements" + sctest.BackupRollbacks(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupRollbacks_base_create_function(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -200,6 +214,13 @@ func TestBackupRollbacks_base_create_index(t *testing.T) { sctest.BackupRollbacks(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupRollbacks_base_create_index_create_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements" + sctest.BackupRollbacks(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupRollbacks_base_create_index_create_schema_separate_statements(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -508,6 +529,20 @@ func TestBackupRollbacksMixedVersion_base_alter_table_validate_constraint(t *tes sctest.BackupRollbacksMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupRollbacksMixedVersion_base_create_database(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database" + sctest.BackupRollbacksMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + +func TestBackupRollbacksMixedVersion_base_create_database_drop_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements" + sctest.BackupRollbacksMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupRollbacksMixedVersion_base_create_function(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -529,6 +564,13 @@ func TestBackupRollbacksMixedVersion_base_create_index(t *testing.T) { sctest.BackupRollbacksMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupRollbacksMixedVersion_base_create_index_create_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements" + sctest.BackupRollbacksMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupRollbacksMixedVersion_base_create_index_create_schema_separate_statements(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -837,6 +879,20 @@ func TestBackupSuccess_base_alter_table_validate_constraint(t *testing.T) { sctest.BackupSuccess(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupSuccess_base_create_database(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database" + sctest.BackupSuccess(t, path, sctest.SingleNodeTestClusterFactory{}) +} + +func TestBackupSuccess_base_create_database_drop_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements" + sctest.BackupSuccess(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupSuccess_base_create_function(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -858,6 +914,13 @@ func TestBackupSuccess_base_create_index(t *testing.T) { sctest.BackupSuccess(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupSuccess_base_create_index_create_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements" + sctest.BackupSuccess(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupSuccess_base_create_index_create_schema_separate_statements(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1166,6 +1229,20 @@ func TestBackupSuccessMixedVersion_base_alter_table_validate_constraint(t *testi sctest.BackupSuccessMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupSuccessMixedVersion_base_create_database(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database" + sctest.BackupSuccessMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + +func TestBackupSuccessMixedVersion_base_create_database_drop_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements" + sctest.BackupSuccessMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupSuccessMixedVersion_base_create_function(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1187,6 +1264,13 @@ func TestBackupSuccessMixedVersion_base_create_index(t *testing.T) { sctest.BackupSuccessMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestBackupSuccessMixedVersion_base_create_index_create_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements" + sctest.BackupSuccessMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestBackupSuccessMixedVersion_base_create_index_create_schema_separate_statements(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) diff --git a/pkg/internal/team/TEAMS.yaml b/pkg/internal/team/TEAMS.yaml new file mode 100644 index 000000000000..f3b0cd98bb93 --- /dev/null +++ b/pkg/internal/team/TEAMS.yaml @@ -0,0 +1,122 @@ +# This is a YAML file mapping team aliases from GitHub to +# metadata about the team. +# Expected structure is available in pkg/internal/team/team.go. + +# Finding triage_column_id: +# TriageColumnID is the column id of the project column the team uses to +# triage issues. To get it, open the project, click the "..." on top of +# the project column, and click "Copy column link". That link contains +# the ID as the `#column-` fragment. +# +# You can also use: +# https://github.com/cockroachlabs/github-find-triage-column-id using +# `go install github.com/cockroachlabs/github-find-triage-column-id@latest`. +# +# Then to retrieve triage_column_id from a repo-based project, run: +# github-get-column-id --repo "cockroach" --project "Bazel" --column "To do" +# Or retrieve the triage_column_id from a organization-based project, run: +# github-get-column-id --project "Spatial" --column "Backlog" + +cockroachdb/docs: + triage_column_id: 3971225 + aliases: + cockroachdb/docs-infra-prs: other +cockroachdb/sql-foundations: + aliases: + cockroachdb/sql-syntax-prs: other + cockroachdb/sqlproxy-prs: other + cockroachdb/sql-api-prs: other + triage_column_id: 19467489 + label: T-sql-foundations +cockroachdb/sql-queries: + aliases: + cockroachdb/sql-queries-prs: other + cockroachdb/sql-optimizer: other + cockroachdb/sql-opt-prs: other + # SQL Queries team uses GH projects v2, which doesn't have a REST API, so + # there is no triage column ID. + # See .github/workflows/add-issues-to-project.yml. + label: T-sql-queries +cockroachdb/cluster-observability: + triage_column_id: 12618343 + label: T-cluster-observability +cockroachdb/kv: + aliases: + cockroachdb/kv-triage: roachtest + cockroachdb/kv-prs: other + triage_column_id: 14242655 + label: T-kv +cockroachdb/replication: + aliases: + cockroachdb/repl-prs: other + label: T-kv-replication +cockroachdb/spatial: + triage_column_id: 9487269 + label: T-spatial +cockroachdb/dev-inf: + triage_column_id: 10210759 + label: T-dev-inf +cockroachdb/multiregion: + triage_column_id: 11926170 + label: T-multiregion +cockroachdb/storage: + aliases: + cockroachdb/admission-control: other + triage_column_id: 6668367 + label: T-storage +cockroachdb/test-eng: + triage_column_id: 14041337 + label: T-testeng +cockroachdb/test-eng-prs: + triage_column_id: 14041337 + label: T-testeng +cockroachdb/security: + label: T-cross-product-security +cockroachdb/prodsec: + label: T-cross-product-security +cockroachdb/disaster-recovery: + triage_column_id: 3097123 + label: T-disaster-recovery +cockroachdb/cdc: + aliases: + cockroachdb/cdc-prs: other + # CDC team uses GH projects v2, which doesn't have a REST API, so no triage column ID + # see .github/workflows/add-issues-to-project.yml + label: T-cdc +cockroachdb/server: + aliases: + cockroachdb/cli-prs: other + cockroachdb/server-prs: other + triage_column_id: 2521812 +cockroachdb/admin-ui: + aliases: + cockroachdb/admin-ui-prs: other + triage_column_id: 6598672 + label: T-observability-inf +cockroachdb/obs-inf-prs: + aliases: + cockroachdb/http-api-prs: other + triage_column_id: 14196277 + label: T-observability-inf +cockroachdb/multi-tenant: + # Multi-tenant team uses GH projects v2, which doesn't have a REST API, so no triage column ID + # see .github/workflows/add-issues-to-project.yml + label: T-multitenant +cockroachdb/jobs: + aliases: + cockroachdb/jobs-prs: other + # Jobs uses GH projects v2, which doesn't have a REST API, so no triage column ID + # see .github/workflows/add-issues-to-project.yml + label: T-jobs +cockroachdb/cloud-identity: + triage_column_id: 18588697 +cockroachdb/unowned: + aliases: + cockroachdb/rfc-prs: other + triage_column_id: 0 # TODO +cockroachdb/migrations: + label: T-migrations + triage_column_id: 18330909 +cockroachdb/release-eng: + label: T-release + triage_column_id: 9149730 diff --git a/pkg/sql/create_database.go b/pkg/sql/create_database.go index 0b6f2506e70c..06f8e6f54ed2 100644 --- a/pkg/sql/create_database.go +++ b/pkg/sql/create_database.go @@ -146,8 +146,8 @@ func (p *planner) CreateDatabase(ctx context.Context, n *tree.CreateDatabase) (p return &createDatabaseNode{n: n}, nil } -// CanCreateDatabase verifies that the current user has the CREATEDB -// role option. +// CanCreateDatabase returns nil if current user has CREATEDB system privilege +// or the equivalent, legacy role options. func (p *planner) CanCreateDatabase(ctx context.Context) error { hasCreateDB, err := p.HasGlobalPrivilegeOrRoleOption(ctx, privilege.CREATEDB) if err != nil { diff --git a/pkg/sql/logictest/testdata/logic_test/bytes b/pkg/sql/logictest/testdata/logic_test/bytes index acec525bd7e5..8aea9a789ab8 100644 --- a/pkg/sql/logictest/testdata/logic_test/bytes +++ b/pkg/sql/logictest/testdata/logic_test/bytes @@ -148,7 +148,12 @@ DROP TABLE t subtest Regression_4312 statement ok -PREPARE r1(bytes) AS SELECT descriptor::STRING FROM system.descriptor WHERE descriptor != $1 ORDER BY descriptor DESC LIMIT 1 +PREPARE r1(bytes) AS + SELECT descriptor::STRING + FROM system.descriptor + WHERE id = ( + SELECT id FROM system.namespace WHERE name = 'defaultdb' + ); query T EXECUTE r1('abc') diff --git a/pkg/sql/schemachanger/scbuild/builder_state.go b/pkg/sql/schemachanger/scbuild/builder_state.go index dee137696a49..4b5142cfd712 100644 --- a/pkg/sql/schemachanger/scbuild/builder_state.go +++ b/pkg/sql/schemachanger/scbuild/builder_state.go @@ -11,6 +11,7 @@ package scbuild import ( + "context" "sort" "github.com/cockroachdb/cockroach/pkg/keys" @@ -297,6 +298,7 @@ func (b *builderState) CheckPrivilege(e scpb.Element, privilege privilege.Kind) b.checkPrivilege(screl.GetDescID(e), privilege) } +// checkPrivilege checks if current user has privilege `priv` on descriptor with `id`. func (b *builderState) checkPrivilege(id catid.DescID, priv privilege.Kind) { b.ensureDescriptor(id) c := b.descCache[id] @@ -325,6 +327,13 @@ func (b *builderState) checkPrivilege(id catid.DescID, priv privilege.Kind) { } } +// HasGlobalPrivilegeOrRoleOption implements the scbuildstmt.PrivilegeChecker interface. +func (b *builderState) HasGlobalPrivilegeOrRoleOption( + ctx context.Context, privilege privilege.Kind, +) (bool, error) { + return b.auth.HasGlobalPrivilegeOrRoleOption(ctx, privilege) +} + // CurrentUserHasAdminOrIsMemberOf implements the scbuildstmt.PrivilegeChecker interface. func (b *builderState) CurrentUserHasAdminOrIsMemberOf(role username.SQLUsername) bool { if b.hasAdmin { @@ -345,6 +354,11 @@ func (b *builderState) CurrentUser() username.SQLUsername { return b.evalCtx.SessionData().User() } +// CheckRoleExists implements the scbuild.AuthorizationAccessor interface. +func (b *builderState) CheckRoleExists(ctx context.Context, role username.SQLUsername) error { + return b.auth.CheckRoleExists(ctx, role) +} + var _ scbuildstmt.TableHelpers = (*builderState)(nil) // NextTableColumnID implements the scbuildstmt.TableHelpers interface. diff --git a/pkg/sql/schemachanger/scbuild/dependencies.go b/pkg/sql/schemachanger/scbuild/dependencies.go index 6187385a5d6b..e17ab51c548f 100644 --- a/pkg/sql/schemachanger/scbuild/dependencies.go +++ b/pkg/sql/schemachanger/scbuild/dependencies.go @@ -178,14 +178,14 @@ type AuthorizationAccessor interface { ctx context.Context, privilegeObject privilege.Object, privilege privilege.Kind, ) error - // HasAdminRole verifies if a user has an admin role. + // HasAdminRole verifies if current user has an admin role. HasAdminRole(ctx context.Context) (bool, error) // HasOwnership returns true iff the role, or any role the role is a member // of, has ownership privilege of the desc. HasOwnership(ctx context.Context, privilegeObject privilege.Object) (bool, error) - // CheckPrivilegeForUser verifies that the user has `privilege` on `descriptor`. + // CheckPrivilegeForUser verifies that `user` has `privilege` on `descriptor`. CheckPrivilegeForUser( ctx context.Context, privilegeObject privilege.Object, privilege privilege.Kind, user username.SQLUsername, ) error @@ -194,11 +194,18 @@ type AuthorizationAccessor interface { // and indirect) and returns a map of "role" -> "isAdmin". MemberOfWithAdminOption(ctx context.Context, member username.SQLUsername) (map[username.SQLUsername]bool, error) - // HasPrivilege checks if the user has `privilege` on `descriptor`. + // HasPrivilege checks if the `user` has `privilege` on `privilegeObject`. HasPrivilege(ctx context.Context, privilegeObject privilege.Object, privilege privilege.Kind, user username.SQLUsername) (bool, error) // HasAnyPrivilege returns true if user has any privileges at all. HasAnyPrivilege(ctx context.Context, privilegeObject privilege.Object) (bool, error) + + // HasGlobalPrivilegeOrRoleOption returns a bool representing whether the current user + // has a global privilege or the corresponding legacy role option. + HasGlobalPrivilegeOrRoleOption(ctx context.Context, privilege privilege.Kind) (bool, error) + + // CheckRoleExists returns nil if `role` exists. + CheckRoleExists(ctx context.Context, role username.SQLUsername) error } // AstFormatter provides interfaces for formatting AST nodes. diff --git a/pkg/sql/schemachanger/scbuild/event_log.go b/pkg/sql/schemachanger/scbuild/event_log.go index db5995f01837..2a5f42bb3cd5 100644 --- a/pkg/sql/schemachanger/scbuild/event_log.go +++ b/pkg/sql/schemachanger/scbuild/event_log.go @@ -284,7 +284,9 @@ func (pb payloadBuilder) build(b buildCtx) logpb.EventPayload { switch e := pb.Element().(type) { case *scpb.Database: if pb.TargetStatus == scpb.Status_PUBLIC { - return nil + return &eventpb.CreateDatabase{ + DatabaseName: fullyQualifiedName(b, e), + } } else { return &eventpb.DropDatabase{ DatabaseName: fullyQualifiedName(b, e), diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/BUILD.bazel b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/BUILD.bazel index 30eb27fb2a1e..6e9db3e27da7 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/BUILD.bazel +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/BUILD.bazel @@ -12,6 +12,7 @@ go_library( "alter_table_drop_constraint.go", "alter_table_validate_constraint.go", "comment_on.go", + "create_database.go", "create_function.go", "create_index.go", "create_schema.go", @@ -69,6 +70,7 @@ go_library( "//pkg/sql/sem/volatility", "//pkg/sql/sessiondata", "//pkg/sql/sessiondatapb", + "//pkg/sql/sqlclustersettings", "//pkg/sql/sqlerrors", "//pkg/sql/sqltelemetry", "//pkg/sql/storageparam", @@ -77,6 +79,7 @@ go_library( "//pkg/util/errorutil/unimplemented", "//pkg/util/protoutil", "@com_github_cockroachdb_errors//:errors", + "@com_github_cockroachdb_redact//:redact", "@com_github_lib_pq//oid", ], ) diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/create_database.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/create_database.go new file mode 100644 index 000000000000..db32a41b1bfc --- /dev/null +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/create_database.go @@ -0,0 +1,321 @@ +// Copyright 2023 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package scbuildstmt + +import ( + "strings" + + "github.com/cockroachdb/cockroach/pkg/keys" + "github.com/cockroachdb/cockroach/pkg/security/username" + "github.com/cockroachdb/cockroach/pkg/sql/catalog/catpb" + "github.com/cockroachdb/cockroach/pkg/sql/decodeusername" + "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" + "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" + "github.com/cockroachdb/cockroach/pkg/sql/privilege" + "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scerrors" + "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scpb" + "github.com/cockroachdb/cockroach/pkg/sql/sem/catconstants" + "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" + "github.com/cockroachdb/cockroach/pkg/sql/sqlclustersettings" + "github.com/cockroachdb/cockroach/pkg/sql/sqlerrors" + "github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented" + "github.com/cockroachdb/errors" +) + +func CreateDatabase(b BuildCtx, n *tree.CreateDatabase) { + // TODO (xiang): Remove the fallback cases. + fallBackCreateDatabaseIfMultiRegion(b, n) + + // 1. Run a bunch of pre-checks. + createDatabasePreChecks(b, n) + b.IncrementSchemaChangeCreateCounter("database") + + // 2. Ensure database name is not already in use. + dbName := string(n.Name) + if databaseExists(b, n.Name) { + if n.IfNotExists { + return + } + panic(sqlerrors.NewDatabaseAlreadyExistsError(dbName)) + } + + // 3. Ensure current user can create a database with possibly a + // different user as the database's owner. + owner := getOwnerOfDB(b, n) + if err := checkCreateDatabaseCanAlterToOwner(b, n, owner); err != nil { + panic(err) + } + + // 4. Construct and add all relevant elements, including the database, + // its public schema, and others. + dbElem, _ := addCreateDatabaseElements(b, dbName, owner) + b.LogEventForExistingTarget(dbElem) +} + +func addCreateDatabaseElements( + b BuildCtx, dbName string, dbOwner username.SQLUsername, +) (*scpb.Database, *scpb.Schema) { + databaseID := b.GenerateUniqueDescID() + publicSchemaID := b.GenerateUniqueDescID() + + // Add database related elements. + dbElem := &scpb.Database{DatabaseID: databaseID} + b.Add(dbElem) + b.Add(&scpb.Namespace{ + DatabaseID: 0, + SchemaID: 0, + DescriptorID: databaseID, + Name: dbName, + }) + b.Add(&scpb.DatabaseData{DatabaseID: databaseID}) + b.Add(&scpb.Owner{ + DescriptorID: databaseID, + Owner: dbOwner.Normalized(), + }) + for _, up := range catpb.NewBaseDatabasePrivilegeDescriptor(dbOwner).Users { + b.Add(&scpb.UserPrivileges{ + DescriptorID: databaseID, + UserName: up.User().Normalized(), + Privileges: up.Privileges, + WithGrantOption: up.WithGrantOption, + }) + } + + // Add public schema related elements. + scElem := &scpb.Schema{ + SchemaID: publicSchemaID, + IsPublic: true, + } + b.Add(scElem) + b.Add(&scpb.Namespace{ + DatabaseID: databaseID, + SchemaID: 0, + DescriptorID: publicSchemaID, + Name: catconstants.PublicSchemaName, + }) + b.Add(&scpb.SchemaParent{ + SchemaID: publicSchemaID, + ParentDatabaseID: databaseID, + }) + b.Add(&scpb.Owner{ + DescriptorID: publicSchemaID, + Owner: username.AdminRoleName().Normalized(), + }) + includeCreatePriv := sqlclustersettings.PublicSchemaCreatePrivilegeEnabled.Get(&b.ClusterSettings().SV) + for _, up := range catpb.NewPublicSchemaPrivilegeDescriptor(includeCreatePriv).Users { + b.Add(&scpb.UserPrivileges{ + DescriptorID: publicSchemaID, + UserName: up.User().Normalized(), + Privileges: up.Privileges, + WithGrantOption: up.WithGrantOption, + }) + } + + return dbElem, scElem +} + +// checkCreateDatabaseCanAlterToOwner ensures that current user can alter the ownership +// of the to-be-created database `n` to `newOwner`. +// It can if +// - current user is a super user, or +// - current user is a direct or indirect member of the new owning role. +func checkCreateDatabaseCanAlterToOwner( + b BuildCtx, n *tree.CreateDatabase, newOwner username.SQLUsername, +) error { + // Ensure `newOwner` exists. + err := b.CheckRoleExists(b, newOwner) + if err != nil { + return err + } + // Ensure current user is either an admin or a member of new owing role. + if !b.CurrentUserHasAdminOrIsMemberOf(newOwner) { + return pgerror.Newf(pgcode.InsufficientPrivilege, "must be member of role %q", newOwner) + } + return nil +} + +// fallBackCreateDatabaseIfMultiRegion falls back if +// - it's explicitly requested to be multi-region, or +// - it has a non-empty default primary region, or +// - the system database is multi-region, and thus it will need to inherit +// that multi-region configuration. +func fallBackCreateDatabaseIfMultiRegion(b BuildCtx, n *tree.CreateDatabase) { + if len(n.Regions) > 0 || n.PrimaryRegion != "" || n.SecondaryRegion != "" || + n.SurvivalGoal != tree.SurvivalGoalDefault || n.SuperRegion.Name != "" { + panic(scerrors.NotImplementedError(n)) + } + defaultPrimaryRegion := sqlclustersettings.DefaultPrimaryRegion.Get(&b.ClusterSettings().SV) + if defaultPrimaryRegion != "" { + panic(scerrors.NotImplementedError(n)) + } + _, _, elem := scpb.FindDatabaseRegionConfig(b.QueryByID(keys.SystemDatabaseID)) + if elem != nil { + panic(scerrors.NotImplementedError(n)) + } +} + +// createDatabasePreChecks includes a bunch of quick pre-checks. +// It panics if any checks fails. +// The logics are copied from legacy schema changer. +func createDatabasePreChecks(b BuildCtx, n *tree.CreateDatabase) { + if n.Name == "" { + panic(sqlerrors.ErrEmptyDatabaseName) + } + + if tmpl := n.Template; tmpl != "" { + // See https://www.postgresql.org/docs/current/static/manage-ag-templatedbs.html + if !strings.EqualFold(tmpl, "template0") { + panic(unimplemented.NewWithIssuef(10151, + "unsupported template: %s", tmpl)) + } + } + + if enc := n.Encoding; enc != "" { + // We only support UTF8 (and aliases for UTF8). + if !(strings.EqualFold(enc, "UTF8") || + strings.EqualFold(enc, "UTF-8") || + strings.EqualFold(enc, "UNICODE")) { + panic(unimplemented.NewWithIssueDetailf(35882, "create.db.encoding", + "unsupported encoding: %s", enc)) + } + } + + if col := n.Collate; col != "" { + // We only support C and C.UTF-8. + if col != "C" && col != "C.UTF-8" { + panic(unimplemented.NewWithIssueDetailf(16618, "create.db.collation", + "unsupported collation: %s", col)) + } + } + + if ctype := n.CType; ctype != "" { + // We only support C and C.UTF-8. + if ctype != "C" && ctype != "C.UTF-8" { + panic(unimplemented.NewWithIssueDetailf(35882, "create.db.classification", + "unsupported character classification: %s", ctype)) + } + } + + if n.ConnectionLimit != -1 { + panic(unimplemented.NewWithIssueDetailf( + 54241, + "create.db.connection_limit", + "only connection limit -1 is supported, got: %d", + n.ConnectionLimit, + )) + } + + if n.SurvivalGoal != tree.SurvivalGoalDefault && + n.PrimaryRegion == tree.PrimaryRegionNotSpecifiedName { + panic(pgerror.New( + pgcode.InvalidDatabaseDefinition, + "PRIMARY REGION must be specified when using SURVIVE", + )) + } + + if n.Placement != tree.DataPlacementUnspecified { + if !b.EvalCtx().SessionData().PlacementEnabled { + panic(errors.WithHint(pgerror.New( + pgcode.ExperimentalFeature, + "PLACEMENT requires that the session setting enable_multiregion_placement_policy "+ + "is enabled", + ), + "to use PLACEMENT, enable the session setting with SET"+ + " enable_multiregion_placement_policy = true or enable the cluster setting"+ + " sql.defaults.multiregion_placement_policy.enabled", + )) + } + + if n.PrimaryRegion == tree.PrimaryRegionNotSpecifiedName { + panic(pgerror.New( + pgcode.InvalidDatabaseDefinition, + "PRIMARY REGION must be specified when using PLACEMENT", + )) + } + + if n.Placement == tree.DataPlacementRestricted && + n.SurvivalGoal == tree.SurvivalGoalRegionFailure { + panic(pgerror.New( + pgcode.InvalidDatabaseDefinition, + "PLACEMENT RESTRICTED can only be used with SURVIVE ZONE FAILURE", + )) + } + } + + if err := canCreateDatabase(b); err != nil { + panic(err) + } + + if n.PrimaryRegion == tree.PrimaryRegionNotSpecifiedName && n.SecondaryRegion != tree.SecondaryRegionNotSpecifiedName { + panic(pgerror.New( + pgcode.InvalidDatabaseDefinition, + "PRIMARY REGION must be specified when using SECONDARY REGION", + )) + } + + if n.PrimaryRegion != tree.PrimaryRegionNotSpecifiedName && n.SecondaryRegion == n.PrimaryRegion { + panic(pgerror.New( + pgcode.InvalidDatabaseDefinition, + "SECONDARY REGION can not be the same as the PRIMARY REGION", + )) + } + + // Disallow CREATEs for system tenant. + if err := shouldRestrictAccessToSystemInterface(b, + "DDL execution", /* operation */ + "running the DDL", /* alternate action */ + ); err != nil { + panic(err) + } +} + +// canCreateDatabase returns nil if current user has CREATEDB system privilege +// or the equivalent, legacy role options. +func canCreateDatabase(b BuildCtx) error { + hasCreateDB, err := b.HasGlobalPrivilegeOrRoleOption(b, privilege.CREATEDB) + if err != nil { + return err + } + if !hasCreateDB { + return pgerror.New( + pgcode.InsufficientPrivilege, + "permission denied to create database", + ) + } + return nil +} + +// databaseExists returns true if `dbName` has already been used by some database. +func databaseExists(b BuildCtx, dbName tree.Name) bool { + dbElem := b.ResolveDatabase(dbName, ResolveParams{ + IsExistenceOptional: true, + RequiredPrivilege: privilege.CONNECT, + RequireOwnership: false, + WithOffline: true, /* We search schema with name `schema`, including offline ones. */ + }) + return dbElem != nil +} + +// getOwnerOfDB either uses current user as owner of the to-be-created database, +// or the one specified in `n`. +func getOwnerOfDB(b BuildCtx, n *tree.CreateDatabase) username.SQLUsername { + var err error + owner := b.SessionData().User() + if !n.Owner.Undefined() { + owner, err = decodeusername.FromRoleSpec( + b.SessionData(), username.PurposeValidation, n.Owner, + ) + if err != nil { + panic(err) + } + } + return owner +} diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/dependencies.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/dependencies.go index fb09c2e3f0fb..85ccf7076c50 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/dependencies.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/dependencies.go @@ -216,12 +216,19 @@ type PrivilegeChecker interface { // privilege for the element. CheckPrivilege(e scpb.Element, privilege privilege.Kind) + // HasGlobalPrivilegeOrRoleOption returns a bool representing whether the current user + // has a global privilege or the corresponding legacy role option. + HasGlobalPrivilegeOrRoleOption(ctx context.Context, privilege privilege.Kind) (bool, error) + // CurrentUserHasAdminOrIsMemberOf returns true iff the current user is (1) // an admin or (2) has membership in the specified role. - CurrentUserHasAdminOrIsMemberOf(member username.SQLUsername) bool + CurrentUserHasAdminOrIsMemberOf(role username.SQLUsername) bool // CurrentUser returns the user of current session. CurrentUser() username.SQLUsername + + // CheckRoleExists returns nil if `role` exists. + CheckRoleExists(ctx context.Context, role username.SQLUsername) error } // TableHelpers has methods useful for creating new table elements. diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/helpers.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/helpers.go index 0133dc4489ea..8d20b591d810 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/helpers.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/helpers.go @@ -26,9 +26,11 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/screl" "github.com/cockroachdb/cockroach/pkg/sql/sem/catid" "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" + "github.com/cockroachdb/cockroach/pkg/sql/sqlclustersettings" "github.com/cockroachdb/cockroach/pkg/sql/sqlerrors" "github.com/cockroachdb/cockroach/pkg/util/protoutil" "github.com/cockroachdb/errors" + "github.com/cockroachdb/redact" ) func qualifiedName(b BuildCtx, id catid.DescID) string { @@ -1575,3 +1577,25 @@ func getInflatedPrimaryIndexChain(b BuildCtx, tableID catid.DescID) (chain *prim chain.inflate(b) return chain } + +// shouldRestrictAccessToSystemInterface decides whether to restrict +// access to certain SQL features from the system tenant/interface. +// This restriction exists to prevent UX surprise. See the docstring +// on the RestrictAccessToSystemInterface cluster setting for details. +// +// It is copied from legacy schema changer. +func shouldRestrictAccessToSystemInterface( + b BuildCtx, operation, alternateAction redact.RedactableString, +) error { + if b.Codec().ForSystemTenant() && + !b.SessionData().Internal && // We only restrict access for external SQL sessions. + sqlclustersettings.RestrictAccessToSystemInterface.Get(&b.ClusterSettings().SV) { + return errors.WithHintf( + pgerror.Newf(pgcode.InsufficientPrivilege, "blocked %s from the system interface", operation), + "Access blocked via %s to prevent likely user errors.\n"+ + "Try %s from a virtual cluster instead.", + sqlclustersettings.RestrictAccessToSystemInterface.Name(), + alternateAction) + } + return nil +} diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/process.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/process.go index f8793519f8a3..a1841a5a629e 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/process.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/process.go @@ -66,6 +66,7 @@ var supportedStatements = map[reflect.Type]supportedStatement{ reflect.TypeOf((*tree.CreateRoutine)(nil)): {fn: CreateFunction, statementTags: []string{tree.CreateFunctionTag, tree.CreateProcedureTag}, on: true, checks: nil}, reflect.TypeOf((*tree.CreateSchema)(nil)): {fn: CreateSchema, statementTags: []string{tree.CreateSchemaTag}, on: false, checks: isV232Active}, reflect.TypeOf((*tree.CreateSequence)(nil)): {fn: CreateSequence, statementTags: []string{tree.CreateSequenceTag}, on: false, checks: isV232Active}, + reflect.TypeOf((*tree.CreateDatabase)(nil)): {fn: CreateDatabase, statementTags: []string{tree.CreateDatabaseTag}, on: true, checks: isV241Active}, } // supportedStatementTags tracks statement tags which are implemented @@ -208,3 +209,7 @@ func getDeclarativeSchemaChangerModeForStmt( var isV232Active = func(_ tree.NodeFormatter, _ sessiondatapb.NewSchemaChangerMode, activeVersion clusterversion.ClusterVersion) bool { return activeVersion.IsActive(clusterversion.V23_2) } + +var isV241Active = func(_ tree.NodeFormatter, _ sessiondatapb.NewSchemaChangerMode, activeVersion clusterversion.ClusterVersion) bool { + return activeVersion.IsActive(clusterversion.V24_1) +} diff --git a/pkg/sql/schemachanger/scbuild/testdata/create_database b/pkg/sql/schemachanger/scbuild/testdata/create_database new file mode 100644 index 000000000000..d05169129988 --- /dev/null +++ b/pkg/sql/schemachanger/scbuild/testdata/create_database @@ -0,0 +1,35 @@ +setup +CREATE USER roacher; +---- + +build +CREATE DATABASE db OWNER roacher; +---- +- [[Database:{DescID: 104}, PUBLIC], ABSENT] + {databaseId: 104} +- [[Namespace:{DescID: 104, Name: db, ReferencedDescID: 0}, PUBLIC], ABSENT] + {descriptorId: 104, name: db} +- [[DatabaseData:{DescID: 104}, PUBLIC], ABSENT] + {databaseId: 104} +- [[Owner:{DescID: 104}, PUBLIC], ABSENT] + {descriptorId: 104, owner: roacher} +- [[UserPrivileges:{DescID: 104, Name: admin}, PUBLIC], ABSENT] + {descriptorId: 104, privileges: "2", userName: admin, withGrantOption: "2"} +- [[UserPrivileges:{DescID: 104, Name: public}, PUBLIC], ABSENT] + {descriptorId: 104, privileges: "2048", userName: public} +- [[UserPrivileges:{DescID: 104, Name: root}, PUBLIC], ABSENT] + {descriptorId: 104, privileges: "2", userName: root, withGrantOption: "2"} +- [[Schema:{DescID: 105}, PUBLIC], ABSENT] + {isPublic: true, schemaId: 105} +- [[Namespace:{DescID: 105, Name: public, ReferencedDescID: 104}, PUBLIC], ABSENT] + {databaseId: 104, descriptorId: 105, name: public} +- [[SchemaParent:{DescID: 105, ReferencedDescID: 104}, PUBLIC], ABSENT] + {parentDatabaseId: 104, schemaId: 105} +- [[Owner:{DescID: 105}, PUBLIC], ABSENT] + {descriptorId: 105, owner: admin} +- [[UserPrivileges:{DescID: 105, Name: admin}, PUBLIC], ABSENT] + {descriptorId: 105, privileges: "2", userName: admin, withGrantOption: "2"} +- [[UserPrivileges:{DescID: 105, Name: public}, PUBLIC], ABSENT] + {descriptorId: 105, privileges: "516", userName: public} +- [[UserPrivileges:{DescID: 105, Name: root}, PUBLIC], ABSENT] + {descriptorId: 105, privileges: "2", userName: root, withGrantOption: "2"} diff --git a/pkg/sql/schemachanger/scbuild/testdata/unimplemented_create b/pkg/sql/schemachanger/scbuild/testdata/unimplemented_create index 4d48725adee2..1c11304aa9dd 100644 --- a/pkg/sql/schemachanger/scbuild/testdata/unimplemented_create +++ b/pkg/sql/schemachanger/scbuild/testdata/unimplemented_create @@ -2,10 +2,6 @@ setup CREATE USER roacher ---- -unimplemented -CREATE DATABASE db; ----- - unimplemented CREATE DATABASE db PRIMARY REGION "us-east1" REGIONS "us-east1", "us-central1", "us-west1" SURVIVE REGION FAILURE; ---- diff --git a/pkg/sql/schemachanger/scdeps/sctestdeps/database_state.go b/pkg/sql/schemachanger/scdeps/sctestdeps/database_state.go index d27a91730499..c38094bfd9b5 100644 --- a/pkg/sql/schemachanger/scdeps/sctestdeps/database_state.go +++ b/pkg/sql/schemachanger/scdeps/sctestdeps/database_state.go @@ -74,9 +74,6 @@ ORDER BY id`) t.Fatal(err) } desc := b.BuildCreatedMutable() - if desc.GetID() == keys.SystemDatabaseID || desc.GetParentID() == keys.SystemDatabaseID { - continue - } // Redact time-dependent fields. switch t := desc.(type) { diff --git a/pkg/sql/schemachanger/scdeps/sctestdeps/test_deps.go b/pkg/sql/schemachanger/scdeps/sctestdeps/test_deps.go index 7cd6febf8fd6..83be03bd143a 100644 --- a/pkg/sql/schemachanger/scdeps/sctestdeps/test_deps.go +++ b/pkg/sql/schemachanger/scdeps/sctestdeps/test_deps.go @@ -207,6 +207,21 @@ func (s *TestState) MemberOfWithAdminOption( return nil, nil } +// HasGlobalPrivilegeOrRoleOption implements the scbuild.AuthorizationAccessor interface. +func (s *TestState) HasGlobalPrivilegeOrRoleOption( + ctx context.Context, privilege privilege.Kind, +) (bool, error) { + s.LogSideEffectf("checking current user %q has system privilege %q or the corresponding"+ + " legacy role option", s.User(), privilege.DisplayName()) + return true, nil +} + +// CheckRoleExists implements the scbuild.AuthorizationAccessor interface. +func (s *TestState) CheckRoleExists(ctx context.Context, role username.SQLUsername) error { + s.LogSideEffectf("checking role/user %q exists", role) + return nil +} + // IndexPartitioningCCLCallback implements the scbuild.Dependencies interface. func (s *TestState) IndexPartitioningCCLCallback() scbuild.CreatePartitioningCCLCallback { if ccl := scdeps.CreatePartitioningCCL; ccl != nil { diff --git a/pkg/sql/schemachanger/scexec/scmutationexec/BUILD.bazel b/pkg/sql/schemachanger/scexec/scmutationexec/BUILD.bazel index 84c390f414f4..8914c336e71c 100644 --- a/pkg/sql/schemachanger/scexec/scmutationexec/BUILD.bazel +++ b/pkg/sql/schemachanger/scexec/scmutationexec/BUILD.bazel @@ -7,6 +7,7 @@ go_library( "comment.go", "constraint.go", "create.go", + "database.go", "dependencies.go", "drop.go", "function.go", @@ -29,6 +30,7 @@ go_library( "//pkg/sql/catalog/catalogkeys", "//pkg/sql/catalog/catenumpb", "//pkg/sql/catalog/catpb", + "//pkg/sql/catalog/catprivilege", "//pkg/sql/catalog/colinfo", "//pkg/sql/catalog/dbdesc", "//pkg/sql/catalog/descpb", diff --git a/pkg/sql/schemachanger/scexec/scmutationexec/database.go b/pkg/sql/schemachanger/scexec/scmutationexec/database.go new file mode 100644 index 000000000000..b90bf87c7ea3 --- /dev/null +++ b/pkg/sql/schemachanger/scexec/scmutationexec/database.go @@ -0,0 +1,39 @@ +// Copyright 2023 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package scmutationexec + +import ( + "context" + + "github.com/cockroachdb/cockroach/pkg/sql/catalog/catpb" + "github.com/cockroachdb/cockroach/pkg/sql/catalog/catprivilege" + "github.com/cockroachdb/cockroach/pkg/sql/catalog/dbdesc" + "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" + "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scop" +) + +func (i *immediateVisitor) CreateDatabaseDescriptor( + ctx context.Context, op scop.CreateDatabaseDescriptor, +) error { + db := &descpb.DatabaseDescriptor{ + Name: "", // Set by `DatabaseName` element + ID: op.DatabaseID, + Version: 1, + Privileges: &catpb.PrivilegeDescriptor{Version: catpb.Version23_2}, // Populated by `UserPrivileges` elements and `Owner` element, + Schemas: map[string]descpb.DatabaseDescriptor_SchemaInfo{}, // Populated by `SchemaParent` element + State: descpb.DescriptorState_ADD, + RegionConfig: nil, + DefaultPrivileges: catprivilege.MakeDefaultPrivilegeDescriptor(catpb.DefaultPrivilegeDescriptor_DATABASE), + } + mut := dbdesc.NewBuilder(db).BuildCreatedMutableDatabase() + i.CreateDescriptor(mut) + return nil +} diff --git a/pkg/sql/schemachanger/scexec/scmutationexec/references.go b/pkg/sql/schemachanger/scexec/scmutationexec/references.go index 971ad7d69763..d2f1299b9316 100644 --- a/pkg/sql/schemachanger/scexec/scmutationexec/references.go +++ b/pkg/sql/schemachanger/scexec/scmutationexec/references.go @@ -53,6 +53,9 @@ func (i *immediateVisitor) AddSchemaParent(ctx context.Context, op scop.AddSchem if sc.Name == "" { return errors.AssertionFailedf("schema name is empty") } + if db.Schemas == nil { + db.Schemas = make(map[string]descpb.DatabaseDescriptor_SchemaInfo) + } if _, ok := db.Schemas[sc.Name]; ok { return errors.AssertionFailedf("schema %v already exists in database %v", sc.Name, db.Name) } diff --git a/pkg/sql/schemachanger/scexec/scmutationexec/schema.go b/pkg/sql/schemachanger/scexec/scmutationexec/schema.go index fe42ac59352a..914059d2c0db 100644 --- a/pkg/sql/schemachanger/scexec/scmutationexec/schema.go +++ b/pkg/sql/schemachanger/scexec/scmutationexec/schema.go @@ -25,12 +25,12 @@ func (i *immediateVisitor) CreateSchemaDescriptor( ) error { mut := schemadesc.NewBuilder(&descpb.SchemaDescriptor{ ParentID: catid.InvalidDescID, // Set by `SchemaParent` element - Name: "", // Set by `Namespace` element + Name: "", // Set by `SchemaName` element ID: op.SchemaID, Privileges: &catpb.PrivilegeDescriptor{Version: catpb.Version23_2}, // Populated by `UserPrivileges` elements and `Owner` element Version: 1, + State: descpb.DescriptorState_ADD, }).BuildCreatedMutableSchema() - mut.State = descpb.DescriptorState_ADD i.CreateDescriptor(mut) return nil } diff --git a/pkg/sql/schemachanger/scop/immediate_mutation.go b/pkg/sql/schemachanger/scop/immediate_mutation.go index 513604c20517..d4675c4066d0 100644 --- a/pkg/sql/schemachanger/scop/immediate_mutation.go +++ b/pkg/sql/schemachanger/scop/immediate_mutation.go @@ -842,3 +842,8 @@ type InitSequence struct { RestartWith int64 UseRestartWith bool } + +type CreateDatabaseDescriptor struct { + immediateMutationOp + DatabaseID descpb.ID +} diff --git a/pkg/sql/schemachanger/scop/immediate_mutation_visitor_generated.go b/pkg/sql/schemachanger/scop/immediate_mutation_visitor_generated.go index cbd4819cbd2d..611f82502111 100644 --- a/pkg/sql/schemachanger/scop/immediate_mutation_visitor_generated.go +++ b/pkg/sql/schemachanger/scop/immediate_mutation_visitor_generated.go @@ -128,6 +128,7 @@ type ImmediateMutationVisitor interface { CreateSequenceDescriptor(context.Context, CreateSequenceDescriptor) error SetSequenceOptions(context.Context, SetSequenceOptions) error InitSequence(context.Context, InitSequence) error + CreateDatabaseDescriptor(context.Context, CreateDatabaseDescriptor) error } // Visit is part of the ImmediateMutationOp interface. @@ -659,3 +660,8 @@ func (op SetSequenceOptions) Visit(ctx context.Context, v ImmediateMutationVisit func (op InitSequence) Visit(ctx context.Context, v ImmediateMutationVisitor) error { return v.InitSequence(ctx, op) } + +// Visit is part of the ImmediateMutationOp interface. +func (op CreateDatabaseDescriptor) Visit(ctx context.Context, v ImmediateMutationVisitor) error { + return v.CreateDatabaseDescriptor(ctx, op) +} diff --git a/pkg/sql/schemachanger/scpb/elements.proto b/pkg/sql/schemachanger/scpb/elements.proto index 76bbc1350d6f..6bddfa2085c9 100644 --- a/pkg/sql/schemachanger/scpb/elements.proto +++ b/pkg/sql/schemachanger/scpb/elements.proto @@ -129,7 +129,6 @@ message ElementProto { SchemaParent schema_parent = 90 [(gogoproto.moretags) = "parent:\"Schema\""]; SchemaComment schema_comment = 91 [(gogoproto.moretags) = "parent:\"Schema\""]; - // SchemaChild elements. SchemaChild schema_child = 100 [(gogoproto.moretags) = "parent:\"AliasType, EnumType, Table, View, Sequence\""]; @@ -735,3 +734,4 @@ message FunctionParamDefaultExpression { message ElementCreationMetadata { bool in_23_1_or_later = 1; } + diff --git a/pkg/sql/schemachanger/scplan/internal/opgen/opgen_database.go b/pkg/sql/schemachanger/scplan/internal/opgen/opgen_database.go index 36139a4c6a45..0b6fe0914196 100644 --- a/pkg/sql/schemachanger/scplan/internal/opgen/opgen_database.go +++ b/pkg/sql/schemachanger/scplan/internal/opgen/opgen_database.go @@ -20,9 +20,12 @@ func init() { opRegistry.register((*scpb.Database)(nil), toPublic( scpb.Status_ABSENT, - to(scpb.Status_DROPPED, - emit(func(this *scpb.Database) *scop.NotImplemented { - return notImplemented(this) + equiv(scpb.Status_DROPPED), + to(scpb.Status_DESCRIPTOR_ADDED, + emit(func(this *scpb.Database) *scop.CreateDatabaseDescriptor { + return &scop.CreateDatabaseDescriptor{ + DatabaseID: this.DatabaseID, + } }), ), to(scpb.Status_PUBLIC, @@ -36,6 +39,7 @@ func init() { ), toAbsent( scpb.Status_PUBLIC, + equiv(scpb.Status_DESCRIPTOR_ADDED), to(scpb.Status_DROPPED, revertible(false), emit(func(this *scpb.Database) *scop.MarkDescriptorAsDropped { diff --git a/pkg/sql/schemachanger/scplan/testdata/create_database b/pkg/sql/schemachanger/scplan/testdata/create_database new file mode 100644 index 000000000000..402a0c9e4a38 --- /dev/null +++ b/pkg/sql/schemachanger/scplan/testdata/create_database @@ -0,0 +1,294 @@ +ops +CREATE DATABASE db; +---- +StatementPhase stage 1 of 1 with 17 MutationType ops + transitions: + [[Database:{DescID: 104}, PUBLIC], ABSENT] -> PUBLIC + [[Namespace:{DescID: 104, Name: db, ReferencedDescID: 0}, PUBLIC], ABSENT] -> PUBLIC + [[DatabaseData:{DescID: 104}, PUBLIC], ABSENT] -> PUBLIC + [[Owner:{DescID: 104}, PUBLIC], ABSENT] -> PUBLIC + [[UserPrivileges:{DescID: 104, Name: admin}, PUBLIC], ABSENT] -> PUBLIC + [[UserPrivileges:{DescID: 104, Name: public}, PUBLIC], ABSENT] -> PUBLIC + [[UserPrivileges:{DescID: 104, Name: root}, PUBLIC], ABSENT] -> PUBLIC + [[Schema:{DescID: 105}, PUBLIC], ABSENT] -> PUBLIC + [[Namespace:{DescID: 105, Name: public, ReferencedDescID: 104}, PUBLIC], ABSENT] -> PUBLIC + [[SchemaParent:{DescID: 105, ReferencedDescID: 104}, PUBLIC], ABSENT] -> PUBLIC + [[Owner:{DescID: 105}, PUBLIC], ABSENT] -> PUBLIC + [[UserPrivileges:{DescID: 105, Name: admin}, PUBLIC], ABSENT] -> PUBLIC + [[UserPrivileges:{DescID: 105, Name: public}, PUBLIC], ABSENT] -> PUBLIC + [[UserPrivileges:{DescID: 105, Name: root}, PUBLIC], ABSENT] -> PUBLIC + ops: + *scop.CreateDatabaseDescriptor + DatabaseID: 104 + *scop.SetNameInDescriptor + DescriptorID: 104 + Name: db + *scop.AddDescriptorName + Namespace: + DescriptorID: 104 + Name: db + *scop.UpdateOwner + Owner: + DescriptorID: 104 + Owner: root + *scop.UpdateUserPrivileges + Privileges: + DescriptorID: 104 + Privileges: 2 + UserName: admin + WithGrantOption: 2 + *scop.UpdateUserPrivileges + Privileges: + DescriptorID: 104 + Privileges: 2048 + UserName: public + *scop.UpdateUserPrivileges + Privileges: + DescriptorID: 104 + Privileges: 2 + UserName: root + WithGrantOption: 2 + *scop.CreateSchemaDescriptor + SchemaID: 105 + *scop.SetNameInDescriptor + DescriptorID: 105 + Name: public + *scop.AddDescriptorName + Namespace: + DatabaseID: 104 + DescriptorID: 105 + Name: public + *scop.AddSchemaParent + Parent: + ParentDatabaseID: 104 + SchemaID: 105 + *scop.UpdateOwner + Owner: + DescriptorID: 105 + Owner: admin + *scop.UpdateUserPrivileges + Privileges: + DescriptorID: 105 + Privileges: 2 + UserName: admin + WithGrantOption: 2 + *scop.UpdateUserPrivileges + Privileges: + DescriptorID: 105 + Privileges: 516 + UserName: public + *scop.UpdateUserPrivileges + Privileges: + DescriptorID: 105 + Privileges: 2 + UserName: root + WithGrantOption: 2 + *scop.MarkDescriptorAsPublic + DescriptorID: 104 + *scop.MarkDescriptorAsPublic + DescriptorID: 105 +PreCommitPhase stage 1 of 2 with 1 MutationType op + transitions: + [[Database:{DescID: 104}, PUBLIC], PUBLIC] -> ABSENT + [[Namespace:{DescID: 104, Name: db, ReferencedDescID: 0}, PUBLIC], PUBLIC] -> ABSENT + [[DatabaseData:{DescID: 104}, PUBLIC], PUBLIC] -> ABSENT + [[Owner:{DescID: 104}, PUBLIC], PUBLIC] -> ABSENT + [[UserPrivileges:{DescID: 104, Name: admin}, PUBLIC], PUBLIC] -> ABSENT + [[UserPrivileges:{DescID: 104, Name: public}, PUBLIC], PUBLIC] -> ABSENT + [[UserPrivileges:{DescID: 104, Name: root}, PUBLIC], PUBLIC] -> ABSENT + [[Schema:{DescID: 105}, PUBLIC], PUBLIC] -> ABSENT + [[Namespace:{DescID: 105, Name: public, ReferencedDescID: 104}, PUBLIC], PUBLIC] -> ABSENT + [[SchemaParent:{DescID: 105, ReferencedDescID: 104}, PUBLIC], PUBLIC] -> ABSENT + [[Owner:{DescID: 105}, PUBLIC], PUBLIC] -> ABSENT + [[UserPrivileges:{DescID: 105, Name: admin}, PUBLIC], PUBLIC] -> ABSENT + [[UserPrivileges:{DescID: 105, Name: public}, PUBLIC], PUBLIC] -> ABSENT + [[UserPrivileges:{DescID: 105, Name: root}, PUBLIC], PUBLIC] -> ABSENT + ops: + *scop.UndoAllInTxnImmediateMutationOpSideEffects + {} +PreCommitPhase stage 2 of 2 with 17 MutationType ops + transitions: + [[Database:{DescID: 104}, PUBLIC], ABSENT] -> PUBLIC + [[Namespace:{DescID: 104, Name: db, ReferencedDescID: 0}, PUBLIC], ABSENT] -> PUBLIC + [[DatabaseData:{DescID: 104}, PUBLIC], ABSENT] -> PUBLIC + [[Owner:{DescID: 104}, PUBLIC], ABSENT] -> PUBLIC + [[UserPrivileges:{DescID: 104, Name: admin}, PUBLIC], ABSENT] -> PUBLIC + [[UserPrivileges:{DescID: 104, Name: public}, PUBLIC], ABSENT] -> PUBLIC + [[UserPrivileges:{DescID: 104, Name: root}, PUBLIC], ABSENT] -> PUBLIC + [[Schema:{DescID: 105}, PUBLIC], ABSENT] -> PUBLIC + [[Namespace:{DescID: 105, Name: public, ReferencedDescID: 104}, PUBLIC], ABSENT] -> PUBLIC + [[SchemaParent:{DescID: 105, ReferencedDescID: 104}, PUBLIC], ABSENT] -> PUBLIC + [[Owner:{DescID: 105}, PUBLIC], ABSENT] -> PUBLIC + [[UserPrivileges:{DescID: 105, Name: admin}, PUBLIC], ABSENT] -> PUBLIC + [[UserPrivileges:{DescID: 105, Name: public}, PUBLIC], ABSENT] -> PUBLIC + [[UserPrivileges:{DescID: 105, Name: root}, PUBLIC], ABSENT] -> PUBLIC + ops: + *scop.CreateDatabaseDescriptor + DatabaseID: 104 + *scop.SetNameInDescriptor + DescriptorID: 104 + Name: db + *scop.AddDescriptorName + Namespace: + DescriptorID: 104 + Name: db + *scop.UpdateOwner + Owner: + DescriptorID: 104 + Owner: root + *scop.UpdateUserPrivileges + Privileges: + DescriptorID: 104 + Privileges: 2 + UserName: admin + WithGrantOption: 2 + *scop.UpdateUserPrivileges + Privileges: + DescriptorID: 104 + Privileges: 2048 + UserName: public + *scop.UpdateUserPrivileges + Privileges: + DescriptorID: 104 + Privileges: 2 + UserName: root + WithGrantOption: 2 + *scop.CreateSchemaDescriptor + SchemaID: 105 + *scop.SetNameInDescriptor + DescriptorID: 105 + Name: public + *scop.AddDescriptorName + Namespace: + DatabaseID: 104 + DescriptorID: 105 + Name: public + *scop.AddSchemaParent + Parent: + ParentDatabaseID: 104 + SchemaID: 105 + *scop.UpdateOwner + Owner: + DescriptorID: 105 + Owner: admin + *scop.UpdateUserPrivileges + Privileges: + DescriptorID: 105 + Privileges: 2 + UserName: admin + WithGrantOption: 2 + *scop.UpdateUserPrivileges + Privileges: + DescriptorID: 105 + Privileges: 516 + UserName: public + *scop.UpdateUserPrivileges + Privileges: + DescriptorID: 105 + Privileges: 2 + UserName: root + WithGrantOption: 2 + *scop.MarkDescriptorAsPublic + DescriptorID: 104 + *scop.MarkDescriptorAsPublic + DescriptorID: 105 + +deps +CREATE DATABASE db; +---- +- from: [Database:{DescID: 106}, DESCRIPTOR_ADDED] + to: [DatabaseData:{DescID: 106}, PUBLIC] + kind: Precedence + rule: descriptor existence precedes dependents +- from: [Database:{DescID: 106}, DESCRIPTOR_ADDED] + to: [Namespace:{DescID: 106, Name: db, ReferencedDescID: 0}, PUBLIC] + kind: Precedence + rule: descriptor existence precedes dependents +- from: [Database:{DescID: 106}, DESCRIPTOR_ADDED] + to: [Owner:{DescID: 106}, PUBLIC] + kind: Precedence + rule: descriptor existence precedes dependents +- from: [Database:{DescID: 106}, DESCRIPTOR_ADDED] + to: [UserPrivileges:{DescID: 106, Name: admin}, PUBLIC] + kind: Precedence + rule: descriptor existence precedes dependents +- from: [Database:{DescID: 106}, DESCRIPTOR_ADDED] + to: [UserPrivileges:{DescID: 106, Name: public}, PUBLIC] + kind: Precedence + rule: descriptor existence precedes dependents +- from: [Database:{DescID: 106}, DESCRIPTOR_ADDED] + to: [UserPrivileges:{DescID: 106, Name: root}, PUBLIC] + kind: Precedence + rule: descriptor existence precedes dependents +- from: [DatabaseData:{DescID: 106}, PUBLIC] + to: [Database:{DescID: 106}, PUBLIC] + kind: Precedence + rule: dependents exist before descriptor becomes public +- from: [Namespace:{DescID: 106, Name: db, ReferencedDescID: 0}, PUBLIC] + to: [Database:{DescID: 106}, PUBLIC] + kind: Precedence + rule: dependents exist before descriptor becomes public +- from: [Namespace:{DescID: 107, Name: public, ReferencedDescID: 106}, PUBLIC] + to: [Schema:{DescID: 107}, PUBLIC] + kind: Precedence + rule: dependents exist before descriptor becomes public +- from: [Owner:{DescID: 106}, PUBLIC] + to: [Database:{DescID: 106}, PUBLIC] + kind: Precedence + rule: dependents exist before descriptor becomes public +- from: [Owner:{DescID: 107}, PUBLIC] + to: [Schema:{DescID: 107}, PUBLIC] + kind: Precedence + rule: dependents exist before descriptor becomes public +- from: [Schema:{DescID: 107}, DESCRIPTOR_ADDED] + to: [Namespace:{DescID: 107, Name: public, ReferencedDescID: 106}, PUBLIC] + kind: Precedence + rule: descriptor existence precedes dependents +- from: [Schema:{DescID: 107}, DESCRIPTOR_ADDED] + to: [Owner:{DescID: 107}, PUBLIC] + kind: Precedence + rule: descriptor existence precedes dependents +- from: [Schema:{DescID: 107}, DESCRIPTOR_ADDED] + to: [SchemaParent:{DescID: 107, ReferencedDescID: 106}, PUBLIC] + kind: Precedence + rule: descriptor existence precedes dependents +- from: [Schema:{DescID: 107}, DESCRIPTOR_ADDED] + to: [UserPrivileges:{DescID: 107, Name: admin}, PUBLIC] + kind: Precedence + rule: descriptor existence precedes dependents +- from: [Schema:{DescID: 107}, DESCRIPTOR_ADDED] + to: [UserPrivileges:{DescID: 107, Name: public}, PUBLIC] + kind: Precedence + rule: descriptor existence precedes dependents +- from: [Schema:{DescID: 107}, DESCRIPTOR_ADDED] + to: [UserPrivileges:{DescID: 107, Name: root}, PUBLIC] + kind: Precedence + rule: descriptor existence precedes dependents +- from: [SchemaParent:{DescID: 107, ReferencedDescID: 106}, PUBLIC] + to: [Schema:{DescID: 107}, PUBLIC] + kind: Precedence + rule: dependents exist before descriptor becomes public +- from: [UserPrivileges:{DescID: 106, Name: admin}, PUBLIC] + to: [Database:{DescID: 106}, PUBLIC] + kind: Precedence + rule: dependents exist before descriptor becomes public +- from: [UserPrivileges:{DescID: 106, Name: public}, PUBLIC] + to: [Database:{DescID: 106}, PUBLIC] + kind: Precedence + rule: dependents exist before descriptor becomes public +- from: [UserPrivileges:{DescID: 106, Name: root}, PUBLIC] + to: [Database:{DescID: 106}, PUBLIC] + kind: Precedence + rule: dependents exist before descriptor becomes public +- from: [UserPrivileges:{DescID: 107, Name: admin}, PUBLIC] + to: [Schema:{DescID: 107}, PUBLIC] + kind: Precedence + rule: dependents exist before descriptor becomes public +- from: [UserPrivileges:{DescID: 107, Name: public}, PUBLIC] + to: [Schema:{DescID: 107}, PUBLIC] + kind: Precedence + rule: dependents exist before descriptor becomes public +- from: [UserPrivileges:{DescID: 107, Name: root}, PUBLIC] + to: [Schema:{DescID: 107}, PUBLIC] + kind: Precedence + rule: dependents exist before descriptor becomes public diff --git a/pkg/sql/schemachanger/sctest_generated_test.go b/pkg/sql/schemachanger/sctest_generated_test.go index 87baa738835a..e9348b90cb39 100644 --- a/pkg/sql/schemachanger/sctest_generated_test.go +++ b/pkg/sql/schemachanger/sctest_generated_test.go @@ -181,6 +181,20 @@ func TestEndToEndSideEffects_alter_table_validate_constraint(t *testing.T) { sctest.EndToEndSideEffects(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestEndToEndSideEffects_create_database(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database" + sctest.EndToEndSideEffects(t, path, sctest.SingleNodeTestClusterFactory{}) +} + +func TestEndToEndSideEffects_create_database_drop_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements" + sctest.EndToEndSideEffects(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestEndToEndSideEffects_create_function(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -202,6 +216,13 @@ func TestEndToEndSideEffects_create_index(t *testing.T) { sctest.EndToEndSideEffects(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestEndToEndSideEffects_create_index_create_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements" + sctest.EndToEndSideEffects(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestEndToEndSideEffects_create_index_create_schema_separate_statements(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -510,6 +531,20 @@ func TestExecuteWithDMLInjection_alter_table_validate_constraint(t *testing.T) { sctest.ExecuteWithDMLInjection(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestExecuteWithDMLInjection_create_database(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database" + sctest.ExecuteWithDMLInjection(t, path, sctest.SingleNodeTestClusterFactory{}) +} + +func TestExecuteWithDMLInjection_create_database_drop_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements" + sctest.ExecuteWithDMLInjection(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestExecuteWithDMLInjection_create_function(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -531,6 +566,13 @@ func TestExecuteWithDMLInjection_create_index(t *testing.T) { sctest.ExecuteWithDMLInjection(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestExecuteWithDMLInjection_create_index_create_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements" + sctest.ExecuteWithDMLInjection(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestExecuteWithDMLInjection_create_index_create_schema_separate_statements(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -839,6 +881,20 @@ func TestGenerateSchemaChangeCorpus_alter_table_validate_constraint(t *testing.T sctest.GenerateSchemaChangeCorpus(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestGenerateSchemaChangeCorpus_create_database(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database" + sctest.GenerateSchemaChangeCorpus(t, path, sctest.SingleNodeTestClusterFactory{}) +} + +func TestGenerateSchemaChangeCorpus_create_database_drop_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements" + sctest.GenerateSchemaChangeCorpus(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestGenerateSchemaChangeCorpus_create_function(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -860,6 +916,13 @@ func TestGenerateSchemaChangeCorpus_create_index(t *testing.T) { sctest.GenerateSchemaChangeCorpus(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestGenerateSchemaChangeCorpus_create_index_create_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements" + sctest.GenerateSchemaChangeCorpus(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestGenerateSchemaChangeCorpus_create_index_create_schema_separate_statements(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1168,6 +1231,20 @@ func TestPause_alter_table_validate_constraint(t *testing.T) { sctest.Pause(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestPause_create_database(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database" + sctest.Pause(t, path, sctest.SingleNodeTestClusterFactory{}) +} + +func TestPause_create_database_drop_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements" + sctest.Pause(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestPause_create_function(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1189,6 +1266,13 @@ func TestPause_create_index(t *testing.T) { sctest.Pause(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestPause_create_index_create_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements" + sctest.Pause(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestPause_create_index_create_schema_separate_statements(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1497,6 +1581,20 @@ func TestPauseMixedVersion_alter_table_validate_constraint(t *testing.T) { sctest.PauseMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestPauseMixedVersion_create_database(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database" + sctest.PauseMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + +func TestPauseMixedVersion_create_database_drop_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements" + sctest.PauseMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestPauseMixedVersion_create_function(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1518,6 +1616,13 @@ func TestPauseMixedVersion_create_index(t *testing.T) { sctest.PauseMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestPauseMixedVersion_create_index_create_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements" + sctest.PauseMixedVersion(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestPauseMixedVersion_create_index_create_schema_separate_statements(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1826,6 +1931,20 @@ func TestRollback_alter_table_validate_constraint(t *testing.T) { sctest.Rollback(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestRollback_create_database(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database" + sctest.Rollback(t, path, sctest.SingleNodeTestClusterFactory{}) +} + +func TestRollback_create_database_drop_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements" + sctest.Rollback(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestRollback_create_function(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1847,6 +1966,13 @@ func TestRollback_create_index(t *testing.T) { sctest.Rollback(t, path, sctest.SingleNodeTestClusterFactory{}) } +func TestRollback_create_index_create_database_separate_statements(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + const path = "pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements" + sctest.Rollback(t, path, sctest.SingleNodeTestClusterFactory{}) +} + func TestRollback_create_index_create_schema_separate_statements(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_database/create_database.definition b/pkg/sql/schemachanger/testdata/end_to_end/create_database/create_database.definition new file mode 100644 index 000000000000..d97bbce623bb --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_database/create_database.definition @@ -0,0 +1,3 @@ +test +CREATE DATABASE db; +---- diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_database/create_database.explain b/pkg/sql/schemachanger/testdata/end_to_end/create_database/create_database.explain new file mode 100644 index 000000000000..471d4e833764 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_database/create_database.explain @@ -0,0 +1,94 @@ +/* setup */ + +/* test */ +EXPLAIN (DDL) CREATE DATABASE db; +---- +Schema change plan for CREATE DATABASE ‹db›; + ├── StatementPhase + │ └── Stage 1 of 1 in StatementPhase + │ ├── 14 elements transitioning toward PUBLIC + │ │ ├── ABSENT → PUBLIC Database:{DescID: 104 (db+)} + │ │ ├── ABSENT → PUBLIC Namespace:{DescID: 104 (db+), Name: "db"} + │ │ ├── ABSENT → PUBLIC DatabaseData:{DescID: 104 (db+)} + │ │ ├── ABSENT → PUBLIC Owner:{DescID: 104 (db+)} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 104 (db+), Name: "admin"} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 104 (db+), Name: "public"} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 104 (db+), Name: "root"} + │ │ ├── ABSENT → PUBLIC Schema:{DescID: 105 (public+)} + │ │ ├── ABSENT → PUBLIC Namespace:{DescID: 105 (public+), Name: "public", ReferencedDescID: 104 (db+)} + │ │ ├── ABSENT → PUBLIC SchemaParent:{DescID: 105 (public+), ReferencedDescID: 104 (db+)} + │ │ ├── ABSENT → PUBLIC Owner:{DescID: 105 (public+)} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (public+), Name: "admin"} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (public+), Name: "public"} + │ │ └── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (public+), Name: "root"} + │ └── 17 Mutation operations + │ ├── CreateDatabaseDescriptor {"DatabaseID":104} + │ ├── SetNameInDescriptor {"DescriptorID":104,"Name":"db"} + │ ├── AddDescriptorName {"Namespace":{"DescriptorID":104,"Name":"db"}} + │ ├── UpdateOwner {"Owner":{"DescriptorID":104,"Owner":"root"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":104,"Privileges":2,"UserName":"admin","WithGrantOption":2}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":104,"Privileges":2048,"UserName":"public"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":104,"Privileges":2,"UserName":"root","WithGrantOption":2}} + │ ├── CreateSchemaDescriptor {"SchemaID":105} + │ ├── SetNameInDescriptor {"DescriptorID":105,"Name":"public"} + │ ├── AddDescriptorName {"Namespace":{"DatabaseID":104,"DescriptorID":105,"Name":"public"}} + │ ├── AddSchemaParent {"Parent":{"ParentDatabaseID":104,"SchemaID":105}} + │ ├── UpdateOwner {"Owner":{"DescriptorID":105,"Owner":"admin"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":2,"UserName":"admin","WithGrantOption":2}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":516,"UserName":"public"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":2,"UserName":"root","WithGrantOption":2}} + │ ├── MarkDescriptorAsPublic {"DescriptorID":104} + │ └── MarkDescriptorAsPublic {"DescriptorID":105} + └── PreCommitPhase + ├── Stage 1 of 2 in PreCommitPhase + │ ├── 14 elements transitioning toward PUBLIC + │ │ ├── PUBLIC → ABSENT Database:{DescID: 104 (db+)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 104 (db+), Name: "db"} + │ │ ├── PUBLIC → ABSENT DatabaseData:{DescID: 104 (db+)} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 104 (db+)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 104 (db+), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 104 (db+), Name: "public"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 104 (db+), Name: "root"} + │ │ ├── PUBLIC → ABSENT Schema:{DescID: 105 (public+)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 105 (public+), Name: "public", ReferencedDescID: 104 (db+)} + │ │ ├── PUBLIC → ABSENT SchemaParent:{DescID: 105 (public+), ReferencedDescID: 104 (db+)} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 105 (public+)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (public+), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (public+), Name: "public"} + │ │ └── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (public+), Name: "root"} + │ └── 1 Mutation operation + │ └── UndoAllInTxnImmediateMutationOpSideEffects + └── Stage 2 of 2 in PreCommitPhase + ├── 14 elements transitioning toward PUBLIC + │ ├── ABSENT → PUBLIC Database:{DescID: 104 (db+)} + │ ├── ABSENT → PUBLIC Namespace:{DescID: 104 (db+), Name: "db"} + │ ├── ABSENT → PUBLIC DatabaseData:{DescID: 104 (db+)} + │ ├── ABSENT → PUBLIC Owner:{DescID: 104 (db+)} + │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 104 (db+), Name: "admin"} + │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 104 (db+), Name: "public"} + │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 104 (db+), Name: "root"} + │ ├── ABSENT → PUBLIC Schema:{DescID: 105 (public+)} + │ ├── ABSENT → PUBLIC Namespace:{DescID: 105 (public+), Name: "public", ReferencedDescID: 104 (db+)} + │ ├── ABSENT → PUBLIC SchemaParent:{DescID: 105 (public+), ReferencedDescID: 104 (db+)} + │ ├── ABSENT → PUBLIC Owner:{DescID: 105 (public+)} + │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (public+), Name: "admin"} + │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (public+), Name: "public"} + │ └── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (public+), Name: "root"} + └── 17 Mutation operations + ├── CreateDatabaseDescriptor {"DatabaseID":104} + ├── SetNameInDescriptor {"DescriptorID":104,"Name":"db"} + ├── AddDescriptorName {"Namespace":{"DescriptorID":104,"Name":"db"}} + ├── UpdateOwner {"Owner":{"DescriptorID":104,"Owner":"root"}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":104,"Privileges":2,"UserName":"admin","WithGrantOption":2}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":104,"Privileges":2048,"UserName":"public"}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":104,"Privileges":2,"UserName":"root","WithGrantOption":2}} + ├── CreateSchemaDescriptor {"SchemaID":105} + ├── SetNameInDescriptor {"DescriptorID":105,"Name":"public"} + ├── AddDescriptorName {"Namespace":{"DatabaseID":104,"DescriptorID":105,"Name":"public"}} + ├── AddSchemaParent {"Parent":{"ParentDatabaseID":104,"SchemaID":105}} + ├── UpdateOwner {"Owner":{"DescriptorID":105,"Owner":"admin"}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":2,"UserName":"admin","WithGrantOption":2}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":516,"UserName":"public"}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":2,"UserName":"root","WithGrantOption":2}} + ├── MarkDescriptorAsPublic {"DescriptorID":104} + └── MarkDescriptorAsPublic {"DescriptorID":105} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_database/create_database.explain_shape b/pkg/sql/schemachanger/testdata/end_to_end/create_database/create_database.explain_shape new file mode 100644 index 000000000000..1db22d633344 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_database/create_database.explain_shape @@ -0,0 +1,7 @@ +/* setup */ + +/* test */ +EXPLAIN (DDL, SHAPE) CREATE DATABASE db; +---- +Schema change plan for CREATE DATABASE ‹db›; + └── execute 1 system table mutations transaction diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_database/create_database.side_effects b/pkg/sql/schemachanger/testdata/end_to_end/create_database/create_database.side_effects new file mode 100644 index 000000000000..20e727afc7fd --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_database/create_database.side_effects @@ -0,0 +1,120 @@ +/* setup */ +---- + + +/* test */ +CREATE DATABASE db; +---- +begin transaction #1 +# begin StatementPhase +checking for feature: CREATE DATABASE +checking current user "root" has system privilege "CREATEDB" or the corresponding legacy role option +increment telemetry for sql.schema.create_database +checking role/user "root" exists +write *eventpb.CreateDatabase to event log: + databaseName: db + sql: + descriptorId: 104 + statement: CREATE DATABASE ‹db› + tag: CREATE DATABASE + user: root +## StatementPhase stage 1 of 1 with 17 MutationType ops +add database namespace entry {0 0 db} -> 104 +add schema namespace entry {104 0 public} -> 105 +upsert descriptor #104 + - + +database: + + defaultPrivileges: {} + + id: 104 + + modificationTime: {} + + name: db + + privileges: + + ownerProto: root + + users: + + - privileges: "2" + + userProto: admin + + withGrantOption: "2" + + - privileges: "2048" + + userProto: public + + - privileges: "2" + + userProto: root + + withGrantOption: "2" + + version: 3 + + schemas: + + public: + + id: 105 + + version: "1" +upsert descriptor #105 + - + +schema: + + id: 105 + + modificationTime: {} + + name: public + + parentId: 104 + + privileges: + + ownerProto: admin + + users: + + - privileges: "2" + + userProto: admin + + withGrantOption: "2" + + - privileges: "516" + + userProto: public + + - privileges: "2" + + userProto: root + + withGrantOption: "2" + + version: 3 + + version: "1" +# 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 17 MutationType ops +add database namespace entry {0 0 db} -> 104 +add schema namespace entry {104 0 public} -> 105 +upsert descriptor #104 + - + +database: + + defaultPrivileges: {} + + id: 104 + + modificationTime: {} + + name: db + + privileges: + + ownerProto: root + + users: + + - privileges: "2" + + userProto: admin + + withGrantOption: "2" + + - privileges: "2048" + + userProto: public + + - privileges: "2" + + userProto: root + + withGrantOption: "2" + + version: 3 + + schemas: + + public: + + id: 105 + + version: "1" +upsert descriptor #105 + - + +schema: + + id: 105 + + modificationTime: {} + + name: public + + parentId: 104 + + privileges: + + ownerProto: admin + + users: + + - privileges: "2" + + userProto: admin + + withGrantOption: "2" + + - privileges: "516" + + userProto: public + + - privileges: "2" + + userProto: root + + withGrantOption: "2" + + version: 3 + + version: "1" +persist all catalog changes to storage +# end PreCommitPhase +commit transaction #1 diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements.definition b/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements.definition new file mode 100644 index 000000000000..b84be9834202 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements.definition @@ -0,0 +1,5 @@ +test +CREATE DATABASE db; +DROP DATABASE db; +CREATE DATABASE db; +---- diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements.side_effects b/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements.side_effects new file mode 100644 index 000000000000..c553ec0590a6 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements.side_effects @@ -0,0 +1,208 @@ +/* setup */ +---- + + +/* test */ +CREATE DATABASE db; +DROP DATABASE db; +CREATE DATABASE db; +---- +begin transaction #1 +# begin StatementPhase +checking for feature: CREATE DATABASE +checking current user "root" has system privilege "CREATEDB" or the corresponding legacy role option +increment telemetry for sql.schema.create_database +checking role/user "root" exists +write *eventpb.CreateDatabase to event log: + databaseName: db + sql: + descriptorId: 104 + statement: CREATE DATABASE ‹db› + tag: CREATE DATABASE + user: root +## StatementPhase stage 1 of 1 with 17 MutationType ops +add database namespace entry {0 0 db} -> 104 +add schema namespace entry {104 0 public} -> 105 +upsert descriptor #104 + - + +database: + + defaultPrivileges: {} + + id: 104 + + modificationTime: {} + + name: db + + privileges: + + ownerProto: root + + users: + + - privileges: "2" + + userProto: admin + + withGrantOption: "2" + + - privileges: "2048" + + userProto: public + + - privileges: "2" + + userProto: root + + withGrantOption: "2" + + version: 3 + + schemas: + + public: + + id: 105 + + version: "1" +upsert descriptor #105 + - + +schema: + + id: 105 + + modificationTime: {} + + name: public + + parentId: 104 + + privileges: + + ownerProto: admin + + users: + + - privileges: "2" + + userProto: admin + + withGrantOption: "2" + + - privileges: "516" + + userProto: public + + - privileges: "2" + + userProto: root + + withGrantOption: "2" + + version: 3 + + version: "1" +checking for feature: DROP DATABASE +increment telemetry for sql.schema.drop_database +getting all objects in schema: 105 +write *eventpb.DropDatabase to event log: + databaseName: db + sql: + descriptorId: 104 + statement: DROP DATABASE ‹db› + tag: DROP DATABASE + user: root +## StatementPhase stage 1 of 1 with 13 MutationType ops +delete database namespace entry {0 0 db} -> 104 +delete schema namespace entry {104 0 public} -> 105 +upsert descriptor #104 + ... + withGrantOption: "2" + version: 3 + - schemas: + - public: + - id: 105 + + state: DROP + version: "1" +upsert descriptor #105 + ... + withGrantOption: "2" + version: 3 + + state: DROP + version: "1" +checking for feature: CREATE DATABASE +checking current user "root" has system privilege "CREATEDB" or the corresponding legacy role option +increment telemetry for sql.schema.create_database +checking role/user "root" exists +write *eventpb.CreateDatabase to event log: + databaseName: db + sql: + descriptorId: 106 + statement: CREATE DATABASE ‹db› + tag: CREATE DATABASE + user: root +## StatementPhase stage 1 of 1 with 17 MutationType ops +add database namespace entry {0 0 db} -> 106 +add schema namespace entry {106 0 public} -> 107 +upsert descriptor #106 + - + +database: + + defaultPrivileges: {} + + id: 106 + + modificationTime: {} + + name: db + + privileges: + + ownerProto: root + + users: + + - privileges: "2" + + userProto: admin + + withGrantOption: "2" + + - privileges: "2048" + + userProto: public + + - privileges: "2" + + userProto: root + + withGrantOption: "2" + + version: 3 + + schemas: + + public: + + id: 107 + + version: "1" +upsert descriptor #107 + - + +schema: + + id: 107 + + modificationTime: {} + + name: public + + parentId: 106 + + privileges: + + ownerProto: admin + + users: + + - privileges: "2" + + userProto: admin + + withGrantOption: "2" + + - privileges: "516" + + userProto: public + + - privileges: "2" + + userProto: root + + withGrantOption: "2" + + version: 3 + + version: "1" +# 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 18 MutationType ops +add database namespace entry {0 0 db} -> 106 +add schema namespace entry {106 0 public} -> 107 +upsert descriptor #106 + - + +database: + + defaultPrivileges: {} + + id: 106 + + modificationTime: {} + + name: db + + privileges: + + ownerProto: root + + users: + + - privileges: "2" + + userProto: admin + + withGrantOption: "2" + + - privileges: "2048" + + userProto: public + + - privileges: "2" + + userProto: root + + withGrantOption: "2" + + version: 3 + + schemas: + + public: + + id: 107 + + version: "1" +upsert descriptor #107 + - + +schema: + + id: 107 + + modificationTime: {} + + name: public + + parentId: 106 + + privileges: + + ownerProto: admin + + users: + + - privileges: "2" + + userProto: admin + + withGrantOption: "2" + + - privileges: "516" + + userProto: public + + - privileges: "2" + + userProto: root + + withGrantOption: "2" + + version: 3 + + version: "1" +persist all catalog changes to storage +delete role settings for database on #104 +# end PreCommitPhase +commit transaction #1 diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_1_of_3.explain b/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_1_of_3.explain new file mode 100644 index 000000000000..471d4e833764 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_1_of_3.explain @@ -0,0 +1,94 @@ +/* setup */ + +/* test */ +EXPLAIN (DDL) CREATE DATABASE db; +---- +Schema change plan for CREATE DATABASE ‹db›; + ├── StatementPhase + │ └── Stage 1 of 1 in StatementPhase + │ ├── 14 elements transitioning toward PUBLIC + │ │ ├── ABSENT → PUBLIC Database:{DescID: 104 (db+)} + │ │ ├── ABSENT → PUBLIC Namespace:{DescID: 104 (db+), Name: "db"} + │ │ ├── ABSENT → PUBLIC DatabaseData:{DescID: 104 (db+)} + │ │ ├── ABSENT → PUBLIC Owner:{DescID: 104 (db+)} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 104 (db+), Name: "admin"} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 104 (db+), Name: "public"} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 104 (db+), Name: "root"} + │ │ ├── ABSENT → PUBLIC Schema:{DescID: 105 (public+)} + │ │ ├── ABSENT → PUBLIC Namespace:{DescID: 105 (public+), Name: "public", ReferencedDescID: 104 (db+)} + │ │ ├── ABSENT → PUBLIC SchemaParent:{DescID: 105 (public+), ReferencedDescID: 104 (db+)} + │ │ ├── ABSENT → PUBLIC Owner:{DescID: 105 (public+)} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (public+), Name: "admin"} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (public+), Name: "public"} + │ │ └── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (public+), Name: "root"} + │ └── 17 Mutation operations + │ ├── CreateDatabaseDescriptor {"DatabaseID":104} + │ ├── SetNameInDescriptor {"DescriptorID":104,"Name":"db"} + │ ├── AddDescriptorName {"Namespace":{"DescriptorID":104,"Name":"db"}} + │ ├── UpdateOwner {"Owner":{"DescriptorID":104,"Owner":"root"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":104,"Privileges":2,"UserName":"admin","WithGrantOption":2}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":104,"Privileges":2048,"UserName":"public"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":104,"Privileges":2,"UserName":"root","WithGrantOption":2}} + │ ├── CreateSchemaDescriptor {"SchemaID":105} + │ ├── SetNameInDescriptor {"DescriptorID":105,"Name":"public"} + │ ├── AddDescriptorName {"Namespace":{"DatabaseID":104,"DescriptorID":105,"Name":"public"}} + │ ├── AddSchemaParent {"Parent":{"ParentDatabaseID":104,"SchemaID":105}} + │ ├── UpdateOwner {"Owner":{"DescriptorID":105,"Owner":"admin"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":2,"UserName":"admin","WithGrantOption":2}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":516,"UserName":"public"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":2,"UserName":"root","WithGrantOption":2}} + │ ├── MarkDescriptorAsPublic {"DescriptorID":104} + │ └── MarkDescriptorAsPublic {"DescriptorID":105} + └── PreCommitPhase + ├── Stage 1 of 2 in PreCommitPhase + │ ├── 14 elements transitioning toward PUBLIC + │ │ ├── PUBLIC → ABSENT Database:{DescID: 104 (db+)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 104 (db+), Name: "db"} + │ │ ├── PUBLIC → ABSENT DatabaseData:{DescID: 104 (db+)} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 104 (db+)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 104 (db+), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 104 (db+), Name: "public"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 104 (db+), Name: "root"} + │ │ ├── PUBLIC → ABSENT Schema:{DescID: 105 (public+)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 105 (public+), Name: "public", ReferencedDescID: 104 (db+)} + │ │ ├── PUBLIC → ABSENT SchemaParent:{DescID: 105 (public+), ReferencedDescID: 104 (db+)} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 105 (public+)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (public+), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (public+), Name: "public"} + │ │ └── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (public+), Name: "root"} + │ └── 1 Mutation operation + │ └── UndoAllInTxnImmediateMutationOpSideEffects + └── Stage 2 of 2 in PreCommitPhase + ├── 14 elements transitioning toward PUBLIC + │ ├── ABSENT → PUBLIC Database:{DescID: 104 (db+)} + │ ├── ABSENT → PUBLIC Namespace:{DescID: 104 (db+), Name: "db"} + │ ├── ABSENT → PUBLIC DatabaseData:{DescID: 104 (db+)} + │ ├── ABSENT → PUBLIC Owner:{DescID: 104 (db+)} + │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 104 (db+), Name: "admin"} + │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 104 (db+), Name: "public"} + │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 104 (db+), Name: "root"} + │ ├── ABSENT → PUBLIC Schema:{DescID: 105 (public+)} + │ ├── ABSENT → PUBLIC Namespace:{DescID: 105 (public+), Name: "public", ReferencedDescID: 104 (db+)} + │ ├── ABSENT → PUBLIC SchemaParent:{DescID: 105 (public+), ReferencedDescID: 104 (db+)} + │ ├── ABSENT → PUBLIC Owner:{DescID: 105 (public+)} + │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (public+), Name: "admin"} + │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (public+), Name: "public"} + │ └── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (public+), Name: "root"} + └── 17 Mutation operations + ├── CreateDatabaseDescriptor {"DatabaseID":104} + ├── SetNameInDescriptor {"DescriptorID":104,"Name":"db"} + ├── AddDescriptorName {"Namespace":{"DescriptorID":104,"Name":"db"}} + ├── UpdateOwner {"Owner":{"DescriptorID":104,"Owner":"root"}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":104,"Privileges":2,"UserName":"admin","WithGrantOption":2}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":104,"Privileges":2048,"UserName":"public"}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":104,"Privileges":2,"UserName":"root","WithGrantOption":2}} + ├── CreateSchemaDescriptor {"SchemaID":105} + ├── SetNameInDescriptor {"DescriptorID":105,"Name":"public"} + ├── AddDescriptorName {"Namespace":{"DatabaseID":104,"DescriptorID":105,"Name":"public"}} + ├── AddSchemaParent {"Parent":{"ParentDatabaseID":104,"SchemaID":105}} + ├── UpdateOwner {"Owner":{"DescriptorID":105,"Owner":"admin"}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":2,"UserName":"admin","WithGrantOption":2}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":516,"UserName":"public"}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":2,"UserName":"root","WithGrantOption":2}} + ├── MarkDescriptorAsPublic {"DescriptorID":104} + └── MarkDescriptorAsPublic {"DescriptorID":105} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_1_of_3.explain_shape b/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_1_of_3.explain_shape new file mode 100644 index 000000000000..1db22d633344 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_1_of_3.explain_shape @@ -0,0 +1,7 @@ +/* setup */ + +/* test */ +EXPLAIN (DDL, SHAPE) CREATE DATABASE db; +---- +Schema change plan for CREATE DATABASE ‹db›; + └── execute 1 system table mutations transaction diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_2_of_3.explain b/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_2_of_3.explain new file mode 100644 index 000000000000..01cc9b8c1c75 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_2_of_3.explain @@ -0,0 +1,52 @@ +/* setup */ + +/* test */ +CREATE DATABASE db; +EXPLAIN (DDL) DROP DATABASE db; +---- +Schema change plan for DROP DATABASE ‹db›; following CREATE DATABASE ‹db›; + ├── StatementPhase + │ └── Stage 1 of 1 in StatementPhase + │ ├── 14 elements transitioning toward ABSENT + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 104 (db-), Name: "db"} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 104 (db-)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 104 (db-), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 104 (db-), Name: "public"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 104 (db-), Name: "root"} + │ │ ├── PUBLIC → DROPPED Database:{DescID: 104 (db-)} + │ │ ├── PUBLIC → ABSENT DatabaseRoleSetting:{DescID: 104 (db-), Name: "__placeholder_role_name__"} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 105 (public-), Name: "public", ReferencedDescID: 104 (db-)} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 105 (public-)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (public-), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (public-), Name: "public"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (public-), Name: "root"} + │ │ ├── PUBLIC → DROPPED Schema:{DescID: 105 (public-)} + │ │ └── PUBLIC → ABSENT SchemaParent:{DescID: 105 (public-), ReferencedDescID: 104 (db-)} + │ └── 13 Mutation operations + │ ├── MarkDescriptorAsDropped {"DescriptorID":105} + │ ├── RemoveSchemaParent {"Parent":{"ParentDatabaseID":104,"SchemaID":105}} + │ ├── MarkDescriptorAsDropped {"DescriptorID":104} + │ ├── DrainDescriptorName {"Namespace":{"DatabaseID":104,"DescriptorID":105,"Name":"public"}} + │ ├── NotImplementedForPublicObjects {"DescID":105,"ElementType":"scpb.Owner"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"admin"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"public"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"root"} + │ ├── DrainDescriptorName {"Namespace":{"DescriptorID":104,"Name":"db"}} + │ ├── NotImplementedForPublicObjects {"DescID":104,"ElementType":"scpb.Owner"} + │ ├── RemoveUserPrivileges {"DescriptorID":104,"User":"admin"} + │ ├── RemoveUserPrivileges {"DescriptorID":104,"User":"public"} + │ └── RemoveUserPrivileges {"DescriptorID":104,"User":"root"} + └── PreCommitPhase + ├── Stage 1 of 2 in PreCommitPhase + │ ├── 4 elements transitioning toward ABSENT + │ │ ├── DROPPED → ABSENT Database:{DescID: 104 (db-)} + │ │ ├── ABSENT → PUBLIC DatabaseRoleSetting:{DescID: 104 (db-), Name: "__placeholder_role_name__"} + │ │ ├── PUBLIC → ABSENT DatabaseData:{DescID: 104 (db-)} + │ │ └── DROPPED → ABSENT Schema:{DescID: 105 (public-)} + │ └── 1 Mutation operation + │ └── UndoAllInTxnImmediateMutationOpSideEffects + └── Stage 2 of 2 in PreCommitPhase + ├── 1 element transitioning toward ABSENT + │ └── PUBLIC → ABSENT DatabaseRoleSetting:{DescID: 104 (db-), Name: "__placeholder_role_name__"} + └── 1 Mutation operation + └── RemoveDatabaseRoleSettings {"DatabaseID":104} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_2_of_3.explain_shape b/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_2_of_3.explain_shape new file mode 100644 index 000000000000..3d75db61fd9f --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_2_of_3.explain_shape @@ -0,0 +1,8 @@ +/* setup */ + +/* test */ +CREATE DATABASE db; +EXPLAIN (DDL, SHAPE) DROP DATABASE db; +---- +Schema change plan for DROP DATABASE ‹db›; following CREATE DATABASE ‹db›; + └── execute 1 system table mutations transaction diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_3_of_3.explain b/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_3_of_3.explain new file mode 100644 index 000000000000..5e61ec7a05e0 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_3_of_3.explain @@ -0,0 +1,104 @@ +/* setup */ + +/* test */ +CREATE DATABASE db; +DROP DATABASE db; +EXPLAIN (DDL) CREATE DATABASE db; +---- +Schema change plan for CREATE DATABASE ‹db›; following CREATE DATABASE ‹db›; DROP DATABASE ‹db›; + ├── StatementPhase + │ └── Stage 1 of 1 in StatementPhase + │ ├── 14 elements transitioning toward PUBLIC + │ │ ├── ABSENT → PUBLIC Database:{DescID: 106 (db+)} + │ │ ├── ABSENT → PUBLIC Namespace:{DescID: 106 (db+), Name: "db"} + │ │ ├── ABSENT → PUBLIC DatabaseData:{DescID: 106 (db+)} + │ │ ├── ABSENT → PUBLIC Owner:{DescID: 106 (db+)} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 106 (db+), Name: "admin"} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 106 (db+), Name: "public"} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 106 (db+), Name: "root"} + │ │ ├── ABSENT → PUBLIC Schema:{DescID: 107 (public+)} + │ │ ├── ABSENT → PUBLIC Namespace:{DescID: 107 (public+), Name: "public", ReferencedDescID: 106 (db+)} + │ │ ├── ABSENT → PUBLIC SchemaParent:{DescID: 107 (public+), ReferencedDescID: 106 (db+)} + │ │ ├── ABSENT → PUBLIC Owner:{DescID: 107 (public+)} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 107 (public+), Name: "admin"} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 107 (public+), Name: "public"} + │ │ └── ABSENT → PUBLIC UserPrivileges:{DescID: 107 (public+), Name: "root"} + │ └── 17 Mutation operations + │ ├── CreateDatabaseDescriptor {"DatabaseID":106} + │ ├── SetNameInDescriptor {"DescriptorID":106,"Name":"db"} + │ ├── AddDescriptorName {"Namespace":{"DescriptorID":106,"Name":"db"}} + │ ├── UpdateOwner {"Owner":{"DescriptorID":106,"Owner":"root"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":106,"Privileges":2,"UserName":"admin","WithGrantOption":2}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":106,"Privileges":2048,"UserName":"public"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":106,"Privileges":2,"UserName":"root","WithGrantOption":2}} + │ ├── CreateSchemaDescriptor {"SchemaID":107} + │ ├── SetNameInDescriptor {"DescriptorID":107,"Name":"public"} + │ ├── AddDescriptorName {"Namespace":{"DatabaseID":106,"DescriptorID":107,"Name":"public"}} + │ ├── AddSchemaParent {"Parent":{"ParentDatabaseID":106,"SchemaID":107}} + │ ├── UpdateOwner {"Owner":{"DescriptorID":107,"Owner":"admin"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":107,"Privileges":2,"UserName":"admin","WithGrantOption":2}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":107,"Privileges":516,"UserName":"public"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":107,"Privileges":2,"UserName":"root","WithGrantOption":2}} + │ ├── MarkDescriptorAsPublic {"DescriptorID":106} + │ └── MarkDescriptorAsPublic {"DescriptorID":107} + └── PreCommitPhase + ├── Stage 1 of 2 in PreCommitPhase + │ ├── 14 elements transitioning toward PUBLIC + │ │ ├── PUBLIC → ABSENT Database:{DescID: 106 (db+)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 106 (db+), Name: "db"} + │ │ ├── PUBLIC → ABSENT DatabaseData:{DescID: 106 (db+)} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 106 (db+)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (db+), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (db+), Name: "public"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (db+), Name: "root"} + │ │ ├── PUBLIC → ABSENT Schema:{DescID: 107 (public+)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 107 (public+), Name: "public", ReferencedDescID: 106 (db+)} + │ │ ├── PUBLIC → ABSENT SchemaParent:{DescID: 107 (public+), ReferencedDescID: 106 (db+)} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 107 (public+)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 107 (public+), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 107 (public+), Name: "public"} + │ │ └── PUBLIC → ABSENT UserPrivileges:{DescID: 107 (public+), Name: "root"} + │ ├── 4 elements transitioning toward ABSENT + │ │ ├── DROPPED → ABSENT Database:{DescID: 104 (db-)} + │ │ ├── ABSENT → PUBLIC DatabaseRoleSetting:{DescID: 104 (db-), Name: "__placeholder_role_name__"} + │ │ ├── PUBLIC → ABSENT DatabaseData:{DescID: 104 (db-)} + │ │ └── DROPPED → ABSENT Schema:{DescID: 105 (public-)} + │ └── 1 Mutation operation + │ └── UndoAllInTxnImmediateMutationOpSideEffects + └── Stage 2 of 2 in PreCommitPhase + ├── 14 elements transitioning toward PUBLIC + │ ├── ABSENT → PUBLIC Database:{DescID: 106 (db+)} + │ ├── ABSENT → PUBLIC Namespace:{DescID: 106 (db+), Name: "db"} + │ ├── ABSENT → PUBLIC DatabaseData:{DescID: 106 (db+)} + │ ├── ABSENT → PUBLIC Owner:{DescID: 106 (db+)} + │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 106 (db+), Name: "admin"} + │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 106 (db+), Name: "public"} + │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 106 (db+), Name: "root"} + │ ├── ABSENT → PUBLIC Schema:{DescID: 107 (public+)} + │ ├── ABSENT → PUBLIC Namespace:{DescID: 107 (public+), Name: "public", ReferencedDescID: 106 (db+)} + │ ├── ABSENT → PUBLIC SchemaParent:{DescID: 107 (public+), ReferencedDescID: 106 (db+)} + │ ├── ABSENT → PUBLIC Owner:{DescID: 107 (public+)} + │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 107 (public+), Name: "admin"} + │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 107 (public+), Name: "public"} + │ └── ABSENT → PUBLIC UserPrivileges:{DescID: 107 (public+), Name: "root"} + ├── 1 element transitioning toward ABSENT + │ └── PUBLIC → ABSENT DatabaseRoleSetting:{DescID: 104 (db-), Name: "__placeholder_role_name__"} + └── 18 Mutation operations + ├── RemoveDatabaseRoleSettings {"DatabaseID":104} + ├── CreateDatabaseDescriptor {"DatabaseID":106} + ├── SetNameInDescriptor {"DescriptorID":106,"Name":"db"} + ├── AddDescriptorName {"Namespace":{"DescriptorID":106,"Name":"db"}} + ├── UpdateOwner {"Owner":{"DescriptorID":106,"Owner":"root"}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":106,"Privileges":2,"UserName":"admin","WithGrantOption":2}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":106,"Privileges":2048,"UserName":"public"}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":106,"Privileges":2,"UserName":"root","WithGrantOption":2}} + ├── CreateSchemaDescriptor {"SchemaID":107} + ├── SetNameInDescriptor {"DescriptorID":107,"Name":"public"} + ├── AddDescriptorName {"Namespace":{"DatabaseID":106,"DescriptorID":107,"Name":"public"}} + ├── AddSchemaParent {"Parent":{"ParentDatabaseID":106,"SchemaID":107}} + ├── UpdateOwner {"Owner":{"DescriptorID":107,"Owner":"admin"}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":107,"Privileges":2,"UserName":"admin","WithGrantOption":2}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":107,"Privileges":516,"UserName":"public"}} + ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":107,"Privileges":2,"UserName":"root","WithGrantOption":2}} + ├── MarkDescriptorAsPublic {"DescriptorID":106} + └── MarkDescriptorAsPublic {"DescriptorID":107} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_3_of_3.explain_shape b/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_3_of_3.explain_shape new file mode 100644 index 000000000000..2e6c6d63d284 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_database_drop_database_separate_statements/create_database_drop_database_separate_statements__statement_3_of_3.explain_shape @@ -0,0 +1,9 @@ +/* setup */ + +/* test */ +CREATE DATABASE db; +DROP DATABASE db; +EXPLAIN (DDL, SHAPE) CREATE DATABASE db; +---- +Schema change plan for CREATE DATABASE ‹db›; following CREATE DATABASE ‹db›; DROP DATABASE ‹db›; + └── execute 1 system table mutations transaction diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements.definition b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements.definition new file mode 100644 index 000000000000..96f5b5c5edb8 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements.definition @@ -0,0 +1,9 @@ +setup +CREATE TABLE t (i INT PRIMARY KEY, j INT NOT NULL); +INSERT INTO t SELECT val, val+1 FROM generate_series(1,10) AS temp(val); +---- + +test +CREATE UNIQUE INDEX idx ON t(j) WHERE (i > 0); +CREATE DATABASE db; +---- diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements.side_effects b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements.side_effects new file mode 100644 index 000000000000..8a71faf92b48 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements.side_effects @@ -0,0 +1,690 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j INT NOT NULL); +INSERT INTO t SELECT val, val+1 FROM generate_series(1,10) AS temp(val); +---- +... ++object {100 101 t} -> 104 + +/* test */ +CREATE UNIQUE INDEX idx ON t(j) WHERE (i > 0); +CREATE DATABASE db; +---- +begin transaction #1 +# begin StatementPhase +checking for feature: CREATE INDEX +increment telemetry for sql.schema.create_index +increment telemetry for sql.schema.partial_index +write *eventpb.CreateIndex to event log: + indexName: idx + mutationId: 1 + sql: + descriptorId: 104 + statement: CREATE UNIQUE INDEX ‹idx› ON ‹defaultdb›.‹public›.‹t› (‹j›) WHERE (‹i› > ‹0›) + tag: CREATE INDEX + user: root + tableName: defaultdb.public.t +## StatementPhase stage 1 of 1 with 9 MutationType ops +upsert descriptor #104 + ... + id: 104 + modificationTime: {} + + mutations: + + - direction: ADD + + index: + + constraintId: 2 + + createdAtNanos: "1640998800000000000" + + createdExplicitly: true + + foreignKey: {} + + geoConfig: {} + + id: 2 + + interleave: {} + + keyColumnDirections: + + - ASC + + keyColumnIds: + + - 2 + + keyColumnNames: + + - j + + keySuffixColumnIds: + + - 1 + + name: idx + + partitioning: {} + + predicate: i > 0:::INT8 + + sharded: {} + + storeColumnNames: [] + + unique: true + + version: 4 + + mutationId: 1 + + state: BACKFILLING + + - direction: ADD + + index: + + constraintId: 3 + + createdExplicitly: true + + foreignKey: {} + + geoConfig: {} + + id: 3 + + interleave: {} + + keyColumnDirections: + + - ASC + + keyColumnIds: + + - 2 + + keyColumnNames: + + - j + + keySuffixColumnIds: + + - 1 + + name: crdb_internal_index_3_name_placeholder + + partitioning: {} + + predicate: i > 0:::INT8 + + sharded: {} + + storeColumnNames: [] + + unique: true + + useDeletePreservingEncoding: true + + version: 4 + + mutationId: 1 + + state: DELETE_ONLY + name: t + nextColumnId: 3 + - nextConstraintId: 2 + + nextConstraintId: 4 + nextFamilyId: 1 + - nextIndexId: 2 + + nextIndexId: 4 + nextMutationId: 1 + parentId: 100 + ... + time: {} + unexposedParentSchemaId: 101 + - version: "1" + + version: "2" +checking for feature: CREATE DATABASE +checking current user "root" has system privilege "CREATEDB" or the corresponding legacy role option +increment telemetry for sql.schema.create_database +checking role/user "root" exists +write *eventpb.CreateDatabase to event log: + databaseName: db + sql: + descriptorId: 105 + statement: CREATE DATABASE ‹db› + tag: CREATE DATABASE + user: root +## StatementPhase stage 1 of 1 with 17 MutationType ops +add database namespace entry {0 0 db} -> 105 +add schema namespace entry {105 0 public} -> 106 +upsert descriptor #105 + - + +database: + + defaultPrivileges: {} + + id: 105 + + modificationTime: {} + + name: db + + privileges: + + ownerProto: root + + users: + + - privileges: "2" + + userProto: admin + + withGrantOption: "2" + + - privileges: "2048" + + userProto: public + + - privileges: "2" + + userProto: root + + withGrantOption: "2" + + version: 3 + + schemas: + + public: + + id: 106 + + version: "1" +upsert descriptor #106 + - + +schema: + + id: 106 + + modificationTime: {} + + name: public + + parentId: 105 + + privileges: + + ownerProto: admin + + users: + + - privileges: "2" + + userProto: admin + + withGrantOption: "2" + + - privileges: "516" + + userProto: public + + - privileges: "2" + + userProto: root + + withGrantOption: "2" + + version: 3 + + version: "1" +# 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 30 MutationType ops +add database namespace entry {0 0 db} -> 105 +add schema namespace entry {105 0 public} -> 106 +upsert descriptor #105 + - + +database: + + declarativeSchemaChangerState: + + authorization: + + userName: root + + currentStatuses: + + jobId: "1" + + nameMapping: + + id: 105 + + name: db + + relevantStatements: + + - statement: + + redactedStatement: CREATE DATABASE ‹db› + + statement: CREATE DATABASE db + + statementTag: CREATE DATABASE + + statementRank: 1 + + revertible: true + + targetRanks: + + targets: + + defaultPrivileges: {} + + id: 105 + + modificationTime: {} + + name: db + + privileges: + + ownerProto: root + + users: + + - privileges: "2" + + userProto: admin + + withGrantOption: "2" + + - privileges: "2048" + + userProto: public + + - privileges: "2" + + userProto: root + + withGrantOption: "2" + + version: 3 + + schemas: + + public: + + id: 106 + + state: ADD + + version: "1" +upsert descriptor #106 + - + +schema: + + declarativeSchemaChangerState: + + authorization: + + userName: root + + currentStatuses: + + jobId: "1" + + nameMapping: + + id: 106 + + name: public + + relevantStatements: + + - statement: + + redactedStatement: CREATE DATABASE ‹db› + + statement: CREATE DATABASE db + + statementTag: CREATE DATABASE + + statementRank: 1 + + revertible: true + + targetRanks: + + targets: + + id: 106 + + modificationTime: {} + + name: public + + parentId: 105 + + privileges: + + ownerProto: admin + + users: + + - privileges: "2" + + userProto: admin + + withGrantOption: "2" + + - privileges: "516" + + userProto: public + + - privileges: "2" + + userProto: root + + withGrantOption: "2" + + version: 3 + + state: ADD + + version: "1" +upsert descriptor #104 + ... + 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 + + "2": idx + + "3": crdb_internal_index_3_name_placeholder + + name: t + + relevantStatements: + + - statement: + + redactedStatement: CREATE UNIQUE INDEX ‹idx› ON ‹defaultdb›.‹public›.‹t› (‹j›) WHERE (‹i› > ‹0›) + + statement: CREATE UNIQUE INDEX idx ON t (j) WHERE (i > 0) + + statementTag: CREATE INDEX + + revertible: true + + targetRanks: + + targets: + families: + - columnIds: + ... + id: 104 + modificationTime: {} + + mutations: + + - direction: ADD + + index: + + constraintId: 2 + + createdAtNanos: "1640998800000000000" + + createdExplicitly: true + + foreignKey: {} + + geoConfig: {} + + id: 2 + + interleave: {} + + keyColumnDirections: + + - ASC + + keyColumnIds: + + - 2 + + keyColumnNames: + + - j + + keySuffixColumnIds: + + - 1 + + name: idx + + partitioning: {} + + predicate: i > 0:::INT8 + + sharded: {} + + storeColumnNames: [] + + unique: true + + version: 4 + + mutationId: 1 + + state: BACKFILLING + + - direction: ADD + + index: + + constraintId: 3 + + createdExplicitly: true + + foreignKey: {} + + geoConfig: {} + + id: 3 + + interleave: {} + + keyColumnDirections: + + - ASC + + keyColumnIds: + + - 2 + + keyColumnNames: + + - j + + keySuffixColumnIds: + + - 1 + + name: crdb_internal_index_3_name_placeholder + + partitioning: {} + + predicate: i > 0:::INT8 + + sharded: {} + + storeColumnNames: [] + + unique: true + + useDeletePreservingEncoding: true + + version: 4 + + mutationId: 1 + + state: DELETE_ONLY + name: t + nextColumnId: 3 + - nextConstraintId: 2 + + nextConstraintId: 4 + nextFamilyId: 1 + - nextIndexId: 2 + + nextIndexId: 4 + nextMutationId: 1 + parentId: 100 + ... + time: {} + unexposedParentSchemaId: 101 + - version: "1" + + version: "2" +persist all catalog changes to storage +create job #1 (non-cancelable: false): "CREATE UNIQUE INDEX idx ON defaultdb.public.t (j) WHERE (i > 0); CREATE DATABASE db" + descriptor IDs: [104 105 106] +# end PreCommitPhase +commit transaction #1 +notified job registry to adopt jobs: [1] +# begin PostCommitPhase +begin transaction #2 +commit transaction #2 +begin transaction #3 +## PostCommitPhase stage 1 of 7 with 5 MutationType ops +upsert descriptor #104 + ... + version: 4 + mutationId: 1 + - state: DELETE_ONLY + + state: WRITE_ONLY + name: t + nextColumnId: 3 + ... + time: {} + unexposedParentSchemaId: 101 + - version: "2" + + version: "3" +upsert descriptor #105 + ... + id: 106 + state: ADD + - version: "1" + + version: "2" +upsert descriptor #106 + ... + version: 3 + state: ADD + - version: "1" + + version: "2" +persist all catalog changes to storage +update progress of schema change job #1: "PostCommitPhase stage 2 of 7 with 1 BackfillType op pending" +commit transaction #3 +begin transaction #4 +## PostCommitPhase stage 2 of 7 with 1 BackfillType op +backfill indexes [2] from index #1 in table #104 +commit transaction #4 +begin transaction #5 +## PostCommitPhase stage 3 of 7 with 5 MutationType ops +upsert descriptor #104 + ... + version: 4 + mutationId: 1 + - state: BACKFILLING + + state: DELETE_ONLY + - direction: ADD + index: + ... + time: {} + unexposedParentSchemaId: 101 + - version: "3" + + version: "4" +upsert descriptor #105 + ... + id: 106 + state: ADD + - version: "2" + + version: "3" +upsert descriptor #106 + ... + version: 3 + state: ADD + - version: "2" + + version: "3" +persist all catalog changes to storage +update progress of schema change job #1: "PostCommitPhase stage 4 of 7 with 1 MutationType op pending" +commit transaction #5 +begin transaction #6 +## PostCommitPhase stage 4 of 7 with 5 MutationType ops +upsert descriptor #104 + ... + version: 4 + mutationId: 1 + - state: DELETE_ONLY + + state: MERGING + - direction: ADD + index: + ... + time: {} + unexposedParentSchemaId: 101 + - version: "4" + + version: "5" +upsert descriptor #105 + ... + id: 106 + state: ADD + - version: "3" + + version: "4" +upsert descriptor #106 + ... + version: 3 + state: ADD + - version: "3" + + version: "4" +persist all catalog changes to storage +update progress of schema change job #1: "PostCommitPhase stage 5 of 7 with 1 BackfillType op pending" +commit transaction #6 +begin transaction #7 +## PostCommitPhase stage 5 of 7 with 1 BackfillType op +merge temporary indexes [3] into backfilled indexes [2] in table #104 +commit transaction #7 +begin transaction #8 +## PostCommitPhase stage 6 of 7 with 6 MutationType ops +upsert descriptor #104 + ... + version: 4 + mutationId: 1 + - state: MERGING + - - direction: ADD + + state: WRITE_ONLY + + - direction: DROP + index: + constraintId: 3 + ... + version: 4 + mutationId: 1 + - state: WRITE_ONLY + + state: DELETE_ONLY + name: t + nextColumnId: 3 + ... + time: {} + unexposedParentSchemaId: 101 + - version: "5" + + version: "6" +upsert descriptor #105 + ... + id: 106 + state: ADD + - version: "4" + + version: "5" +upsert descriptor #106 + ... + version: 3 + state: ADD + - version: "4" + + version: "5" +persist all catalog changes to storage +update progress of schema change job #1: "PostCommitPhase stage 7 of 7 with 1 ValidationType op pending" +commit transaction #8 +begin transaction #9 +## PostCommitPhase stage 7 of 7 with 1 ValidationType op +validate forward indexes [2] in table #104 +commit transaction #9 +begin transaction #10 +## PostCommitNonRevertiblePhase stage 1 of 1 with 12 MutationType ops +upsert descriptor #104 + ... + 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 + - "2": idx + - "3": crdb_internal_index_3_name_placeholder + - name: t + - relevantStatements: + - - statement: + - redactedStatement: CREATE UNIQUE INDEX ‹idx› ON ‹defaultdb›.‹public›.‹t› (‹j›) WHERE (‹i› > ‹0›) + - statement: CREATE UNIQUE INDEX idx ON t (j) WHERE (i > 0) + - statementTag: CREATE INDEX + - revertible: true + - targetRanks: + - targets: + families: + - columnIds: + ... + formatVersion: 3 + id: 104 + + indexes: + + - constraintId: 2 + + createdAtNanos: "1640998800000000000" + + createdExplicitly: true + + foreignKey: {} + + geoConfig: {} + + id: 2 + + interleave: {} + + keyColumnDirections: + + - ASC + + keyColumnIds: + + - 2 + + keyColumnNames: + + - j + + keySuffixColumnIds: + + - 1 + + name: idx + + partitioning: {} + + predicate: i > 0:::INT8 + + sharded: {} + + storeColumnNames: [] + + unique: true + + version: 4 + modificationTime: {} + - mutations: + - - direction: ADD + - index: + - constraintId: 2 + - createdAtNanos: "1640998800000000000" + - createdExplicitly: true + - foreignKey: {} + - geoConfig: {} + - id: 2 + - interleave: {} + - keyColumnDirections: + - - ASC + - keyColumnIds: + - - 2 + - keyColumnNames: + - - j + - keySuffixColumnIds: + - - 1 + - name: idx + - partitioning: {} + - predicate: i > 0:::INT8 + - sharded: {} + - storeColumnNames: [] + - unique: true + - version: 4 + - mutationId: 1 + - state: WRITE_ONLY + - - direction: DROP + - index: + - constraintId: 3 + - createdExplicitly: true + - foreignKey: {} + - geoConfig: {} + - id: 3 + - interleave: {} + - keyColumnDirections: + - - ASC + - keyColumnIds: + - - 2 + - keyColumnNames: + - - j + - keySuffixColumnIds: + - - 1 + - name: crdb_internal_index_3_name_placeholder + - partitioning: {} + - predicate: i > 0:::INT8 + - sharded: {} + - storeColumnNames: [] + - unique: true + - useDeletePreservingEncoding: true + - version: 4 + - mutationId: 1 + - state: DELETE_ONLY + + mutations: [] + name: t + nextColumnId: 3 + ... + time: {} + unexposedParentSchemaId: 101 + - version: "6" + + version: "7" +upsert descriptor #105 + database: + - declarativeSchemaChangerState: + - authorization: + - userName: root + - currentStatuses: + - jobId: "1" + - nameMapping: + - id: 105 + - name: db + - relevantStatements: + - - statement: + - redactedStatement: CREATE DATABASE ‹db› + - statement: CREATE DATABASE db + - statementTag: CREATE DATABASE + - statementRank: 1 + - revertible: true + - targetRanks: + - targets: + defaultPrivileges: {} + id: 105 + ... + public: + id: 106 + - state: ADD + - version: "5" + + version: "6" +upsert descriptor #106 + schema: + - declarativeSchemaChangerState: + - authorization: + - userName: root + - currentStatuses: + - jobId: "1" + - nameMapping: + - id: 106 + - name: public + - relevantStatements: + - - statement: + - redactedStatement: CREATE DATABASE ‹db› + - statement: CREATE DATABASE db + - statementTag: CREATE DATABASE + - statementRank: 1 + - revertible: true + - targetRanks: + - targets: + id: 106 + modificationTime: {} + ... + withGrantOption: "2" + version: 3 + - state: ADD + - version: "5" + + version: "6" +persist all catalog changes to storage +adding table for stats refresh: 104 +create job #2 (non-cancelable: true): "GC for CREATE UNIQUE INDEX idx ON defaultdb.public.t (j) WHERE (i > 0)" + descriptor IDs: [104] +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 +write *eventpb.FinishSchemaChange to event log: + sc: + descriptorId: 105 +write *eventpb.FinishSchemaChange to event log: + sc: + descriptorId: 106 +commit transaction #10 +notified job registry to adopt jobs: [2] +# end PostCommitPhase diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_1_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_1_of_7.explain new file mode 100644 index 000000000000..acc4eb831750 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_1_of_7.explain @@ -0,0 +1,75 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j INT NOT NULL); +INSERT INTO t SELECT val, val+1 FROM generate_series(1,10) AS temp(val); + +/* test */ +CREATE UNIQUE INDEX idx ON t(j) WHERE (i > 0); +CREATE DATABASE db; +EXPLAIN (DDL) rollback at post-commit stage 1 of 7; +---- +Schema change plan for rolling back CREATE DATABASE ‹db›; following CREATE UNIQUE INDEX ‹idx› ON ‹defaultdb›.public.‹t› (‹j›) WHERE (‹i› > ‹0›); + └── PostCommitNonRevertiblePhase + ├── Stage 1 of 2 in PostCommitNonRevertiblePhase + │ ├── 22 elements transitioning toward ABSENT + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexName:{DescID: 104 (t), Name: "idx", IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexData:{DescID: 104 (t), IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ ├── BACKFILL_ONLY → ABSENT SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx-), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey)} + │ │ ├── DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder), ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ │ ├── DESCRIPTOR_ADDED → DROPPED Database:{DescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 105 (db-), Name: "db"} + │ │ ├── PUBLIC → ABSENT DatabaseRoleSetting:{DescID: 105 (db-), Name: "__placeholder_role_name__"} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "public"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "root"} + │ │ ├── DESCRIPTOR_ADDED → DROPPED Schema:{DescID: 106 (public-)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 106 (public-), Name: "public", ReferencedDescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT SchemaParent:{DescID: 106 (public-), ReferencedDescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 106 (public-)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "public"} + │ │ └── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "root"} + │ └── 26 Mutation operations + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"Kind":1,"TableID":104} + │ ├── MakeIndexAbsent {"IndexID":3,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":2,"Kind":1,"TableID":104} + │ ├── SetIndexName {"IndexID":2,"Name":"crdb_internal_in...","TableID":104} + │ ├── MakeIndexAbsent {"IndexID":2,"TableID":104} + │ ├── MarkDescriptorAsDropped {"DescriptorID":106} + │ ├── RemoveSchemaParent {"Parent":{"ParentDatabaseID":105,"SchemaID":106}} + │ ├── NotImplementedForPublicObjects {"DescID":106,"ElementType":"scpb.Owner"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"admin"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"public"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"root"} + │ ├── CreateGCJobForIndex {"IndexID":2,"TableID":104} + │ ├── MarkDescriptorAsDropped {"DescriptorID":105} + │ ├── DrainDescriptorName {"Namespace":{"DescriptorID":105,"Name":"db"}} + │ ├── RemoveDatabaseRoleSettings {"DatabaseID":105} + │ ├── NotImplementedForPublicObjects {"DescID":105,"ElementType":"scpb.Owner"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"admin"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"public"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"root"} + │ ├── DrainDescriptorName {"Namespace":{"DatabaseID":105,"DescriptorID":106,"Name":"public"}} + │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ ├── SetJobStateOnDescriptor {"DescriptorID":105} + │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"PostCommitNonRev..."} + └── Stage 2 of 2 in PostCommitNonRevertiblePhase + ├── 3 elements transitioning toward ABSENT + │ ├── DROPPED → ABSENT Database:{DescID: 105 (db-)} + │ ├── PUBLIC → ABSENT DatabaseData:{DescID: 105 (db-)} + │ └── DROPPED → ABSENT Schema:{DescID: 106 (public-)} + └── 7 Mutation operations + ├── DeleteDescriptor {"DescriptorID":105} + ├── CreateGCJobForDatabase {"DatabaseID":105} + ├── DeleteDescriptor {"DescriptorID":106} + ├── RemoveJobStateFromDescriptor {"DescriptorID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":105} + ├── RemoveJobStateFromDescriptor {"DescriptorID":106} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_2_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_2_of_7.explain new file mode 100644 index 000000000000..3870d11424e3 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_2_of_7.explain @@ -0,0 +1,79 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j INT NOT NULL); +INSERT INTO t SELECT val, val+1 FROM generate_series(1,10) AS temp(val); + +/* test */ +CREATE UNIQUE INDEX idx ON t(j) WHERE (i > 0); +CREATE DATABASE db; +EXPLAIN (DDL) rollback at post-commit stage 2 of 7; +---- +Schema change plan for rolling back CREATE DATABASE ‹db›; following CREATE UNIQUE INDEX ‹idx› ON ‹defaultdb›.public.‹t› (‹j›) WHERE (‹i› > ‹0›); + └── PostCommitNonRevertiblePhase + ├── Stage 1 of 2 in PostCommitNonRevertiblePhase + │ ├── 21 elements transitioning toward ABSENT + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexName:{DescID: 104 (t), Name: "idx", IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ ├── BACKFILL_ONLY → ABSENT SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx-), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey)} + │ │ ├── WRITE_ONLY → DELETE_ONLY TemporaryIndex:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder), ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ │ ├── DESCRIPTOR_ADDED → DROPPED Database:{DescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 105 (db-), Name: "db"} + │ │ ├── PUBLIC → ABSENT DatabaseRoleSetting:{DescID: 105 (db-), Name: "__placeholder_role_name__"} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "public"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "root"} + │ │ ├── DESCRIPTOR_ADDED → DROPPED Schema:{DescID: 106 (public-)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 106 (public-), Name: "public", ReferencedDescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT SchemaParent:{DescID: 106 (public-), ReferencedDescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 106 (public-)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "public"} + │ │ └── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "root"} + │ └── 25 Mutation operations + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":2,"Kind":1,"TableID":104} + │ ├── SetIndexName {"IndexID":2,"Name":"crdb_internal_in...","TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"Kind":1,"TableID":104} + │ ├── MakeIndexAbsent {"IndexID":2,"TableID":104} + │ ├── MarkDescriptorAsDropped {"DescriptorID":106} + │ ├── RemoveSchemaParent {"Parent":{"ParentDatabaseID":105,"SchemaID":106}} + │ ├── NotImplementedForPublicObjects {"DescID":106,"ElementType":"scpb.Owner"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"admin"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"public"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"root"} + │ ├── MarkDescriptorAsDropped {"DescriptorID":105} + │ ├── DrainDescriptorName {"Namespace":{"DescriptorID":105,"Name":"db"}} + │ ├── RemoveDatabaseRoleSettings {"DatabaseID":105} + │ ├── NotImplementedForPublicObjects {"DescID":105,"ElementType":"scpb.Owner"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"admin"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"public"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"root"} + │ ├── DrainDescriptorName {"Namespace":{"DatabaseID":105,"DescriptorID":106,"Name":"public"}} + │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ ├── SetJobStateOnDescriptor {"DescriptorID":105} + │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"PostCommitNonRev..."} + └── Stage 2 of 2 in PostCommitNonRevertiblePhase + ├── 6 elements transitioning toward ABSENT + │ ├── PUBLIC → ABSENT IndexData:{DescID: 104 (t), IndexID: 2 (idx-)} + │ ├── PUBLIC → ABSENT IndexData:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ ├── DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder), ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ ├── DROPPED → ABSENT Database:{DescID: 105 (db-)} + │ ├── PUBLIC → ABSENT DatabaseData:{DescID: 105 (db-)} + │ └── DROPPED → ABSENT Schema:{DescID: 106 (public-)} + └── 10 Mutation operations + ├── CreateGCJobForIndex {"IndexID":2,"TableID":104} + ├── MakeIndexAbsent {"IndexID":3,"TableID":104} + ├── DeleteDescriptor {"DescriptorID":105} + ├── CreateGCJobForDatabase {"DatabaseID":105} + ├── DeleteDescriptor {"DescriptorID":106} + ├── CreateGCJobForIndex {"IndexID":3,"TableID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":105} + ├── RemoveJobStateFromDescriptor {"DescriptorID":106} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_3_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_3_of_7.explain new file mode 100644 index 000000000000..b8faf99524ee --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_3_of_7.explain @@ -0,0 +1,79 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j INT NOT NULL); +INSERT INTO t SELECT val, val+1 FROM generate_series(1,10) AS temp(val); + +/* test */ +CREATE UNIQUE INDEX idx ON t(j) WHERE (i > 0); +CREATE DATABASE db; +EXPLAIN (DDL) rollback at post-commit stage 3 of 7; +---- +Schema change plan for rolling back CREATE DATABASE ‹db›; following CREATE UNIQUE INDEX ‹idx› ON ‹defaultdb›.public.‹t› (‹j›) WHERE (‹i› > ‹0›); + └── PostCommitNonRevertiblePhase + ├── Stage 1 of 2 in PostCommitNonRevertiblePhase + │ ├── 21 elements transitioning toward ABSENT + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexName:{DescID: 104 (t), Name: "idx", IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ ├── BACKFILL_ONLY → ABSENT SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx-), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey)} + │ │ ├── WRITE_ONLY → DELETE_ONLY TemporaryIndex:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder), ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ │ ├── DESCRIPTOR_ADDED → DROPPED Database:{DescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 105 (db-), Name: "db"} + │ │ ├── PUBLIC → ABSENT DatabaseRoleSetting:{DescID: 105 (db-), Name: "__placeholder_role_name__"} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "public"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "root"} + │ │ ├── DESCRIPTOR_ADDED → DROPPED Schema:{DescID: 106 (public-)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 106 (public-), Name: "public", ReferencedDescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT SchemaParent:{DescID: 106 (public-), ReferencedDescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 106 (public-)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "public"} + │ │ └── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "root"} + │ └── 25 Mutation operations + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":2,"Kind":1,"TableID":104} + │ ├── SetIndexName {"IndexID":2,"Name":"crdb_internal_in...","TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"Kind":1,"TableID":104} + │ ├── MakeIndexAbsent {"IndexID":2,"TableID":104} + │ ├── MarkDescriptorAsDropped {"DescriptorID":106} + │ ├── RemoveSchemaParent {"Parent":{"ParentDatabaseID":105,"SchemaID":106}} + │ ├── NotImplementedForPublicObjects {"DescID":106,"ElementType":"scpb.Owner"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"admin"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"public"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"root"} + │ ├── MarkDescriptorAsDropped {"DescriptorID":105} + │ ├── DrainDescriptorName {"Namespace":{"DescriptorID":105,"Name":"db"}} + │ ├── RemoveDatabaseRoleSettings {"DatabaseID":105} + │ ├── NotImplementedForPublicObjects {"DescID":105,"ElementType":"scpb.Owner"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"admin"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"public"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"root"} + │ ├── DrainDescriptorName {"Namespace":{"DatabaseID":105,"DescriptorID":106,"Name":"public"}} + │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ ├── SetJobStateOnDescriptor {"DescriptorID":105} + │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"PostCommitNonRev..."} + └── Stage 2 of 2 in PostCommitNonRevertiblePhase + ├── 6 elements transitioning toward ABSENT + │ ├── PUBLIC → ABSENT IndexData:{DescID: 104 (t), IndexID: 2 (idx-)} + │ ├── PUBLIC → ABSENT IndexData:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ ├── DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder), ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ ├── DROPPED → ABSENT Database:{DescID: 105 (db-)} + │ ├── PUBLIC → ABSENT DatabaseData:{DescID: 105 (db-)} + │ └── DROPPED → ABSENT Schema:{DescID: 106 (public-)} + └── 10 Mutation operations + ├── CreateGCJobForIndex {"IndexID":2,"TableID":104} + ├── MakeIndexAbsent {"IndexID":3,"TableID":104} + ├── DeleteDescriptor {"DescriptorID":105} + ├── CreateGCJobForDatabase {"DatabaseID":105} + ├── DeleteDescriptor {"DescriptorID":106} + ├── CreateGCJobForIndex {"IndexID":3,"TableID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":105} + ├── RemoveJobStateFromDescriptor {"DescriptorID":106} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_4_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_4_of_7.explain new file mode 100644 index 000000000000..133cc5e464dd --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_4_of_7.explain @@ -0,0 +1,79 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j INT NOT NULL); +INSERT INTO t SELECT val, val+1 FROM generate_series(1,10) AS temp(val); + +/* test */ +CREATE UNIQUE INDEX idx ON t(j) WHERE (i > 0); +CREATE DATABASE db; +EXPLAIN (DDL) rollback at post-commit stage 4 of 7; +---- +Schema change plan for rolling back CREATE DATABASE ‹db›; following CREATE UNIQUE INDEX ‹idx› ON ‹defaultdb›.public.‹t› (‹j›) WHERE (‹i› > ‹0›); + └── PostCommitNonRevertiblePhase + ├── Stage 1 of 2 in PostCommitNonRevertiblePhase + │ ├── 21 elements transitioning toward ABSENT + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexName:{DescID: 104 (t), Name: "idx", IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ ├── DELETE_ONLY → ABSENT SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx-), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey)} + │ │ ├── WRITE_ONLY → DELETE_ONLY TemporaryIndex:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder), ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ │ ├── DESCRIPTOR_ADDED → DROPPED Database:{DescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 105 (db-), Name: "db"} + │ │ ├── PUBLIC → ABSENT DatabaseRoleSetting:{DescID: 105 (db-), Name: "__placeholder_role_name__"} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "public"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "root"} + │ │ ├── DESCRIPTOR_ADDED → DROPPED Schema:{DescID: 106 (public-)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 106 (public-), Name: "public", ReferencedDescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT SchemaParent:{DescID: 106 (public-), ReferencedDescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 106 (public-)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "public"} + │ │ └── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "root"} + │ └── 25 Mutation operations + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":2,"Kind":1,"TableID":104} + │ ├── SetIndexName {"IndexID":2,"Name":"crdb_internal_in...","TableID":104} + │ ├── MakeIndexAbsent {"IndexID":2,"TableID":104} + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"Kind":1,"TableID":104} + │ ├── MarkDescriptorAsDropped {"DescriptorID":106} + │ ├── RemoveSchemaParent {"Parent":{"ParentDatabaseID":105,"SchemaID":106}} + │ ├── NotImplementedForPublicObjects {"DescID":106,"ElementType":"scpb.Owner"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"admin"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"public"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"root"} + │ ├── MarkDescriptorAsDropped {"DescriptorID":105} + │ ├── DrainDescriptorName {"Namespace":{"DescriptorID":105,"Name":"db"}} + │ ├── RemoveDatabaseRoleSettings {"DatabaseID":105} + │ ├── NotImplementedForPublicObjects {"DescID":105,"ElementType":"scpb.Owner"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"admin"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"public"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"root"} + │ ├── DrainDescriptorName {"Namespace":{"DatabaseID":105,"DescriptorID":106,"Name":"public"}} + │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ ├── SetJobStateOnDescriptor {"DescriptorID":105} + │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"PostCommitNonRev..."} + └── Stage 2 of 2 in PostCommitNonRevertiblePhase + ├── 6 elements transitioning toward ABSENT + │ ├── PUBLIC → ABSENT IndexData:{DescID: 104 (t), IndexID: 2 (idx-)} + │ ├── PUBLIC → ABSENT IndexData:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ ├── DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder), ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ ├── DROPPED → ABSENT Database:{DescID: 105 (db-)} + │ ├── PUBLIC → ABSENT DatabaseData:{DescID: 105 (db-)} + │ └── DROPPED → ABSENT Schema:{DescID: 106 (public-)} + └── 10 Mutation operations + ├── CreateGCJobForIndex {"IndexID":2,"TableID":104} + ├── MakeIndexAbsent {"IndexID":3,"TableID":104} + ├── DeleteDescriptor {"DescriptorID":105} + ├── CreateGCJobForDatabase {"DatabaseID":105} + ├── DeleteDescriptor {"DescriptorID":106} + ├── CreateGCJobForIndex {"IndexID":3,"TableID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":105} + ├── RemoveJobStateFromDescriptor {"DescriptorID":106} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_5_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_5_of_7.explain new file mode 100644 index 000000000000..e709e484faee --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_5_of_7.explain @@ -0,0 +1,82 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j INT NOT NULL); +INSERT INTO t SELECT val, val+1 FROM generate_series(1,10) AS temp(val); + +/* test */ +CREATE UNIQUE INDEX idx ON t(j) WHERE (i > 0); +CREATE DATABASE db; +EXPLAIN (DDL) rollback at post-commit stage 5 of 7; +---- +Schema change plan for rolling back CREATE DATABASE ‹db›; following CREATE UNIQUE INDEX ‹idx› ON ‹defaultdb›.public.‹t› (‹j›) WHERE (‹i› > ‹0›); + └── PostCommitNonRevertiblePhase + ├── Stage 1 of 2 in PostCommitNonRevertiblePhase + │ ├── 21 elements transitioning toward ABSENT + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexName:{DescID: 104 (t), Name: "idx", IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ ├── MERGE_ONLY → DELETE_ONLY SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx-), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey)} + │ │ ├── WRITE_ONLY → DELETE_ONLY TemporaryIndex:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder), ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ │ ├── DESCRIPTOR_ADDED → DROPPED Database:{DescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 105 (db-), Name: "db"} + │ │ ├── PUBLIC → ABSENT DatabaseRoleSetting:{DescID: 105 (db-), Name: "__placeholder_role_name__"} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "public"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "root"} + │ │ ├── DESCRIPTOR_ADDED → DROPPED Schema:{DescID: 106 (public-)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 106 (public-), Name: "public", ReferencedDescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT SchemaParent:{DescID: 106 (public-), ReferencedDescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 106 (public-)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "public"} + │ │ └── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "root"} + │ └── 26 Mutation operations + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"Kind":1,"TableID":104} + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":2,"TableID":104} + │ ├── RemoveDroppedIndexPartialPredicate {"IndexID":2,"TableID":104} + │ ├── MarkDescriptorAsDropped {"DescriptorID":106} + │ ├── RemoveSchemaParent {"Parent":{"ParentDatabaseID":105,"SchemaID":106}} + │ ├── NotImplementedForPublicObjects {"DescID":106,"ElementType":"scpb.Owner"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"admin"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"public"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"root"} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":2,"Kind":1,"TableID":104} + │ ├── SetIndexName {"IndexID":2,"Name":"crdb_internal_in...","TableID":104} + │ ├── MarkDescriptorAsDropped {"DescriptorID":105} + │ ├── DrainDescriptorName {"Namespace":{"DescriptorID":105,"Name":"db"}} + │ ├── RemoveDatabaseRoleSettings {"DatabaseID":105} + │ ├── NotImplementedForPublicObjects {"DescID":105,"ElementType":"scpb.Owner"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"admin"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"public"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"root"} + │ ├── DrainDescriptorName {"Namespace":{"DatabaseID":105,"DescriptorID":106,"Name":"public"}} + │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ ├── SetJobStateOnDescriptor {"DescriptorID":105} + │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"PostCommitNonRev..."} + └── Stage 2 of 2 in PostCommitNonRevertiblePhase + ├── 7 elements transitioning toward ABSENT + │ ├── PUBLIC → ABSENT IndexData:{DescID: 104 (t), IndexID: 2 (idx-)} + │ ├── PUBLIC → ABSENT IndexData:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ ├── DELETE_ONLY → ABSENT SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx-), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey)} + │ ├── DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder), ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ ├── DROPPED → ABSENT Database:{DescID: 105 (db-)} + │ ├── PUBLIC → ABSENT DatabaseData:{DescID: 105 (db-)} + │ └── DROPPED → ABSENT Schema:{DescID: 106 (public-)} + └── 11 Mutation operations + ├── MakeIndexAbsent {"IndexID":2,"TableID":104} + ├── MakeIndexAbsent {"IndexID":3,"TableID":104} + ├── DeleteDescriptor {"DescriptorID":105} + ├── CreateGCJobForDatabase {"DatabaseID":105} + ├── DeleteDescriptor {"DescriptorID":106} + ├── CreateGCJobForIndex {"IndexID":2,"TableID":104} + ├── CreateGCJobForIndex {"IndexID":3,"TableID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":105} + ├── RemoveJobStateFromDescriptor {"DescriptorID":106} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_6_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_6_of_7.explain new file mode 100644 index 000000000000..2e783657b621 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_6_of_7.explain @@ -0,0 +1,82 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j INT NOT NULL); +INSERT INTO t SELECT val, val+1 FROM generate_series(1,10) AS temp(val); + +/* test */ +CREATE UNIQUE INDEX idx ON t(j) WHERE (i > 0); +CREATE DATABASE db; +EXPLAIN (DDL) rollback at post-commit stage 6 of 7; +---- +Schema change plan for rolling back CREATE DATABASE ‹db›; following CREATE UNIQUE INDEX ‹idx› ON ‹defaultdb›.public.‹t› (‹j›) WHERE (‹i› > ‹0›); + └── PostCommitNonRevertiblePhase + ├── Stage 1 of 2 in PostCommitNonRevertiblePhase + │ ├── 21 elements transitioning toward ABSENT + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexName:{DescID: 104 (t), Name: "idx", IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ ├── MERGE_ONLY → DELETE_ONLY SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx-), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey)} + │ │ ├── WRITE_ONLY → DELETE_ONLY TemporaryIndex:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder), ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ │ ├── DESCRIPTOR_ADDED → DROPPED Database:{DescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 105 (db-), Name: "db"} + │ │ ├── PUBLIC → ABSENT DatabaseRoleSetting:{DescID: 105 (db-), Name: "__placeholder_role_name__"} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "public"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "root"} + │ │ ├── DESCRIPTOR_ADDED → DROPPED Schema:{DescID: 106 (public-)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 106 (public-), Name: "public", ReferencedDescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT SchemaParent:{DescID: 106 (public-), ReferencedDescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 106 (public-)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "public"} + │ │ └── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "root"} + │ └── 26 Mutation operations + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"Kind":1,"TableID":104} + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":2,"TableID":104} + │ ├── RemoveDroppedIndexPartialPredicate {"IndexID":2,"TableID":104} + │ ├── MarkDescriptorAsDropped {"DescriptorID":106} + │ ├── RemoveSchemaParent {"Parent":{"ParentDatabaseID":105,"SchemaID":106}} + │ ├── NotImplementedForPublicObjects {"DescID":106,"ElementType":"scpb.Owner"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"admin"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"public"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"root"} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":2,"Kind":1,"TableID":104} + │ ├── SetIndexName {"IndexID":2,"Name":"crdb_internal_in...","TableID":104} + │ ├── MarkDescriptorAsDropped {"DescriptorID":105} + │ ├── DrainDescriptorName {"Namespace":{"DescriptorID":105,"Name":"db"}} + │ ├── RemoveDatabaseRoleSettings {"DatabaseID":105} + │ ├── NotImplementedForPublicObjects {"DescID":105,"ElementType":"scpb.Owner"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"admin"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"public"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"root"} + │ ├── DrainDescriptorName {"Namespace":{"DatabaseID":105,"DescriptorID":106,"Name":"public"}} + │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ ├── SetJobStateOnDescriptor {"DescriptorID":105} + │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"PostCommitNonRev..."} + └── Stage 2 of 2 in PostCommitNonRevertiblePhase + ├── 7 elements transitioning toward ABSENT + │ ├── PUBLIC → ABSENT IndexData:{DescID: 104 (t), IndexID: 2 (idx-)} + │ ├── PUBLIC → ABSENT IndexData:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ ├── DELETE_ONLY → ABSENT SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx-), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey)} + │ ├── DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder), ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ ├── DROPPED → ABSENT Database:{DescID: 105 (db-)} + │ ├── PUBLIC → ABSENT DatabaseData:{DescID: 105 (db-)} + │ └── DROPPED → ABSENT Schema:{DescID: 106 (public-)} + └── 11 Mutation operations + ├── MakeIndexAbsent {"IndexID":2,"TableID":104} + ├── MakeIndexAbsent {"IndexID":3,"TableID":104} + ├── DeleteDescriptor {"DescriptorID":105} + ├── CreateGCJobForDatabase {"DatabaseID":105} + ├── DeleteDescriptor {"DescriptorID":106} + ├── CreateGCJobForIndex {"IndexID":2,"TableID":104} + ├── CreateGCJobForIndex {"IndexID":3,"TableID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":105} + ├── RemoveJobStateFromDescriptor {"DescriptorID":106} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_7_of_7.explain b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_7_of_7.explain new file mode 100644 index 000000000000..98d247cd3e54 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__rollback_7_of_7.explain @@ -0,0 +1,80 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j INT NOT NULL); +INSERT INTO t SELECT val, val+1 FROM generate_series(1,10) AS temp(val); + +/* test */ +CREATE UNIQUE INDEX idx ON t(j) WHERE (i > 0); +CREATE DATABASE db; +EXPLAIN (DDL) rollback at post-commit stage 7 of 7; +---- +Schema change plan for rolling back CREATE DATABASE ‹db›; following CREATE UNIQUE INDEX ‹idx› ON ‹defaultdb›.public.‹t› (‹j›) WHERE (‹i› > ‹0›); + └── PostCommitNonRevertiblePhase + ├── Stage 1 of 2 in PostCommitNonRevertiblePhase + │ ├── 21 elements transitioning toward ABSENT + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexName:{DescID: 104 (t), Name: "idx", IndexID: 2 (idx-)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ ├── WRITE_ONLY → DELETE_ONLY SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx-), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey)} + │ │ ├── TRANSIENT_DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder), ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ │ ├── DESCRIPTOR_ADDED → DROPPED Database:{DescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 105 (db-), Name: "db"} + │ │ ├── PUBLIC → ABSENT DatabaseRoleSetting:{DescID: 105 (db-), Name: "__placeholder_role_name__"} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "public"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db-), Name: "root"} + │ │ ├── DESCRIPTOR_ADDED → DROPPED Schema:{DescID: 106 (public-)} + │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 106 (public-), Name: "public", ReferencedDescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT SchemaParent:{DescID: 106 (public-), ReferencedDescID: 105 (db-)} + │ │ ├── PUBLIC → ABSENT Owner:{DescID: 106 (public-)} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "admin"} + │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "public"} + │ │ └── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public-), Name: "root"} + │ └── 26 Mutation operations + │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":2,"TableID":104} + │ ├── RemoveDroppedIndexPartialPredicate {"IndexID":2,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":2,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":2,"Kind":1,"TableID":104} + │ ├── SetIndexName {"IndexID":2,"Name":"crdb_internal_in...","TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"TableID":104} + │ ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"Kind":1,"TableID":104} + │ ├── MakeIndexAbsent {"IndexID":3,"TableID":104} + │ ├── MarkDescriptorAsDropped {"DescriptorID":106} + │ ├── RemoveSchemaParent {"Parent":{"ParentDatabaseID":105,"SchemaID":106}} + │ ├── NotImplementedForPublicObjects {"DescID":106,"ElementType":"scpb.Owner"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"admin"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"public"} + │ ├── RemoveUserPrivileges {"DescriptorID":106,"User":"root"} + │ ├── MarkDescriptorAsDropped {"DescriptorID":105} + │ ├── DrainDescriptorName {"Namespace":{"DescriptorID":105,"Name":"db"}} + │ ├── RemoveDatabaseRoleSettings {"DatabaseID":105} + │ ├── NotImplementedForPublicObjects {"DescID":105,"ElementType":"scpb.Owner"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"admin"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"public"} + │ ├── RemoveUserPrivileges {"DescriptorID":105,"User":"root"} + │ ├── DrainDescriptorName {"Namespace":{"DatabaseID":105,"DescriptorID":106,"Name":"public"}} + │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ ├── SetJobStateOnDescriptor {"DescriptorID":105} + │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"PostCommitNonRev..."} + └── Stage 2 of 2 in PostCommitNonRevertiblePhase + ├── 6 elements transitioning toward ABSENT + │ ├── PUBLIC → ABSENT IndexData:{DescID: 104 (t), IndexID: 2 (idx-)} + │ ├── PUBLIC → ABSENT IndexData:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ ├── DELETE_ONLY → ABSENT SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx-), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey)} + │ ├── DROPPED → ABSENT Database:{DescID: 105 (db-)} + │ ├── PUBLIC → ABSENT DatabaseData:{DescID: 105 (db-)} + │ └── DROPPED → ABSENT Schema:{DescID: 106 (public-)} + └── 10 Mutation operations + ├── MakeIndexAbsent {"IndexID":2,"TableID":104} + ├── DeleteDescriptor {"DescriptorID":105} + ├── CreateGCJobForDatabase {"DatabaseID":105} + ├── DeleteDescriptor {"DescriptorID":106} + ├── CreateGCJobForIndex {"IndexID":2,"TableID":104} + ├── CreateGCJobForIndex {"IndexID":3,"TableID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":105} + ├── RemoveJobStateFromDescriptor {"DescriptorID":106} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__statement_1_of_2.explain b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__statement_1_of_2.explain new file mode 100644 index 000000000000..8b302fec7040 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__statement_1_of_2.explain @@ -0,0 +1,135 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j INT NOT NULL); +INSERT INTO t SELECT val, val+1 FROM generate_series(1,10) AS temp(val); + +/* test */ +EXPLAIN (DDL) CREATE UNIQUE INDEX idx ON t(j) WHERE (i > 0); +---- +Schema change plan for CREATE UNIQUE INDEX ‹idx› ON ‹defaultdb›.‹public›.‹t› (‹j›) WHERE (‹i› > ‹0›); + ├── StatementPhase + │ └── Stage 1 of 1 in StatementPhase + │ ├── 5 elements transitioning toward PUBLIC + │ │ ├── ABSENT → BACKFILL_ONLY SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 2 (idx+)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 2 (idx+)} + │ │ ├── ABSENT → PUBLIC IndexData:{DescID: 104 (t), IndexID: 2 (idx+)} + │ │ └── ABSENT → PUBLIC IndexName:{DescID: 104 (t), Name: "idx", IndexID: 2 (idx+)} + │ ├── 3 elements transitioning toward TRANSIENT_ABSENT + │ │ ├── ABSENT → DELETE_ONLY TemporaryIndex:{DescID: 104 (t), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 3} + │ │ └── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3} + │ └── 9 Mutation operations + │ ├── MakeAbsentIndexBackfilling {"IsSecondaryIndex":true} + │ ├── SetAddedIndexPartialPredicate {"Expr":"i \u003e 0:::INT8","IndexID":2,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":2,"IndexID":2,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":1,"IndexID":2,"Kind":1,"TableID":104} + │ ├── SetIndexName {"IndexID":2,"Name":"idx","TableID":104} + │ ├── MakeAbsentTempIndexDeleteOnly {"IsSecondaryIndex":true} + │ ├── SetAddedIndexPartialPredicate {"Expr":"i \u003e 0:::INT8","IndexID":3,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":2,"IndexID":3,"TableID":104} + │ └── AddColumnToIndex {"ColumnID":1,"IndexID":3,"Kind":1,"TableID":104} + ├── PreCommitPhase + │ ├── Stage 1 of 2 in PreCommitPhase + │ │ ├── 5 elements transitioning toward PUBLIC + │ │ │ ├── BACKFILL_ONLY → ABSENT SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 2 (idx+)} + │ │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 2 (idx+)} + │ │ │ ├── PUBLIC → ABSENT IndexData:{DescID: 104 (t), IndexID: 2 (idx+)} + │ │ │ └── PUBLIC → ABSENT IndexName:{DescID: 104 (t), Name: "idx", IndexID: 2 (idx+)} + │ │ ├── 3 elements transitioning toward TRANSIENT_ABSENT + │ │ │ ├── DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 104 (t), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 3} + │ │ │ └── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3} + │ │ └── 1 Mutation operation + │ │ └── UndoAllInTxnImmediateMutationOpSideEffects + │ └── Stage 2 of 2 in PreCommitPhase + │ ├── 5 elements transitioning toward PUBLIC + │ │ ├── ABSENT → BACKFILL_ONLY SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 2 (idx+)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 2 (idx+)} + │ │ ├── ABSENT → PUBLIC IndexData:{DescID: 104 (t), IndexID: 2 (idx+)} + │ │ └── ABSENT → PUBLIC IndexName:{DescID: 104 (t), Name: "idx", IndexID: 2 (idx+)} + │ ├── 3 elements transitioning toward TRANSIENT_ABSENT + │ │ ├── ABSENT → DELETE_ONLY TemporaryIndex:{DescID: 104 (t), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 3} + │ │ └── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3} + │ └── 13 Mutation operations + │ ├── MakeAbsentIndexBackfilling {"IsSecondaryIndex":true} + │ ├── MaybeAddSplitForIndex {"IndexID":2,"TableID":104} + │ ├── SetAddedIndexPartialPredicate {"Expr":"i \u003e 0:::INT8","IndexID":2,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":2,"IndexID":2,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":1,"IndexID":2,"Kind":1,"TableID":104} + │ ├── SetIndexName {"IndexID":2,"Name":"idx","TableID":104} + │ ├── MakeAbsentTempIndexDeleteOnly {"IsSecondaryIndex":true} + │ ├── SetAddedIndexPartialPredicate {"Expr":"i \u003e 0:::INT8","IndexID":3,"TableID":104} + │ ├── MaybeAddSplitForIndex {"IndexID":3,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":2,"IndexID":3,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":1,"IndexID":3,"Kind":1,"TableID":104} + │ ├── SetJobStateOnDescriptor {"DescriptorID":104,"Initialize":true} + │ └── CreateSchemaChangerJob {"RunningStatus":"PostCommitPhase ..."} + ├── PostCommitPhase + │ ├── Stage 1 of 7 in PostCommitPhase + │ │ ├── 2 elements transitioning toward TRANSIENT_ABSENT + │ │ │ ├── DELETE_ONLY → WRITE_ONLY TemporaryIndex:{DescID: 104 (t), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ │ │ └── ABSENT → PUBLIC IndexData:{DescID: 104 (t), IndexID: 3} + │ │ └── 3 Mutation operations + │ │ ├── MakeDeleteOnlyIndexWriteOnly {"IndexID":3,"TableID":104} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ │ └── UpdateSchemaChangerJob {"RunningStatus":"PostCommitPhase ..."} + │ ├── Stage 2 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── BACKFILL_ONLY → BACKFILLED SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ │ └── 1 Backfill operation + │ │ └── BackfillIndex {"IndexID":2,"SourceIndexID":1,"TableID":104} + │ ├── Stage 3 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── BACKFILLED → DELETE_ONLY SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ │ └── 3 Mutation operations + │ │ ├── MakeBackfillingIndexDeleteOnly {"IndexID":2,"TableID":104} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ │ └── UpdateSchemaChangerJob {"RunningStatus":"PostCommitPhase ..."} + │ ├── Stage 4 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── DELETE_ONLY → MERGE_ONLY SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ │ └── 3 Mutation operations + │ │ ├── MakeBackfilledIndexMerging {"IndexID":2,"TableID":104} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ │ └── UpdateSchemaChangerJob {"RunningStatus":"PostCommitPhase ..."} + │ ├── Stage 5 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── MERGE_ONLY → MERGED SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ │ └── 1 Backfill operation + │ │ └── MergeIndex {"BackfilledIndexID":2,"TableID":104,"TemporaryIndexID":3} + │ ├── Stage 6 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── MERGED → WRITE_ONLY SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ │ ├── 1 element transitioning toward TRANSIENT_ABSENT + │ │ │ └── WRITE_ONLY → TRANSIENT_DELETE_ONLY TemporaryIndex:{DescID: 104 (t), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ │ └── 4 Mutation operations + │ │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":104} + │ │ ├── MakeMergedIndexWriteOnly {"IndexID":2,"TableID":104} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ │ └── UpdateSchemaChangerJob {"RunningStatus":"PostCommitPhase ..."} + │ └── Stage 7 of 7 in PostCommitPhase + │ ├── 1 element transitioning toward PUBLIC + │ │ └── WRITE_ONLY → VALIDATED SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ └── 1 Validation operation + │ └── ValidateIndex {"IndexID":2,"TableID":104} + └── PostCommitNonRevertiblePhase + └── Stage 1 of 1 in PostCommitNonRevertiblePhase + ├── 1 element transitioning toward PUBLIC + │ └── VALIDATED → PUBLIC SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3, SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + ├── 4 elements transitioning toward TRANSIENT_ABSENT + │ ├── TRANSIENT_DELETE_ONLY → TRANSIENT_ABSENT TemporaryIndex:{DescID: 104 (t), IndexID: 3, ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ ├── PUBLIC → TRANSIENT_ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 3} + │ ├── PUBLIC → TRANSIENT_ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3} + │ └── PUBLIC → TRANSIENT_ABSENT IndexData:{DescID: 104 (t), IndexID: 3} + └── 8 Mutation operations + ├── MakeValidatedSecondaryIndexPublic {"IndexID":2,"TableID":104} + ├── RefreshStats {"TableID":104} + ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"TableID":104} + ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"Kind":1,"TableID":104} + ├── MakeIndexAbsent {"IndexID":3,"TableID":104} + ├── CreateGCJobForIndex {"IndexID":3,"TableID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":104} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__statement_1_of_2.explain_shape b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__statement_1_of_2.explain_shape new file mode 100644 index 000000000000..bac6769ad677 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__statement_1_of_2.explain_shape @@ -0,0 +1,17 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j INT NOT NULL); +INSERT INTO t SELECT val, val+1 FROM generate_series(1,10) AS temp(val); + +/* test */ +EXPLAIN (DDL, SHAPE) CREATE UNIQUE INDEX idx ON t(j) WHERE (i > 0); +---- +Schema change plan for CREATE UNIQUE INDEX ‹idx› ON ‹defaultdb›.‹public›.‹t› (‹j›) WHERE (‹i› > ‹0›); + ├── execute 2 system table mutations transactions + ├── backfill using primary index t_pkey in relation t + │ └── into idx+ (j: i) + ├── execute 2 system table mutations transactions + ├── merge temporary indexes into backfilled indexes in relation t + │ └── from t@[3] into idx+ + ├── execute 1 system table mutations transaction + ├── validate UNIQUE constraint backed by index idx+ in relation t + └── execute 1 system table mutations transaction diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__statement_2_of_2.explain b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__statement_2_of_2.explain new file mode 100644 index 000000000000..6a68541a2dea --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__statement_2_of_2.explain @@ -0,0 +1,208 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j INT NOT NULL); +INSERT INTO t SELECT val, val+1 FROM generate_series(1,10) AS temp(val); + +/* test */ +CREATE UNIQUE INDEX idx ON t(j) WHERE (i > 0); +EXPLAIN (DDL) CREATE DATABASE db; +---- +Schema change plan for CREATE DATABASE ‹db›; following CREATE UNIQUE INDEX ‹idx› ON ‹defaultdb›.‹public›.‹t› (‹j›) WHERE (‹i› > ‹0›); + ├── StatementPhase + │ └── Stage 1 of 1 in StatementPhase + │ ├── 14 elements transitioning toward PUBLIC + │ │ ├── ABSENT → PUBLIC Database:{DescID: 105 (db+)} + │ │ ├── ABSENT → PUBLIC Namespace:{DescID: 105 (db+), Name: "db"} + │ │ ├── ABSENT → PUBLIC DatabaseData:{DescID: 105 (db+)} + │ │ ├── ABSENT → PUBLIC Owner:{DescID: 105 (db+)} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (db+), Name: "admin"} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (db+), Name: "public"} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (db+), Name: "root"} + │ │ ├── ABSENT → PUBLIC Schema:{DescID: 106 (public+)} + │ │ ├── ABSENT → PUBLIC Namespace:{DescID: 106 (public+), Name: "public", ReferencedDescID: 105 (db+)} + │ │ ├── ABSENT → PUBLIC SchemaParent:{DescID: 106 (public+), ReferencedDescID: 105 (db+)} + │ │ ├── ABSENT → PUBLIC Owner:{DescID: 106 (public+)} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 106 (public+), Name: "admin"} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 106 (public+), Name: "public"} + │ │ └── ABSENT → PUBLIC UserPrivileges:{DescID: 106 (public+), Name: "root"} + │ └── 17 Mutation operations + │ ├── CreateDatabaseDescriptor {"DatabaseID":105} + │ ├── SetNameInDescriptor {"DescriptorID":105,"Name":"db"} + │ ├── AddDescriptorName {"Namespace":{"DescriptorID":105,"Name":"db"}} + │ ├── UpdateOwner {"Owner":{"DescriptorID":105,"Owner":"root"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":2,"UserName":"admin","WithGrantOption":2}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":2048,"UserName":"public"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":2,"UserName":"root","WithGrantOption":2}} + │ ├── CreateSchemaDescriptor {"SchemaID":106} + │ ├── SetNameInDescriptor {"DescriptorID":106,"Name":"public"} + │ ├── AddDescriptorName {"Namespace":{"DatabaseID":105,"DescriptorID":106,"Name":"public"}} + │ ├── AddSchemaParent {"Parent":{"ParentDatabaseID":105,"SchemaID":106}} + │ ├── UpdateOwner {"Owner":{"DescriptorID":106,"Owner":"admin"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":106,"Privileges":2,"UserName":"admin","WithGrantOption":2}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":106,"Privileges":516,"UserName":"public"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":106,"Privileges":2,"UserName":"root","WithGrantOption":2}} + │ ├── MarkDescriptorAsPublic {"DescriptorID":105} + │ └── MarkDescriptorAsPublic {"DescriptorID":106} + ├── PreCommitPhase + │ ├── Stage 1 of 2 in PreCommitPhase + │ │ ├── 19 elements transitioning toward PUBLIC + │ │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 2 (idx+)} + │ │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 2 (idx+)} + │ │ │ ├── PUBLIC → ABSENT IndexName:{DescID: 104 (t), Name: "idx", IndexID: 2 (idx+)} + │ │ │ ├── PUBLIC → ABSENT IndexData:{DescID: 104 (t), IndexID: 2 (idx+)} + │ │ │ ├── BACKFILL_ONLY → ABSENT SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ │ │ ├── PUBLIC → ABSENT Database:{DescID: 105 (db+)} + │ │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 105 (db+), Name: "db"} + │ │ │ ├── PUBLIC → ABSENT DatabaseData:{DescID: 105 (db+)} + │ │ │ ├── PUBLIC → ABSENT Owner:{DescID: 105 (db+)} + │ │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db+), Name: "admin"} + │ │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db+), Name: "public"} + │ │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 105 (db+), Name: "root"} + │ │ │ ├── PUBLIC → ABSENT Schema:{DescID: 106 (public+)} + │ │ │ ├── PUBLIC → ABSENT Namespace:{DescID: 106 (public+), Name: "public", ReferencedDescID: 105 (db+)} + │ │ │ ├── PUBLIC → ABSENT SchemaParent:{DescID: 106 (public+), ReferencedDescID: 105 (db+)} + │ │ │ ├── PUBLIC → ABSENT Owner:{DescID: 106 (public+)} + │ │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public+), Name: "admin"} + │ │ │ ├── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public+), Name: "public"} + │ │ │ └── PUBLIC → ABSENT UserPrivileges:{DescID: 106 (public+), Name: "root"} + │ │ ├── 3 elements transitioning toward TRANSIENT_ABSENT + │ │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ │ ├── PUBLIC → ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ │ └── DELETE_ONLY → ABSENT TemporaryIndex:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder), ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ │ └── 1 Mutation operation + │ │ └── UndoAllInTxnImmediateMutationOpSideEffects + │ └── Stage 2 of 2 in PreCommitPhase + │ ├── 19 elements transitioning toward PUBLIC + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 2 (idx+)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 2 (idx+)} + │ │ ├── ABSENT → PUBLIC IndexName:{DescID: 104 (t), Name: "idx", IndexID: 2 (idx+)} + │ │ ├── ABSENT → PUBLIC IndexData:{DescID: 104 (t), IndexID: 2 (idx+)} + │ │ ├── ABSENT → BACKFILL_ONLY SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ │ ├── ABSENT → DESCRIPTOR_ADDED Database:{DescID: 105 (db+)} + │ │ ├── ABSENT → PUBLIC Namespace:{DescID: 105 (db+), Name: "db"} + │ │ ├── ABSENT → PUBLIC DatabaseData:{DescID: 105 (db+)} + │ │ ├── ABSENT → PUBLIC Owner:{DescID: 105 (db+)} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (db+), Name: "admin"} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (db+), Name: "public"} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 105 (db+), Name: "root"} + │ │ ├── ABSENT → DESCRIPTOR_ADDED Schema:{DescID: 106 (public+)} + │ │ ├── ABSENT → PUBLIC Namespace:{DescID: 106 (public+), Name: "public", ReferencedDescID: 105 (db+)} + │ │ ├── ABSENT → PUBLIC SchemaParent:{DescID: 106 (public+), ReferencedDescID: 105 (db+)} + │ │ ├── ABSENT → PUBLIC Owner:{DescID: 106 (public+)} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 106 (public+), Name: "admin"} + │ │ ├── ABSENT → PUBLIC UserPrivileges:{DescID: 106 (public+), Name: "public"} + │ │ └── ABSENT → PUBLIC UserPrivileges:{DescID: 106 (public+), Name: "root"} + │ ├── 3 elements transitioning toward TRANSIENT_ABSENT + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ ├── ABSENT → PUBLIC IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ └── ABSENT → DELETE_ONLY TemporaryIndex:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder), ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ └── 30 Mutation operations + │ ├── MakeAbsentIndexBackfilling {"IsSecondaryIndex":true} + │ ├── MaybeAddSplitForIndex {"IndexID":2,"TableID":104} + │ ├── SetAddedIndexPartialPredicate {"Expr":"i \u003e 0:::INT8","IndexID":2,"TableID":104} + │ ├── MakeAbsentTempIndexDeleteOnly {"IsSecondaryIndex":true} + │ ├── SetAddedIndexPartialPredicate {"Expr":"i \u003e 0:::INT8","IndexID":3,"TableID":104} + │ ├── MaybeAddSplitForIndex {"IndexID":3,"TableID":104} + │ ├── CreateDatabaseDescriptor {"DatabaseID":105} + │ ├── SetNameInDescriptor {"DescriptorID":105,"Name":"db"} + │ ├── AddDescriptorName {"Namespace":{"DescriptorID":105,"Name":"db"}} + │ ├── UpdateOwner {"Owner":{"DescriptorID":105,"Owner":"root"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":2,"UserName":"admin","WithGrantOption":2}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":2048,"UserName":"public"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":105,"Privileges":2,"UserName":"root","WithGrantOption":2}} + │ ├── CreateSchemaDescriptor {"SchemaID":106} + │ ├── SetNameInDescriptor {"DescriptorID":106,"Name":"public"} + │ ├── AddDescriptorName {"Namespace":{"DatabaseID":105,"DescriptorID":106,"Name":"public"}} + │ ├── AddSchemaParent {"Parent":{"ParentDatabaseID":105,"SchemaID":106}} + │ ├── UpdateOwner {"Owner":{"DescriptorID":106,"Owner":"admin"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":106,"Privileges":2,"UserName":"admin","WithGrantOption":2}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":106,"Privileges":516,"UserName":"public"}} + │ ├── UpdateUserPrivileges {"Privileges":{"DescriptorID":106,"Privileges":2,"UserName":"root","WithGrantOption":2}} + │ ├── AddColumnToIndex {"ColumnID":2,"IndexID":2,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":1,"IndexID":2,"Kind":1,"TableID":104} + │ ├── SetIndexName {"IndexID":2,"Name":"idx","TableID":104} + │ ├── AddColumnToIndex {"ColumnID":2,"IndexID":3,"TableID":104} + │ ├── AddColumnToIndex {"ColumnID":1,"IndexID":3,"Kind":1,"TableID":104} + │ ├── SetJobStateOnDescriptor {"DescriptorID":104,"Initialize":true} + │ ├── SetJobStateOnDescriptor {"DescriptorID":105,"Initialize":true} + │ ├── SetJobStateOnDescriptor {"DescriptorID":106,"Initialize":true} + │ └── CreateSchemaChangerJob {"RunningStatus":"PostCommitPhase ..."} + ├── PostCommitPhase + │ ├── Stage 1 of 7 in PostCommitPhase + │ │ ├── 2 elements transitioning toward TRANSIENT_ABSENT + │ │ │ ├── ABSENT → PUBLIC IndexData:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ │ │ └── DELETE_ONLY → WRITE_ONLY TemporaryIndex:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder), ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ │ └── 5 Mutation operations + │ │ ├── MakeDeleteOnlyIndexWriteOnly {"IndexID":3,"TableID":104} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":105} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ │ └── UpdateSchemaChangerJob {"RunningStatus":"PostCommitPhase ..."} + │ ├── Stage 2 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── BACKFILL_ONLY → BACKFILLED SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ │ └── 1 Backfill operation + │ │ └── BackfillIndex {"IndexID":2,"SourceIndexID":1,"TableID":104} + │ ├── Stage 3 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── BACKFILLED → DELETE_ONLY SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ │ └── 5 Mutation operations + │ │ ├── MakeBackfillingIndexDeleteOnly {"IndexID":2,"TableID":104} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":105} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ │ └── UpdateSchemaChangerJob {"RunningStatus":"PostCommitPhase ..."} + │ ├── Stage 4 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── DELETE_ONLY → MERGE_ONLY SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ │ └── 5 Mutation operations + │ │ ├── MakeBackfilledIndexMerging {"IndexID":2,"TableID":104} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":105} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ │ └── UpdateSchemaChangerJob {"RunningStatus":"PostCommitPhase ..."} + │ ├── Stage 5 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── MERGE_ONLY → MERGED SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ │ └── 1 Backfill operation + │ │ └── MergeIndex {"BackfilledIndexID":2,"TableID":104,"TemporaryIndexID":3} + │ ├── Stage 6 of 7 in PostCommitPhase + │ │ ├── 1 element transitioning toward PUBLIC + │ │ │ └── MERGED → WRITE_ONLY SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ │ ├── 1 element transitioning toward TRANSIENT_ABSENT + │ │ │ └── WRITE_ONLY → TRANSIENT_DELETE_ONLY TemporaryIndex:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder), ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + │ │ └── 6 Mutation operations + │ │ ├── MakeWriteOnlyIndexDeleteOnly {"IndexID":3,"TableID":104} + │ │ ├── MakeMergedIndexWriteOnly {"IndexID":2,"TableID":104} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":104} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":105} + │ │ ├── SetJobStateOnDescriptor {"DescriptorID":106} + │ │ └── UpdateSchemaChangerJob {"RunningStatus":"PostCommitPhase ..."} + │ └── Stage 7 of 7 in PostCommitPhase + │ ├── 1 element transitioning toward PUBLIC + │ │ └── WRITE_ONLY → VALIDATED SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ └── 1 Validation operation + │ └── ValidateIndex {"IndexID":2,"TableID":104} + └── PostCommitNonRevertiblePhase + └── Stage 1 of 1 in PostCommitNonRevertiblePhase + ├── 3 elements transitioning toward PUBLIC + │ ├── VALIDATED → PUBLIC SecondaryIndex:{DescID: 104 (t), IndexID: 2 (idx+), ConstraintID: 2, TemporaryIndexID: 3 (crdb_internal_index_3_name_placeholder), SourceIndexID: 1 (t_pkey), RecreateSourceIndexID: 0} + │ ├── DESCRIPTOR_ADDED → PUBLIC Database:{DescID: 105 (db+)} + │ └── DESCRIPTOR_ADDED → PUBLIC Schema:{DescID: 106 (public+)} + ├── 4 elements transitioning toward TRANSIENT_ABSENT + │ ├── PUBLIC → TRANSIENT_ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 2 (j), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ ├── PUBLIC → TRANSIENT_ABSENT IndexColumn:{DescID: 104 (t), ColumnID: 1 (i), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ ├── PUBLIC → TRANSIENT_ABSENT IndexData:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder)} + │ └── TRANSIENT_DELETE_ONLY → TRANSIENT_ABSENT TemporaryIndex:{DescID: 104 (t), IndexID: 3 (crdb_internal_index_3_name_placeholder), ConstraintID: 3, SourceIndexID: 1 (t_pkey)} + └── 12 Mutation operations + ├── RemoveColumnFromIndex {"ColumnID":2,"IndexID":3,"TableID":104} + ├── RemoveColumnFromIndex {"ColumnID":1,"IndexID":3,"Kind":1,"TableID":104} + ├── MakeValidatedSecondaryIndexPublic {"IndexID":2,"TableID":104} + ├── RefreshStats {"TableID":104} + ├── MakeIndexAbsent {"IndexID":3,"TableID":104} + ├── MarkDescriptorAsPublic {"DescriptorID":105} + ├── MarkDescriptorAsPublic {"DescriptorID":106} + ├── CreateGCJobForIndex {"IndexID":3,"TableID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":104} + ├── RemoveJobStateFromDescriptor {"DescriptorID":105} + ├── RemoveJobStateFromDescriptor {"DescriptorID":106} + └── UpdateSchemaChangerJob {"IsNonCancelable":true,"RunningStatus":"all stages compl..."} diff --git a/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__statement_2_of_2.explain_shape b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__statement_2_of_2.explain_shape new file mode 100644 index 000000000000..d0b1b2d19ba3 --- /dev/null +++ b/pkg/sql/schemachanger/testdata/end_to_end/create_index_create_database_separate_statements/create_index_create_database_separate_statements__statement_2_of_2.explain_shape @@ -0,0 +1,18 @@ +/* setup */ +CREATE TABLE t (i INT PRIMARY KEY, j INT NOT NULL); +INSERT INTO t SELECT val, val+1 FROM generate_series(1,10) AS temp(val); + +/* test */ +CREATE UNIQUE INDEX idx ON t(j) WHERE (i > 0); +EXPLAIN (DDL, SHAPE) CREATE DATABASE db; +---- +Schema change plan for CREATE DATABASE ‹db›; following CREATE UNIQUE INDEX ‹idx› ON ‹defaultdb›.‹public›.‹t› (‹j›) WHERE (‹i› > ‹0›); + ├── execute 2 system table mutations transactions + ├── backfill using primary index t_pkey in relation t + │ └── into idx+ (j: i) + ├── execute 2 system table mutations transactions + ├── merge temporary indexes into backfilled indexes in relation t + │ └── from crdb_internal_index_3_name_placeholder into idx+ + ├── execute 1 system table mutations transaction + ├── validate UNIQUE constraint backed by index idx+ in relation t + └── execute 1 system table mutations transaction diff --git a/pkg/sql/sem/tree/stmt.go b/pkg/sql/sem/tree/stmt.go index 0a871b9f4fbb..10698839870e 100644 --- a/pkg/sql/sem/tree/stmt.go +++ b/pkg/sql/sem/tree/stmt.go @@ -97,6 +97,7 @@ const ( CreateProcedureTag = "CREATE PROCEDURE" CreateSchemaTag = "CREATE SCHEMA" CreateSequenceTag = "CREATE SEQUENCE" + CreateDatabaseTag = "CREATE DATABASE" CommentOnColumnTag = "COMMENT ON COLUMN" CommentOnConstraintTag = "COMMENT ON CONSTRAINT" CommentOnDatabaseTag = "COMMENT ON DATABASE"