Skip to content

Commit a248502

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 ba4fefb commit a248502

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
"syscall"
1112
"testing"
1213
"time"
@@ -271,3 +272,49 @@ func TestRestoreJobMessages(t *testing.T) {
271272
return nil
272273
})
273274
}
275+
276+
func TestRestoreDuplicateTempTables(t *testing.T) {
277+
defer leaktest.AfterTest(t)()
278+
defer log.Scope(t).Close(t)
279+
280+
// This is a regression test for #153722. It verifies that restoring a backup
281+
// that contains two temporary tables with the same name does not cause the
282+
// restore to fail with an error of the form: "restoring 17 TableDescriptors
283+
// from 4 databases: restoring table desc and namespace entries: table
284+
// already exists"
285+
286+
clusterSize := 1
287+
tc, sqlDB, _, cleanupFn := backuptestutils.StartBackupRestoreTestCluster(t, clusterSize)
288+
defer cleanupFn()
289+
290+
sqlDB.Exec(t, `SET experimental_enable_temp_tables=true`)
291+
sqlDB.Exec(t, `CREATE DATABASE test_db`)
292+
sqlDB.Exec(t, `USE test_db`)
293+
sqlDB.Exec(t, `CREATE TABLE permanent_table (id INT PRIMARY KEY, name TEXT)`)
294+
295+
sessions := make([]*gosql.DB, 2)
296+
for i := range sessions {
297+
sessions[i] = tc.Servers[0].SQLConn(t)
298+
sql := sqlutils.MakeSQLRunner(sessions[i])
299+
sql.Exec(t, `SET experimental_enable_temp_tables=true`)
300+
sql.Exec(t, `USE test_db`)
301+
sql.Exec(t, `CREATE TEMP TABLE duplicate_temp (id INT PRIMARY KEY, value TEXT)`)
302+
sql.Exec(t, `INSERT INTO duplicate_temp VALUES (1, 'value')`)
303+
}
304+
305+
sqlDB.Exec(t, `BACKUP INTO 'nodelocal://1/duplicate_temp_backup'`)
306+
307+
for _, session := range sessions {
308+
require.NoError(t, session.Close())
309+
}
310+
311+
// The cluster must be empty for a full cluster restore.
312+
sqlDB.Exec(t, `DROP DATABASE test_db CASCADE`)
313+
sqlDB.Exec(t, `RESTORE FROM LATEST IN 'nodelocal://1/duplicate_temp_backup'`)
314+
315+
sqlDB.Exec(t, `DROP DATABASE test_db CASCADE`)
316+
sqlDB.Exec(t, `RESTORE DATABASE test_db FROM LATEST IN 'nodelocal://1/duplicate_temp_backup'`)
317+
318+
result := sqlDB.QueryStr(t, `SELECT table_name FROM [SHOW TABLES] ORDER BY table_name`)
319+
require.Equal(t, [][]string{{"permanent_table"}}, result)
320+
}

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)