Skip to content

Commit 830c168

Browse files
committed
Give a more user-friendly error message in situation where CREATE DATABASE
specifies a new default tablespace and the template database already has some tables in that tablespace. There isn't any way to solve this fully without modifying the clone database's pg_class contents, so for now the best we can do is issue a better error message.
1 parent fae7ce8 commit 830c168

File tree

3 files changed

+43
-12
lines changed

3 files changed

+43
-12
lines changed

src/backend/commands/dbcommands.c

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.144 2004/08/30 03:50:24 tgl Exp $
12+
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.145 2004/10/17 20:47:20 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -281,6 +281,37 @@ createdb(const CreatedbStmt *stmt)
281281
if (aclresult != ACLCHECK_OK)
282282
aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
283283
tablespacename);
284+
285+
/*
286+
* If we are trying to change the default tablespace of the template,
287+
* we require that the template not have any files in the new default
288+
* tablespace. This is necessary because otherwise the copied
289+
* database would contain pg_class rows that refer to its default
290+
* tablespace both explicitly (by OID) and implicitly (as zero), which
291+
* would cause problems. For example another CREATE DATABASE using
292+
* the copied database as template, and trying to change its default
293+
* tablespace again, would yield outright incorrect results (it would
294+
* improperly move tables to the new default tablespace that should
295+
* stay in the same tablespace).
296+
*/
297+
if (dst_deftablespace != src_deftablespace)
298+
{
299+
char *srcpath;
300+
struct stat st;
301+
302+
srcpath = GetDatabasePath(src_dboid, dst_deftablespace);
303+
304+
if (stat(srcpath, &st) == 0 &&
305+
S_ISDIR(st.st_mode) &&
306+
!directory_is_empty(srcpath))
307+
ereport(ERROR,
308+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
309+
errmsg("cannot assign new default tablespace \"%s\"",
310+
tablespacename),
311+
errdetail("There is a conflict because database \"%s\" already has some tables in this tablespace.",
312+
dbtemplate)));
313+
pfree(srcpath);
314+
}
284315
}
285316
else
286317
{
@@ -311,11 +342,6 @@ createdb(const CreatedbStmt *stmt)
311342
/*
312343
* Iterate through all tablespaces of the template database, and copy
313344
* each one to the new database.
314-
*
315-
* If we are trying to change the default tablespace of the template, we
316-
* require that the template not have any files in the new default
317-
* tablespace. This avoids the need to merge two subdirectories. This
318-
* could probably be improved later.
319345
*/
320346
rel = heap_openr(TableSpaceRelationName, AccessShareLock);
321347
scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
@@ -333,7 +359,8 @@ createdb(const CreatedbStmt *stmt)
333359

334360
srcpath = GetDatabasePath(src_dboid, srctablespace);
335361

336-
if (stat(srcpath, &st) < 0 || !S_ISDIR(st.st_mode))
362+
if (stat(srcpath, &st) < 0 || !S_ISDIR(st.st_mode) ||
363+
directory_is_empty(srcpath))
337364
{
338365
/* Assume we can ignore it */
339366
pfree(srcpath);
@@ -352,7 +379,8 @@ createdb(const CreatedbStmt *stmt)
352379
remove_dbtablespaces(dboid);
353380
ereport(ERROR,
354381
(errmsg("could not initialize database directory"),
355-
errdetail("Directory \"%s\" already exists.", dstpath)));
382+
errdetail("Directory \"%s\" already exists.",
383+
dstpath)));
356384
}
357385

358386
#ifndef WIN32

src/backend/commands/tablespace.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
*
4646
*
4747
* IDENTIFICATION
48-
* $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.11 2004/08/30 02:54:38 momjian Exp $
48+
* $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.12 2004/10/17 20:47:20 tgl Exp $
4949
*
5050
*-------------------------------------------------------------------------
5151
*/
@@ -75,7 +75,6 @@
7575

7676
static bool remove_tablespace_directories(Oid tablespaceoid, bool redo);
7777
static void set_short_version(const char *path);
78-
static bool directory_is_empty(const char *path);
7978

8079

8180
/*
@@ -680,8 +679,10 @@ set_short_version(const char *path)
680679

681680
/*
682681
* Check if a directory is empty.
682+
*
683+
* This probably belongs somewhere else, but not sure where...
683684
*/
684-
static bool
685+
bool
685686
directory_is_empty(const char *path)
686687
{
687688
DIR *dirdesc;

src/include/commands/tablespace.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/commands/tablespace.h,v 1.5 2004/08/30 02:54:40 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/commands/tablespace.h,v 1.6 2004/10/17 20:47:21 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -42,6 +42,8 @@ extern void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo);
4242
extern Oid get_tablespace_oid(const char *tablespacename);
4343
extern char *get_tablespace_name(Oid spc_oid);
4444

45+
extern bool directory_is_empty(const char *path);
46+
4547
extern void tblspc_redo(XLogRecPtr lsn, XLogRecord *rptr);
4648
extern void tblspc_undo(XLogRecPtr lsn, XLogRecord *rptr);
4749
extern void tblspc_desc(char *buf, uint8 xl_info, char *rec);

0 commit comments

Comments
 (0)