Skip to content

Commit 936e143

Browse files
committed
backup: restore must skip temporary tables
There is a bug in backup. We backup temporary table descriptors but not temporary schemas. When we restore the temporary tables they end up getting restored into the public schema. This is wrong in the sense the temporary table is placed in the wrong schema and can cause restores to fail if there are multiple temp tables with the same name. Release note: fixes a bug where the presence of duplicate temporary tables in a backup caused the restore to fail with an error containing the text 'restoring table desc and namespace entries: table already exists'. Informs: #153722
1 parent dcd90be commit 936e143

File tree

2 files changed

+51
-1
lines changed

2 files changed

+51
-1
lines changed

pkg/backup/restore_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package backup
77

88
import (
99
"context"
10+
gosql "database/sql"
1011
"testing"
1112
"time"
1213

@@ -85,3 +86,49 @@ func TestFailAfterCleanupSystemTables(t *testing.T) {
8586
sqlDB.Exec(t, "CANCEL JOB $1", jobID)
8687
jobutils.WaitForJobToCancel(t, sqlDB, jobID)
8788
}
89+
90+
func TestRestoreDuplicateTempTables(t *testing.T) {
91+
defer leaktest.AfterTest(t)()
92+
defer log.Scope(t).Close(t)
93+
94+
// This is a regression test for #153722. It verifies that restoring a backup
95+
// that contains two temporary tables with the same name does not cause the
96+
// restore to fail with an error of the form: "restoring 17 TableDescriptors
97+
// from 4 databases: restoring table desc and namespace entries: table
98+
// already exists"
99+
100+
clusterSize := 1
101+
tc, sqlDB, _, cleanupFn := backuptestutils.StartBackupRestoreTestCluster(t, clusterSize)
102+
defer cleanupFn()
103+
104+
sqlDB.Exec(t, `SET experimental_enable_temp_tables=true`)
105+
sqlDB.Exec(t, `CREATE DATABASE test_db`)
106+
sqlDB.Exec(t, `USE test_db`)
107+
sqlDB.Exec(t, `CREATE TABLE permanent_table (id INT PRIMARY KEY, name TEXT)`)
108+
109+
sessions := make([]*gosql.DB, 2)
110+
for i := range sessions {
111+
sessions[i] = tc.Servers[0].SQLConn(t)
112+
sql := sqlutils.MakeSQLRunner(sessions[i])
113+
sql.Exec(t, `SET experimental_enable_temp_tables=true`)
114+
sql.Exec(t, `USE test_db`)
115+
sql.Exec(t, `CREATE TEMP TABLE duplicate_temp (id INT PRIMARY KEY, value TEXT)`)
116+
sql.Exec(t, `INSERT INTO duplicate_temp VALUES (1, 'value')`)
117+
}
118+
119+
sqlDB.Exec(t, `BACKUP INTO 'nodelocal://1/duplicate_temp_backup'`)
120+
121+
for _, session := range sessions {
122+
require.NoError(t, session.Close())
123+
}
124+
125+
// The cluster must be empty for a full cluster restore.
126+
sqlDB.Exec(t, `DROP DATABASE test_db CASCADE`)
127+
sqlDB.Exec(t, `RESTORE FROM LATEST IN 'nodelocal://1/duplicate_temp_backup'`)
128+
129+
sqlDB.Exec(t, `DROP DATABASE test_db CASCADE`)
130+
sqlDB.Exec(t, `RESTORE DATABASE test_db FROM LATEST IN 'nodelocal://1/duplicate_temp_backup'`)
131+
132+
result := sqlDB.QueryStr(t, `SELECT table_name FROM [SHOW TABLES] ORDER BY table_name`)
133+
require.Equal(t, [][]string{{"permanent_table"}}, result)
134+
}

pkg/backup/targets.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,10 @@ func fullClusterTargetsRestore(
305305
var filteredDescs []catalog.Descriptor
306306
var filteredDBs []catalog.DatabaseDescriptor
307307
for _, desc := range fullClusterDescs {
308+
if table, ok := desc.(catalog.TableDescriptor); ok && table.IsTemporary() {
309+
// TODO(jeffswenson): We should move this filtering into backup.
310+
continue
311+
}
308312
if desc.GetID() != keys.SystemDatabaseID {
309313
filteredDescs = append(filteredDescs, desc)
310314
}
@@ -381,7 +385,6 @@ func selectTargets(
381385
}
382386

383387
if descriptorCoverage == tree.AllDescriptors {
384-
385388
tables, dbs, patterns, err := fullClusterTargetsRestore(ctx, allDescs, lastBackupManifest)
386389
return tables, dbs, patterns, nil, err
387390
}

0 commit comments

Comments
 (0)