From 91e0f633255c17e1504f6768e57894b808b1da12 Mon Sep 17 00:00:00 2001 From: Aditya Maru Date: Tue, 22 Mar 2022 18:27:28 +0530 Subject: [PATCH] backupccl: datadrivenify `TestBackupRestoreUserDefinedSchemas` This tests previously started 8 test clusters, now it starts just 2! Informs: #77129 Release note: None --- pkg/ccl/backupccl/backup_test.go | 345 ---------- .../backup-restore-3/user-defined-schemas | 640 ++++++++++++++++++ 2 files changed, 640 insertions(+), 345 deletions(-) create mode 100644 pkg/ccl/backupccl/testdata/backup-restore-3/user-defined-schemas diff --git a/pkg/ccl/backupccl/backup_test.go b/pkg/ccl/backupccl/backup_test.go index 938e174b8304..b7592d1c2f21 100644 --- a/pkg/ccl/backupccl/backup_test.go +++ b/pkg/ccl/backupccl/backup_test.go @@ -1675,351 +1675,6 @@ func TestBackupRestoreControlJob(t *testing.T) { }) } -func TestBackupRestoreUserDefinedSchemas(t *testing.T) { - defer leaktest.AfterTest(t)() - defer log.Scope(t).Close(t) - - // This test takes a full backup and an incremental backup with revision - // history at certain timestamps, then restores to each of the timestamps to - // ensure that the types restored are correct. - t.Run("revision-history", func(t *testing.T) { - _, sqlDB, _, cleanupFn := backupRestoreTestSetup(t, singleNode, 0, InitManualReplication) - defer cleanupFn() - - var ts1, ts2, ts3, ts4, ts5, ts6 string - sqlDB.Exec(t, `CREATE DATABASE d;`) - sqlDB.Exec(t, `USE d;`) - sqlDB.Exec(t, `CREATE SCHEMA sc;`) - sqlDB.Exec(t, `CREATE SCHEMA sc2;`) - sqlDB.Exec(t, `CREATE TABLE d.sc.t1 (x int);`) - sqlDB.Exec(t, `CREATE TABLE d.sc2.t1 (x bool);`) - sqlDB.QueryRow(t, `SELECT cluster_logical_timestamp()`).Scan(&ts1) - - sqlDB.Exec(t, `ALTER SCHEMA sc RENAME TO sc3;`) - sqlDB.Exec(t, `ALTER SCHEMA sc2 RENAME TO sc;`) - sqlDB.QueryRow(t, `SELECT cluster_logical_timestamp()`).Scan(&ts2) - - sqlDB.Exec(t, `DROP TABLE sc.t1;`) - sqlDB.Exec(t, `DROP TABLE sc3.t1;`) - sqlDB.Exec(t, `DROP SCHEMA sc;`) - sqlDB.Exec(t, `DROP SCHEMA sc3;`) - sqlDB.QueryRow(t, `SELECT cluster_logical_timestamp()`).Scan(&ts3) - - sqlDB.Exec(t, `CREATE SCHEMA sc;`) - sqlDB.Exec(t, `CREATE TABLE sc.t1 (a STRING); -`) - sqlDB.QueryRow(t, `SELECT cluster_logical_timestamp()`).Scan(&ts4) - sqlDB.Exec(t, `BACKUP DATABASE d TO 'nodelocal://0/rev-history-backup' WITH revision_history`) - - sqlDB.Exec(t, `DROP TABLE sc.t1;`) - sqlDB.Exec(t, `DROP SCHEMA sc; -`) - sqlDB.QueryRow(t, `SELECT cluster_logical_timestamp()`).Scan(&ts5) - - sqlDB.Exec(t, `CREATE SCHEMA sc;`) - sqlDB.Exec(t, `CREATE TABLE sc.t1 (a FLOAT);`) - sqlDB.QueryRow(t, `SELECT cluster_logical_timestamp()`).Scan(&ts6) - sqlDB.Exec(t, `BACKUP DATABASE d TO 'nodelocal://0/rev-history-backup' WITH revision_history`) - - t.Run("ts1", func(t *testing.T) { - sqlDB.Exec(t, "DROP DATABASE d;") - sqlDB.Exec(t, "RESTORE DATABASE d FROM 'nodelocal://0/rev-history-backup' AS OF SYSTEM TIME "+ts1) - sqlDB.Exec(t, "INSERT INTO d.sc.t1 VALUES (1)") - sqlDB.Exec(t, "INSERT INTO d.sc2.t1 VALUES (true)") - sqlDB.Exec(t, "USE d; CREATE SCHEMA unused;") - }) - t.Run("ts2", func(t *testing.T) { - sqlDB.Exec(t, "DROP DATABASE d;") - sqlDB.Exec(t, "RESTORE DATABASE d FROM 'nodelocal://0/rev-history-backup' AS OF SYSTEM TIME "+ts2) - sqlDB.Exec(t, "INSERT INTO d.sc3.t1 VALUES (1)") - sqlDB.Exec(t, "INSERT INTO d.sc.t1 VALUES (true)") - }) - t.Run("ts3", func(t *testing.T) { - sqlDB.Exec(t, "DROP DATABASE d;") - sqlDB.Exec(t, "RESTORE DATABASE d FROM 'nodelocal://0/rev-history-backup' AS OF SYSTEM TIME "+ts3) - sqlDB.Exec(t, "USE d") - sqlDB.Exec(t, "CREATE SCHEMA sc") - sqlDB.Exec(t, "CREATE SCHEMA sc3;") - }) - t.Run("ts4", func(t *testing.T) { - sqlDB.Exec(t, "DROP DATABASE d;") - sqlDB.Exec(t, "RESTORE DATABASE d FROM 'nodelocal://0/rev-history-backup' AS OF SYSTEM TIME "+ts4) - sqlDB.Exec(t, "INSERT INTO d.sc.t1 VALUES ('hello')") - }) - t.Run("ts5", func(t *testing.T) { - sqlDB.Exec(t, "DROP DATABASE d;") - sqlDB.Exec(t, "RESTORE DATABASE d FROM 'nodelocal://0/rev-history-backup' AS OF SYSTEM TIME "+ts5) - sqlDB.Exec(t, "USE d") - sqlDB.Exec(t, "CREATE SCHEMA sc") - }) - t.Run("ts6", func(t *testing.T) { - sqlDB.Exec(t, "DROP DATABASE d;") - sqlDB.Exec(t, "RESTORE DATABASE d FROM 'nodelocal://0/rev-history-backup' AS OF SYSTEM TIME "+ts6) - sqlDB.Exec(t, `INSERT INTO d.sc.t1 VALUES (123.123)`) - }) - }) - - // Tests full cluster backup/restore with user defined schemas. - t.Run("full-cluster", func(t *testing.T) { - _, sqlDB, dataDir, cleanupFn := backupRestoreTestSetup(t, singleNode, 0, InitManualReplication) - defer cleanupFn() - sqlDB.Exec(t, `CREATE DATABASE d;`) - sqlDB.Exec(t, `USE d;`) - sqlDB.Exec(t, `CREATE SCHEMA unused;`) - sqlDB.Exec(t, `CREATE SCHEMA sc;`) - sqlDB.Exec(t, `CREATE TABLE sc.tb1 (x INT);`) - sqlDB.Exec(t, `INSERT INTO sc.tb1 VALUES (1);`) - sqlDB.Exec(t, `CREATE TYPE sc.typ1 AS ENUM ('hello');`) - sqlDB.Exec(t, `CREATE TABLE sc.tb2 (x sc.typ1);`) - sqlDB.Exec(t, `INSERT INTO sc.tb2 VALUES ('hello');`) - // Now backup the full cluster. - sqlDB.Exec(t, `BACKUP TO 'nodelocal://0/test/'`) - // Start a new server that shares the data directory. - _, sqlDBRestore, cleanupRestore := backupRestoreTestSetupEmpty(t, singleNode, dataDir, InitManualReplication, base.TestClusterArgs{}) - defer cleanupRestore() - - // Restore into the new cluster. - sqlDBRestore.Exec(t, `RESTORE FROM 'nodelocal://0/test/'`) - - // Check that we can resolve all names through the user defined schema. - sqlDBRestore.CheckQueryResults(t, `SELECT * FROM d.sc.tb1`, [][]string{{"1"}}) - sqlDBRestore.CheckQueryResults(t, `SELECT * FROM d.sc.tb2`, [][]string{{"hello"}}) - sqlDBRestore.CheckQueryResults(t, `SELECT 'hello'::d.sc.typ1`, [][]string{{"hello"}}) - - // We shouldn't be able to create a new schema with the same name. - sqlDBRestore.ExpectErr(t, `pq: schema "sc" already exists`, `USE d; CREATE SCHEMA sc`) - sqlDBRestore.ExpectErr(t, `pq: schema "unused" already exists`, `USE d; CREATE SCHEMA unused`) - }) - - // Tests restoring databases with user defined schemas. - t.Run("database", func(t *testing.T) { - _, sqlDB, _, cleanupFn := backupRestoreTestSetup(t, singleNode, 0, InitManualReplication) - defer cleanupFn() - - sqlDB.Exec(t, `CREATE DATABASE d;`) - sqlDB.Exec(t, `USE d;`) - sqlDB.Exec(t, `CREATE SCHEMA sc;`) - sqlDB.Exec(t, `CREATE SCHEMA unused;`) - sqlDB.Exec(t, `CREATE TABLE sc.tb1 (x INT);`) - sqlDB.Exec(t, `INSERT INTO sc.tb1 VALUES (1);`) - sqlDB.Exec(t, `CREATE TYPE sc.typ1 AS ENUM ('hello');`) - sqlDB.Exec(t, `CREATE TABLE sc.tb2 (x sc.typ1);`) - sqlDB.Exec(t, `INSERT INTO sc.tb2 VALUES ('hello');`) - // Backup the database. - sqlDB.Exec(t, `BACKUP DATABASE d TO 'nodelocal://0/test/'`) - - // Drop the database and restore into it. - sqlDB.Exec(t, `DROP DATABASE d`) - sqlDB.Exec(t, `RESTORE DATABASE d FROM 'nodelocal://0/test/'`) - - // Check that we can resolve all names through the user defined schema. - sqlDB.CheckQueryResults(t, `SELECT * FROM d.sc.tb1`, [][]string{{"1"}}) - sqlDB.CheckQueryResults(t, `SELECT * FROM d.sc.tb2`, [][]string{{"hello"}}) - sqlDB.CheckQueryResults(t, `SELECT 'hello'::d.sc.typ1`, [][]string{{"hello"}}) - - // We shouldn't be able to create a new schema with the same name. - sqlDB.ExpectErr(t, `pq: schema "sc" already exists`, `USE d; CREATE SCHEMA sc`) - sqlDB.ExpectErr(t, `pq: schema "unused" already exists`, `USE d; CREATE SCHEMA unused`) - }) - - // Tests backing up and restoring all tables in requested user defined - // schemas. - t.Run("all-tables-in-requested-schema", func(t *testing.T) { - _, sqlDB, _, cleanupFn := backupRestoreTestSetup(t, singleNode, 0, InitManualReplication) - defer cleanupFn() - - sqlDB.Exec(t, `CREATE TABLE table_in_data (x INT);`) - - sqlDB.Exec(t, `CREATE SCHEMA data;`) - sqlDB.Exec(t, `CREATE TABLE data.tb1 (x INT);`) - - sqlDB.Exec(t, `CREATE DATABASE foo;`) - sqlDB.Exec(t, `USE foo;`) - sqlDB.Exec(t, `CREATE SCHEMA schema_in_foo;`) - sqlDB.Exec(t, `CREATE TABLE schema_in_foo.tb1 (x INT);`) - - sqlDB.Exec(t, `CREATE SCHEMA schema_in_foo2;`) - sqlDB.Exec(t, `CREATE TABLE schema_in_foo2.tb1 (x INT);`) - - sqlDB.Exec(t, `CREATE SCHEMA foo;`) - sqlDB.Exec(t, `CREATE TABLE foo.tb1 (x INT);`) - - sqlDB.Exec(t, `CREATE TABLE tb2 (y INT);`) - - for _, tc := range []struct { - name string - target string - expectedTablesInBackup [][]string - }{ - { - name: "fully-qualified-target", - target: "foo.schema_in_foo.*", - expectedTablesInBackup: [][]string{{"schema_in_foo", "tb1"}}, - }, - { - name: "schema-qualified-target", - target: "schema_in_foo.*", - expectedTablesInBackup: [][]string{{"schema_in_foo", "tb1"}}, - }, - { - name: "schema-qualified-target-with-identical-name-as-curdb", - target: "foo.*", - expectedTablesInBackup: [][]string{{"foo", "tb1"}}, - }, - { - name: "curdb-public-schema-target", - target: "*", - expectedTablesInBackup: [][]string{{"public", "tb2"}}, - }, - { - name: "cross-db-qualified-target", - target: "data.*", - expectedTablesInBackup: [][]string{{"data", "tb1"}, {"public", "bank"}, {"public", "table_in_data"}}, - }, - } { - sqlDB.Exec(t, fmt.Sprintf(`BACKUP TABLE %s TO 'nodelocal://0/%s'`, tc.target, tc.name)) - sqlDB.Exec(t, `CREATE DATABASE restore`) - sqlDB.Exec(t, fmt.Sprintf(`RESTORE TABLE %s FROM 'nodelocal://0/%s' WITH into_db='restore'`, tc.target, tc.name)) - sqlDB.CheckQueryResults(t, `SELECT schema_name, -table_name from [SHOW TABLES FROM restore] ORDER BY schema_name, table_name`, tc.expectedTablesInBackup) - sqlDB.Exec(t, `DROP DATABASE restore CASCADE`) - } - }) - - // Test restoring tables with user defined schemas when restore schemas are - // not being remapped. - t.Run("no-remap", func(t *testing.T) { - _, sqlDB, _, cleanupFn := backupRestoreTestSetup(t, singleNode, 0, InitManualReplication) - defer cleanupFn() - - sqlDB.Exec(t, `CREATE DATABASE d;`) - sqlDB.Exec(t, `USE d;`) - sqlDB.Exec(t, `CREATE SCHEMA sc;`) - sqlDB.Exec(t, `CREATE TYPE sc.typ1 AS ENUM ('hello');`) - sqlDB.Exec(t, `CREATE TABLE sc.tb1 (x sc.typ1);`) - sqlDB.Exec(t, `INSERT INTO sc.tb1 VALUES ('hello');`) - sqlDB.Exec(t, `CREATE TABLE sc.tb2 (x INT);`) - sqlDB.Exec(t, `INSERT INTO sc.tb2 VALUES (1);`) - { - // We have to qualify the table correctly to back it up. d.tb1 resolves - // to d.public.tb1. - sqlDB.ExpectErr(t, `pq: failed to resolve targets specified in the BACKUP stmt: table "d.tb1" does not exist`, `BACKUP TABLE d.tb1 TO 'nodelocal://0/test/'`) - // Backup tb1. - sqlDB.Exec(t, `BACKUP TABLE d.sc.tb1 TO 'nodelocal://0/test/'`) - // Create a new database to restore into. This restore should restore the - // schema sc into the new database. - sqlDB.Exec(t, `CREATE DATABASE d2`) - - // We must properly qualify the table name when restoring as well. - sqlDB.ExpectErr(t, `pq: failed to resolve targets in the BACKUP location specified by the RESTORE stmt, use SHOW BACKUP to find correct targets: table "d.tb1" does not exist`, `RESTORE TABLE d.tb1 FROM 'nodelocal://0/test/' WITH into_db = 'd2'`) - - sqlDB.Exec(t, `RESTORE TABLE d.sc.tb1 FROM 'nodelocal://0/test/' WITH into_db = 'd2'`) - - // Check that we can resolve all names through the user defined schema. - sqlDB.CheckQueryResults(t, `SELECT * FROM d2.sc.tb1`, [][]string{{"hello"}}) - sqlDB.CheckQueryResults(t, `SELECT 'hello'::d2.sc.typ1`, [][]string{{"hello"}}) - - // We shouldn't be able to create a new schema with the same name. - sqlDB.ExpectErr(t, `pq: schema "sc" already exists`, `USE d2; CREATE SCHEMA sc`) - } - - { - // Test that we can * expand schema prefixed names. Create a new backup - // with all the tables in d.sc. - sqlDB.Exec(t, `BACKUP TABLE d.sc.* TO 'nodelocal://0/test2/'`) - // Create a new database to restore into. - sqlDB.Exec(t, `CREATE DATABASE d3`) - sqlDB.Exec(t, `RESTORE TABLE d.sc.* FROM 'nodelocal://0/test2/' WITH into_db = 'd3'`) - - // Check that we can resolve all names through the user defined schema. - sqlDB.CheckQueryResults(t, `SELECT * FROM d3.sc.tb1`, [][]string{{"hello"}}) - sqlDB.CheckQueryResults(t, `SELECT * FROM d3.sc.tb2`, [][]string{{"1"}}) - sqlDB.CheckQueryResults(t, `SELECT 'hello'::d3.sc.typ1`, [][]string{{"hello"}}) - - // We shouldn't be able to create a new schema with the same name. - sqlDB.ExpectErr(t, `pq: schema "sc" already exists`, `USE d3; CREATE SCHEMA sc`) - } - }) - - // Test restoring tables with user defined schemas when restore schemas are - // not being remapped. Like no-remap but with more databases and schemas. - t.Run("multi-schemas", func(t *testing.T) { - tc, sqlDB, _, cleanupFn := backupRestoreTestSetup(t, singleNode, 0, InitManualReplication) - defer cleanupFn() - kvDB := tc.Server(0).DB() - - sqlDB.Exec(t, `CREATE DATABASE d1;`) - sqlDB.Exec(t, `USE d1;`) - sqlDB.Exec(t, `CREATE SCHEMA sc1;`) - sqlDB.Exec(t, `CREATE TABLE sc1.tb (x INT);`) - sqlDB.Exec(t, `INSERT INTO sc1.tb VALUES (1);`) - sqlDB.Exec(t, `CREATE SCHEMA sc2;`) - sqlDB.Exec(t, `CREATE TABLE sc2.tb (x INT);`) - sqlDB.Exec(t, `INSERT INTO sc2.tb VALUES (2);`) - - sqlDB.Exec(t, `CREATE DATABASE d2;`) - sqlDB.Exec(t, `USE d2;`) - sqlDB.Exec(t, `CREATE SCHEMA sc3;`) - sqlDB.Exec(t, `CREATE TABLE sc3.tb (x INT);`) - sqlDB.Exec(t, `INSERT INTO sc3.tb VALUES (3);`) - sqlDB.Exec(t, `CREATE SCHEMA sc4;`) - sqlDB.Exec(t, `CREATE TABLE sc4.tb (x INT);`) - sqlDB.Exec(t, `INSERT INTO sc4.tb VALUES (4);`) - { - // Backup all databases. - sqlDB.Exec(t, `BACKUP DATABASE d1, d2 TO 'nodelocal://0/test/'`) - // Create a new database to restore into. This restore should restore the - // schemas into the new database. - sqlDB.Exec(t, `CREATE DATABASE newdb`) - // Create a schema and table in the database to restore into, unrelated to - // the restore. - sqlDB.Exec(t, `USE newdb`) - sqlDB.Exec(t, `CREATE SCHEMA existingschema`) - sqlDB.Exec(t, `CREATE TABLE existingschema.tb (x INT)`) - sqlDB.Exec(t, `INSERT INTO existingschema.tb VALUES (0)`) - - sqlDB.Exec(t, `RESTORE TABLE d1.sc1.*, d1.sc2.*, d2.sc3.*, d2.sc4.* FROM 'nodelocal://0/test/' WITH into_db = 'newdb'`) - - // Check that we can resolve all names through the user defined schemas. - sqlDB.CheckQueryResults(t, `SELECT * FROM newdb.sc1.tb`, [][]string{{"1"}}) - sqlDB.CheckQueryResults(t, `SELECT * FROM newdb.sc2.tb`, [][]string{{"2"}}) - sqlDB.CheckQueryResults(t, `SELECT * FROM newdb.sc3.tb`, [][]string{{"3"}}) - sqlDB.CheckQueryResults(t, `SELECT * FROM newdb.sc4.tb`, [][]string{{"4"}}) - - // Check that name resolution still works for the preexisting schema. - sqlDB.CheckQueryResults(t, `SELECT * FROM newdb.existingschema.tb`, [][]string{{"0"}}) - } - - // Verify that the schemas are in the database's schema map. - dbDesc := desctestutils.TestingGetDatabaseDescriptor(kvDB, keys.SystemSQLCodec, "newdb") - require.Contains(t, dbDesc.DatabaseDesc().Schemas, "sc1") - require.Contains(t, dbDesc.DatabaseDesc().Schemas, "sc2") - require.Contains(t, dbDesc.DatabaseDesc().Schemas, "sc3") - require.Contains(t, dbDesc.DatabaseDesc().Schemas, "sc4") - require.Contains(t, dbDesc.DatabaseDesc().Schemas, "existingschema") - require.Len(t, dbDesc.DatabaseDesc().Schemas, 6) - }) - // Test when we remap schemas to existing schemas in the cluster. - t.Run("remap", func(t *testing.T) { - _, sqlDB, _, cleanupFn := backupRestoreTestSetup(t, singleNode, 0, InitManualReplication) - defer cleanupFn() - - sqlDB.Exec(t, `CREATE DATABASE d;`) - sqlDB.Exec(t, `USE d;`) - sqlDB.Exec(t, `CREATE SCHEMA sc;`) - sqlDB.Exec(t, `CREATE TYPE sc.typ1 AS ENUM ('hello');`) - sqlDB.Exec(t, `CREATE TABLE sc.tb1 (x sc.typ1);`) - sqlDB.Exec(t, `INSERT INTO sc.tb1 VALUES ('hello');`) - // Take a backup. - sqlDB.Exec(t, `BACKUP TABLE d.sc.tb1 TO 'nodelocal://0/test/'`) - // Now drop the table. - sqlDB.Exec(t, `DROP TABLE d.sc.tb1`) - // Restoring the table should restore into d.sc. - sqlDB.Exec(t, `RESTORE TABLE d.sc.tb1 FROM 'nodelocal://0/test/'`) - sqlDB.CheckQueryResults(t, `SELECT * FROM d.sc.tb1`, [][]string{{"hello"}}) - }) -} - func TestBackupRestoreUserDefinedTypes(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) diff --git a/pkg/ccl/backupccl/testdata/backup-restore-3/user-defined-schemas b/pkg/ccl/backupccl/testdata/backup-restore-3/user-defined-schemas new file mode 100644 index 000000000000..52fee5e25013 --- /dev/null +++ b/pkg/ccl/backupccl/testdata/backup-restore-3/user-defined-schemas @@ -0,0 +1,640 @@ +new-server name=s1 nodes=3 splits=1000 +---- + +# This test takes a full backup and an incremental backup with revision history +# at certain timestamps, then restores to each of the timestamps to ensure that +# the types restored are correct. +subtest revision-history + +exec-sql +CREATE DATABASE d; +USE d; +CREATE SCHEMA sc; +CREATE SCHEMA sc2; +CREATE TABLE d.sc.t1(x int); +CREATE TABLE d.sc2.t1 (c bool); +---- + +save-cluster-ts tag=t1 +---- + +exec-sql +ALTER SCHEMA sc RENAME TO sc3; +---- + +exec-sql +ALTER SCHEMA sc2 RENAME TO sc; +---- + +save-cluster-ts tag=t2 +---- + +exec-sql +DROP TABLE sc.t1; +DROP TABLE sc3.t1; +---- + +exec-sql +DROP SCHEMA sc; +---- + +exec-sql +DROP SCHEMA sc3; +---- + +save-cluster-ts tag=t3 +---- + +exec-sql +CREATE SCHEMA sc; +CREATE TABLE sc.t1 (a STRING); +---- + +save-cluster-ts tag=t4 +---- + +exec-sql +BACKUP DATABASE d INTO 'nodelocal://1/rev-history-backup' WITH revision_history; +---- + +exec-sql +DROP TABLE sc.t1; +---- + +exec-sql +DROP SCHEMA sc; +---- + +save-cluster-ts tag=t5 +---- + +exec-sql +CREATE SCHEMA sc; +CREATE TABLE sc.t1 (a FLOAT); +---- + +save-cluster-ts tag=t6 +---- + +exec-sql +BACKUP DATABASE d INTO LATEST IN 'nodelocal://1/rev-history-backup' WITH revision_history; +---- + +subtest revision-history/ts1 + +exec-sql +DROP DATABASE d; +---- + +restore aost=t1 +RESTORE DATABASE d FROM LATEST IN 'nodelocal://1/rev-history-backup' AS OF SYSTEM TIME t1 +---- + +exec-sql +INSERT INTO d.sc.t1 VALUES (1); +INSERT INTO d.sc2.t1 VALUES (true); +USE d; +CREATE SCHEMA unused; +---- + +subtest end + +subtest revision-history/ts2 + +exec-sql +DROP DATABASE d; +---- + +restore aost=t2 +RESTORE DATABASE d FROM LATEST IN 'nodelocal://1/rev-history-backup' AS OF SYSTEM TIME t2 +---- + +exec-sql +INSERT INTO d.sc3.t1 VALUES (1); +INSERT INTO d.sc.t1 VALUES (true); +---- + +subtest end + +subtest revision-history/ts3 + +exec-sql +DROP DATABASE d; +---- + +restore aost=t3 +RESTORE DATABASE d FROM LATEST IN 'nodelocal://1/rev-history-backup' AS OF SYSTEM TIME t3 +---- + +exec-sql +USE d; +CREATE SCHEMA sc; +CREATE SCHEMA sc3; +---- + +subtest end + +subtest revision-history/ts4 + +exec-sql +DROP DATABASE d; +---- + +restore aost=t4 +RESTORE DATABASE d FROM LATEST IN 'nodelocal://1/rev-history-backup' AS OF SYSTEM TIME t4 +---- + +exec-sql +INSERT INTO d.sc.t1 VALUES ('hello'); +---- + +subtest end + +subtest revision-history/ts5 + +exec-sql +DROP DATABASE d; +---- + +restore aost=t5 +RESTORE DATABASE d FROM LATEST IN 'nodelocal://1/rev-history-backup' AS OF SYSTEM TIME t5 +---- + +exec-sql +USE d; +CREATE SCHEMA sc; +---- + +subtest end + +subtest revision-history/ts6 + +exec-sql +DROP DATABASE d; +---- + +restore aost=t6 +RESTORE DATABASE d FROM LATEST IN 'nodelocal://1/rev-history-backup' AS OF SYSTEM TIME t6 +---- + +exec-sql +INSERT INTO d.sc.t1 VALUES (123.123); +---- + +subtest end + +subtest end + +subtest full-cluster + +exec-sql +CREATE DATABASE d2; +USE d2; +CREATE SCHEMA unused; +CREATE SCHEMA sc; +CREATE TABLE sc.tb1 (x INT); +INSERT INTO sc.tb1 VALUES (1); +CREATE TYPE sc.typ1 AS ENUM ('hello'); +CREATE TABLE sc.tb2 (x sc.typ1); +INSERT INTO sc.tb2 VALUES ('hello'); +---- + +# Now backup the full cluster. +exec-sql +BACKUP INTO 'nodelocal://1/test/'; +---- + +# Start a new server that shares the data directory +new-server name=s2 share-io-dir=s1 +---- + +# Restore into the new cluster. +exec-sql +RESTORE FROM LATEST IN 'nodelocal://1/test/'; +---- + +# Check that we can resolve all names through the user defined schema. +query-sql +SELECT * FROM d2.sc.tb1; +---- +1 + +query-sql +SELECT * FROM d2.sc.tb2; +---- +hello + +query-sql +SELECT 'hello'::d2.sc.typ1; +---- +hello + +# We shouldn't be able to create a new schema with the same name. + +query-sql +USE d2; +CREATE SCHEMA sc; +---- +pq: schema "sc" already exists + +query-sql +USE d2; +CREATE SCHEMA unused; +---- +pq: schema "unused" already exists + +subtest end + +subtest database + +# Backup the database. +exec-sql +BACKUP DATABASE d2 INTO 'nodelocal://1/test' +---- + +# Drop the database and restore into it. +exec-sql +DROP DATABASE d2; +---- + +exec-sql +RESTORE DATABASE d2 FROM LATEST IN 'nodelocal://1/test'; +---- + +# Check that we can resolve all names through the user defined schema. +query-sql +SELECT * FROM d2.sc.tb1; +---- +1 + +query-sql +SELECT * FROM d2.sc.tb2; +---- +hello + +query-sql +SELECT 'hello'::d2.sc.typ1; +---- +hello + +# We shouldn't be able to create a new schema with the same name. + +query-sql +USE d2; +CREATE SCHEMA sc; +---- +pq: schema "sc" already exists + +query-sql +USE d2; +CREATE SCHEMA unused; +---- +pq: schema "unused" already exists + +subtest end + +# Tests backing up and restoring all tables in requested user defined schemas. +subtest all-tables-in-requested-schemas + +exec-sql +USE data; +CREATE TABLE table_in_data (x INT); +---- + +exec-sql +CREATE SCHEMA data; +CREATE TABLE data.tb1 (x INT); +---- + +exec-sql +CREATE DATABASE foo; +USE foo; +---- + +exec-sql +CREATE SCHEMA schema_in_foo; +CREATE TABLE schema_in_foo.tb1 (x INT); +CREATE SCHEMA schema_in_foo2; +CREATE TABLE schema_in_foo2.tb1 (x INT); +---- + +exec-sql +CREATE SCHEMA foo; +CREATE TABLE foo.tb1 (x INT); +---- + +exec-sql +CREATE TABLE tb2 (y INT); +---- + +subtest all-tables-in-requested-schemas/fully-qualified-target + +exec-sql +BACKUP TABLE foo.schema_in_foo.* INTO 'nodelocal://1/fully-qualified-target'; +---- + +exec-sql +CREATE DATABASE restore; +---- + +exec-sql +RESTORE TABLE foo.schema_in_foo.* FROM LATEST IN 'nodelocal://1/fully-qualified-target' WITH into_db='restore' +---- + +query-sql +SELECT schema_name, table_name FROM [SHOW TABLES FROM restore] ORDER BY schema_name, table_name; +---- +schema_in_foo tb1 + +# Cleanup +exec-sql +DROP DATABASE restore CASCADE; +---- + +subtest end + + +subtest all-tables-in-requested-schemas/schema-qualified-target + +exec-sql +BACKUP TABLE schema_in_foo.* INTO 'nodelocal://1/schema-qualified-target'; +---- + +exec-sql +CREATE DATABASE restore; +---- + +exec-sql +RESTORE TABLE schema_in_foo.* FROM LATEST IN 'nodelocal://1/schema-qualified-target' WITH into_db='restore' +---- + +query-sql +SELECT schema_name, table_name FROM [SHOW TABLES FROM restore] ORDER BY schema_name, table_name; +---- +schema_in_foo tb1 + +# Cleanup +exec-sql +DROP DATABASE restore CASCADE; +---- + +subtest end + +subtest all-tables-in-requested-schemas/schema-qualified-target-with-identical-name-as-curdb + +exec-sql +BACKUP TABLE foo.* INTO 'nodelocal://1/schema-qualified-target-with-identical-name-as-curdb'; +---- + +exec-sql +CREATE DATABASE restore; +---- + +exec-sql +RESTORE TABLE foo.* FROM LATEST IN 'nodelocal://1/schema-qualified-target-with-identical-name-as-curdb' WITH into_db='restore' +---- + +query-sql +SELECT schema_name, table_name FROM [SHOW TABLES FROM restore] ORDER BY schema_name, table_name; +---- +foo tb1 + +# Cleanup +exec-sql +DROP DATABASE restore CASCADE; +---- + +subtest end + +subtest all-tables-in-requested-schemas/curdb-public-schema-target + +exec-sql +BACKUP TABLE * INTO 'nodelocal://1/curdb-public-schema-target'; +---- + +exec-sql +CREATE DATABASE restore; +---- + +exec-sql +RESTORE TABLE * FROM LATEST IN 'nodelocal://1/curdb-public-schema-target' WITH into_db='restore' +---- + +query-sql +SELECT schema_name, table_name FROM [SHOW TABLES FROM restore] ORDER BY schema_name, table_name; +---- +public tb2 + +# Cleanup +exec-sql +DROP DATABASE restore CASCADE; +---- + +subtest end + +subtest all-tables-in-requested-schemas/cross-db-qualified-target + +exec-sql +BACKUP TABLE data.* INTO 'nodelocal://1/cross-db-qualified-target'; +---- + +exec-sql +CREATE DATABASE restore; +---- + +exec-sql +RESTORE TABLE data.* FROM LATEST IN 'nodelocal://1/cross-db-qualified-target' WITH into_db='restore' +---- + +query-sql +SELECT schema_name, table_name FROM [SHOW TABLES FROM restore] ORDER BY schema_name, table_name; +---- +data tb1 +public bank +public table_in_data + +# Cleanup +exec-sql +DROP DATABASE restore CASCADE; +---- + +subtest end + +subtest end + +subtest no-remap + +exec-sql +CREATE DATABASE d3; +USE d3; +CREATE SCHEMA sc; +CREATE TYPE sc.typ1 AS ENUM ('hello'); +CREATE TABLE sc.tb1 (x sc.typ1); +INSERT INTO sc.tb1 VALUES ('hello'); +CREATE TABLE sc.tb2 (x INT); +INSERT INTO sc.tb2 VALUES (1); +---- + +# We have to qualify the table correctly to back it up. d3.tb1 resolves +# to d3.public.tb1. +exec-sql +BACKUP TABLE d3.tb1 INTO 'nodelocal://1/test' +---- +pq: failed to resolve targets specified in the BACKUP stmt: table "d3.tb1" does not exist, or invalid RESTORE timestamp: supplied backups do not cover requested time + +# Backup tb1. +exec-sql +BACKUP TABLE d3.sc.tb1 INTO 'nodelocal://1/test'; +---- + +# Create a new database to restore into. This restore should restore the schema +# sc into the new database. +exec-sql +CREATE DATABASE d4; +---- + +# We have to qualify the table correctly to restore it. d.tb1 resolves +# to d.public.tb1. +exec-sql +RESTORE TABLE d3.tb1 FROM LATEST IN 'nodelocal://1/test' WITH into_db = 'd4'; +---- +pq: failed to resolve targets in the BACKUP location specified by the RESTORE stmt, use SHOW BACKUP to find correct targets: table "d3.tb1" does not exist + +exec-sql +RESTORE TABLE d3.sc.tb1 FROM LATEST IN 'nodelocal://1/test' WITH into_db = 'd4'; +---- + +# Check that we can resolve all names through the user defined schemas. +query-sql +SELECT * FROM d4.sc.tb1; +---- +hello + +query-sql +SELECT 'hello'::d4.sc.typ1; +---- +hello + +# We shouldn't be able to create a new schema with the same name. +exec-sql +USE d4; +CREATE SCHEMA sc; +---- +pq: schema "sc" already exists + +subtest end + +subtest remap + +exec-sql +CREATE DATABASE d5; +USE d5; +CREATE SCHEMA sc; +CREATE TYPE sc.typ1 AS ENUM ('hello'); +CREATE TABLE sc.tb1 (x sc.typ1); +INSERT INTO sc.tb1 VALUES ('hello'); +---- + +# Take a backup. +exec-sql +BACKUP TABLE d5.sc.tb1 INTO 'nodelocal://1/test'; +---- + +# Now drop a table. +exec-sql +DROP TABLE d5.sc.tb1; +---- + +# Restoring the table should restore into d5. +exec-sql +RESTORE TABLE d5.sc.tb1 FROM LATEST IN 'nodelocal://1/test'; +---- + +query-sql +SELECT * FROM d5.sc.tb1; +---- +hello + +subtest end + +# Test restoring tables with user defined schemas when restore schemas are not +# being remapped. Like no-remap but with more databases and schemas. +subtest multi-schemas + +exec-sql +CREATE DATABASE d6; +USE d6; +CREATE SCHEMA sc1; +CREATE TABLE sc1.tb (x INT); +INSERT INTO sc1.tb VALUES (1); +CREATE SCHEMA sc2; +CREATE TABLE sc2.tb (x INT); +INSERT INTO sc2.tb VALUES (2); +---- + +exec-sql +CREATE DATABASE d7; +USE d7; +CREATE SCHEMA sc3; +CREATE TABLE sc3.tb (x INT); +INSERT INTO sc3.tb VALUES (3); +CREATE SCHEMA sc4; +CREATE TABLE sc4.tb (x INT); +INSERT INTO sc4.tb VALUES (4); +---- + +# Backup all databases. +exec-sql +BACKUP DATABASE d6, d7 INTO 'nodelocal://1/test'; +---- + +# Create a new database to restore into. This restore should restore the schemas +# into the new database. +exec-sql +CREATE DATABASE newdb; +---- + +# Create a schema and table in the database to restore into, unrelated to the +# restore. +exec-sql +USE newdb; +CREATE SCHEMA existingschema; +---- + +exec-sql +CREATE TABLE existingschema.tb (x INT); +INSERT INTO existingschema.tb VALUES (0); +---- + +exec-sql +RESTORE TABLE d6.sc1.*, d6.sc2.*, d7.sc3.*, d7.sc4.* FROM LATEST IN 'nodelocal://1/test' WITH into_db = 'newdb' +---- + +# Check that we can resolve all names through the user defined schemas. +query-sql +SELECT * FROM newdb.sc1.tb; +---- +1 + +query-sql +SELECT * FROM newdb.sc2.tb; +---- +2 + +query-sql +SELECT * FROM newdb.sc3.tb; +---- +3 + +query-sql +SELECT * FROM newdb.sc4.tb; +---- +4 + +# Check that name resolution still workds for the preexisting schema. +query-sql +SELECT * FROM newdb.existingschema.tb; +---- +0 + +subtest end