Skip to content

Commit

Permalink
sql: insert missing public schema namespace entry
Browse files Browse the repository at this point in the history
When restoring a database, a namespace entry for the public
schema was not created.

Release note: None
  • Loading branch information
RichardJCai committed Dec 15, 2021
1 parent 7167b22 commit 96179bf
Show file tree
Hide file tree
Showing 22 changed files with 194 additions and 8 deletions.
2 changes: 1 addition & 1 deletion docs/generated/settings/settings-for-tenants.txt
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,4 @@ trace.debug.enable boolean false if set, traces for recent requests can be seen
trace.jaeger.agent string the address of a Jaeger agent to receive traces using the Jaeger UDP Thrift protocol, as <host>:<port>. If no port is specified, 6381 will be used.
trace.opentelemetry.collector string address of an OpenTelemetry trace collector to receive traces using the otel gRPC protocol, as <host>:<port>. If no port is specified, 4317 will be used.
trace.zipkin.collector string the address of a Zipkin instance to receive traces, as <host>:<port>. If no port is specified, 9411 will be used.
version version 21.2-28 set the active cluster version in the format '<major>.<minor>'
version version 21.2-30 set the active cluster version in the format '<major>.<minor>'
2 changes: 1 addition & 1 deletion docs/generated/settings/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,6 @@
<tr><td><code>trace.jaeger.agent</code></td><td>string</td><td><code></code></td><td>the address of a Jaeger agent to receive traces using the Jaeger UDP Thrift protocol, as <host>:<port>. If no port is specified, 6381 will be used.</td></tr>
<tr><td><code>trace.opentelemetry.collector</code></td><td>string</td><td><code></code></td><td>address of an OpenTelemetry trace collector to receive traces using the otel gRPC protocol, as <host>:<port>. If no port is specified, 4317 will be used.</td></tr>
<tr><td><code>trace.zipkin.collector</code></td><td>string</td><td><code></code></td><td>the address of a Zipkin instance to receive traces, as <host>:<port>. If no port is specified, 9411 will be used.</td></tr>
<tr><td><code>version</code></td><td>version</td><td><code>21.2-28</code></td><td>set the active cluster version in the format '<major>.<minor>'</td></tr>
<tr><td><code>version</code></td><td>version</td><td><code>21.2-30</code></td><td>set the active cluster version in the format '<major>.<minor>'</td></tr>
</tbody>
</table>
1 change: 1 addition & 0 deletions pkg/ccl/backupccl/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ go_test(
"full_cluster_backup_restore_test.go",
"helpers_test.go",
"import_spans_test.go",
"insert_missing_public_schema_namespace_entry_restore_test.go",
"key_rewriter_test.go",
"main_test.go",
"partitioned_backup_test.go",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright 2021 The Cockroach Authors.
//
// Licensed as a CockroachDB Enterprise file under the Cockroach Community
// License (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt

package backupccl_test

import (
"context"
"fmt"
"testing"

"github.com/cockroachdb/cockroach/pkg/base"
"github.com/cockroachdb/cockroach/pkg/clusterversion"
"github.com/cockroachdb/cockroach/pkg/server"
"github.com/cockroachdb/cockroach/pkg/testutils"
"github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
"github.com/cockroachdb/cockroach/pkg/testutils/testcluster"
"github.com/cockroachdb/cockroach/pkg/util/leaktest"
)

func TestPublicSchemaMigration(t *testing.T) {
defer leaktest.AfterTest(t)()
ctx := context.Background()
dir, cleanup := testutils.TempDir(t)
defer cleanup()
tc := testcluster.StartTestCluster(t, 3, base.TestClusterArgs{
ServerArgs: base.TestServerArgs{
ExternalIODir: dir,
Knobs: base.TestingKnobs{
Server: &server.TestingKnobs{
DisableAutomaticVersionUpgrade: 1,
BinaryVersionOverride: clusterversion.ByKey(clusterversion.InsertPublicSchemaNamespaceEntryOnRestore - 1),
},
},
},
})
defer tc.Stopper().Stop(ctx)

db := tc.ServerConn(0)
defer db.Close()
sqlDB := sqlutils.MakeSQLRunner(tc.Conns[0])

// Mimic a restore where the public schema system.namespace entries are
// missing.
sqlDB.Exec(t, `CREATE DATABASE db1`)
sqlDB.Exec(t, `CREATE TABLE db1.t()`)
sqlDB.Exec(t, `CREATE SCHEMA db1.s`)
sqlDB.Exec(t, `CREATE DATABASE db2`)
sqlDB.Exec(t, `CREATE TABLE db2.t(x INT)`)
sqlDB.Exec(t, `INSERT INTO db2.t VALUES (1), (2)`)
sqlDB.Exec(t, `CREATE SCHEMA db2.s`)
sqlDB.Exec(t, `CREATE TABLE db2.s.t(x INT)`)
sqlDB.Exec(t, `INSERT INTO db2.s.t VALUES (1), (2)`)

// Give root the ability to delete from system.namespace.
sqlDB.Exec(t, `INSERT INTO system.users VALUES ('node', '', false);`)
sqlDB.Exec(t, `GRANT node TO root`)

var db1ID, db2ID int
row := sqlDB.QueryRow(t, `SELECT id FROM system.namespace WHERE name = 'db1'`)
row.Scan(&db1ID)
row = sqlDB.QueryRow(t, `SELECT id FROM system.namespace WHERE name = 'db2'`)
row.Scan(&db2ID)

// Remove public schema namespace entries from system.namespace.
sqlDB.Exec(t, fmt.Sprintf(`DELETE FROM system.namespace WHERE name='public' AND id=29 AND "parentID"=%d`, db1ID))
sqlDB.Exec(t, fmt.Sprintf(`DELETE FROM system.namespace WHERE name='public' AND id=29 AND "parentID"=%d`, db2ID))

// Verify that there are no system.namespace entries for the public schema for
// the two databases.
sqlDB.CheckQueryResults(t, fmt.Sprintf(`SELECT id FROM system.namespace WHERE name = 'public' AND "parentID"=%d`, db1ID), [][]string{})
sqlDB.CheckQueryResults(t, fmt.Sprintf(`SELECT id FROM system.namespace WHERE name = 'public' AND "parentID"=%d`, db2ID), [][]string{})

// Kick off migration by upgrading to the new version.
_ = sqlDB.Exec(t, `SET CLUSTER SETTING version = $1`,
clusterversion.ByKey(clusterversion.InsertPublicSchemaNamespaceEntryOnRestore).String())

sqlDB.CheckQueryResults(t, fmt.Sprintf(`SELECT id FROM system.namespace WHERE name = 'public' AND "parentID"=%d`, db1ID), [][]string{{"29"}})
sqlDB.CheckQueryResults(t, fmt.Sprintf(`SELECT id FROM system.namespace WHERE name = 'public' AND "parentID"=%d`, db2ID), [][]string{{"29"}})

}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
����
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
��3
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
O��,
13 changes: 10 additions & 3 deletions pkg/clusterversion/cockroach_versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,9 @@ const (
// MVCCAddSSTable supports MVCC-compliant AddSSTable requests via the new
// WriteAtRequestTimestamp and DisallowConflicts parameters.
MVCCAddSSTable
// Public schema is backed by a descriptor.
PublicSchemasWithDescriptors
// InsertPublicSchemaNamespaceEntryOnRestore ensures all public schemas
// have an entry in system.namespace upon being restored.
InsertPublicSchemaNamespaceEntryOnRestore
// UnsplitRangesInAsyncGCJobs moves ranges unsplitting from transaction of
// "drop table"/"truncate table" to async gc jobs
UnsplitRangesInAsyncGCJobs
Expand All @@ -316,6 +317,8 @@ const (
// protos (the client is responsible for filling it in explicitly), and the
// server-side handler is responsible for opening a span manually.
SelectRPCsTakeTracingInfoInband
// Public schema is backed by a descriptor.
PublicSchemasWithDescriptors

// *************************************************
// Step (1): Add new versions here.
Expand Down Expand Up @@ -530,7 +533,7 @@ var versionsSingleton = keyedVersions{
Version: roachpb.Version{Major: 21, Minor: 2, Internal: 16},
},
{
Key: PublicSchemasWithDescriptors,
Key: InsertPublicSchemaNamespaceEntryOnRestore,
Version: roachpb.Version{Major: 21, Minor: 2, Internal: 18},
},
{
Expand All @@ -553,6 +556,10 @@ var versionsSingleton = keyedVersions{
Key: SelectRPCsTakeTracingInfoInband,
Version: roachpb.Version{Major: 21, Minor: 2, Internal: 28},
},
{
Key: PublicSchemasWithDescriptors,
Version: roachpb.Version{Major: 21, Minor: 2, Internal: 30},
},

// *************************************************
// Step (2): Add new versions here.
Expand Down
7 changes: 4 additions & 3 deletions pkg/clusterversion/key_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pkg/migration/migrations/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ go_library(
"delete_deprecated_namespace_tabledesc.go",
"ensure_no_draining_names.go",
"fix_descriptor_migration.go",
"insert_missing_public_schema_namespace_entry.go",
"join_tokens.go",
"migrations.go",
"records_based_registry.go",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright 2021 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 migrations

import (
"context"

"github.com/cockroachdb/cockroach/pkg/clusterversion"
"github.com/cockroachdb/cockroach/pkg/jobs"
"github.com/cockroachdb/cockroach/pkg/keys"
"github.com/cockroachdb/cockroach/pkg/kv"
"github.com/cockroachdb/cockroach/pkg/migration"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/catalogkeys"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descs"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
)

// insertMissingPublicSchemaNamespaceEntry creates a system.namespace entries
// for public schemas that are missing a system.namespace entry.
// This arises from restore where we mistakenly did not create system.namespace
// entries for public schemas when restoring databases.
func insertMissingPublicSchemaNamespaceEntry(
ctx context.Context, _ clusterversion.ClusterVersion, d migration.TenantDeps, _ *jobs.Job,
) error {
// Get the ID of all databases where we're missing a public schema namespace
// entry for.
query := `
SELECT id
FROM system.namespace
WHERE id
NOT IN (
SELECT ns_db.id
FROM system.namespace AS ns_db
INNER JOIN system.namespace
AS ns_sc ON (
ns_db.id
= ns_sc."parentID"
)
WHERE ns_db."parentSchemaID" = 0
AND ns_db."parentID" = 0
AND ns_sc."parentSchemaID" = 0
AND ns_sc.name = 'public'
AND ns_sc.id = 29
)
AND "parentID" = 0
ORDER BY id ASC;
`
rows, err := d.InternalExecutor.QueryIterator(
ctx, "get_databases_without_public_schema_namespace_entry", nil /* txn */, query,
)
if err != nil {
return err
}
var databaseIDs []descpb.ID
for ok, err := rows.Next(ctx); ok; ok, err = rows.Next(ctx) {
if err != nil {
return err
}
id := descpb.ID(tree.MustBeDInt(rows.Cur()[0]))
databaseIDs = append(databaseIDs, id)
}

return d.CollectionFactory.Txn(ctx, d.InternalExecutor, d.DB, func(
ctx context.Context, txn *kv.Txn, descriptors *descs.Collection,
) error {
b := txn.NewBatch()
for _, dbID := range databaseIDs {
publicSchemaKey := catalogkeys.MakeSchemaNameKey(d.Codec, dbID, tree.PublicSchema)
b.Put(publicSchemaKey, keys.PublicSchemaID)
}
return txn.Run(ctx, b)
})
}
6 changes: 6 additions & 0 deletions pkg/migration/migrations/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ var migrations = []migration.Migration{
NoPrecondition,
alterSystemStmtDiagReqs,
),
migration.NewTenantMigration(
"insert missing system.namespace entries for public schemas",
toCV(clusterversion.InsertPublicSchemaNamespaceEntryOnRestore),
NoPrecondition,
insertMissingPublicSchemaNamespaceEntry,
),
}

func init() {
Expand Down

0 comments on commit 96179bf

Please sign in to comment.