Commit 830c168e authored by Tom Lane's avatar Tom Lane

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.
parent fae7ce83
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.144 2004/08/30 03:50:24 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.145 2004/10/17 20:47:20 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -281,6 +281,37 @@ createdb(const CreatedbStmt *stmt) ...@@ -281,6 +281,37 @@ createdb(const CreatedbStmt *stmt)
if (aclresult != ACLCHECK_OK) if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TABLESPACE, aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
tablespacename); tablespacename);
/*
* If we are trying to change the default tablespace of the template,
* we require that the template not have any files in the new default
* tablespace. This is necessary because otherwise the copied
* database would contain pg_class rows that refer to its default
* tablespace both explicitly (by OID) and implicitly (as zero), which
* would cause problems. For example another CREATE DATABASE using
* the copied database as template, and trying to change its default
* tablespace again, would yield outright incorrect results (it would
* improperly move tables to the new default tablespace that should
* stay in the same tablespace).
*/
if (dst_deftablespace != src_deftablespace)
{
char *srcpath;
struct stat st;
srcpath = GetDatabasePath(src_dboid, dst_deftablespace);
if (stat(srcpath, &st) == 0 &&
S_ISDIR(st.st_mode) &&
!directory_is_empty(srcpath))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot assign new default tablespace \"%s\"",
tablespacename),
errdetail("There is a conflict because database \"%s\" already has some tables in this tablespace.",
dbtemplate)));
pfree(srcpath);
}
} }
else else
{ {
...@@ -311,11 +342,6 @@ createdb(const CreatedbStmt *stmt) ...@@ -311,11 +342,6 @@ createdb(const CreatedbStmt *stmt)
/* /*
* Iterate through all tablespaces of the template database, and copy * Iterate through all tablespaces of the template database, and copy
* each one to the new database. * each one to the new database.
*
* If we are trying to change the default tablespace of the template, we
* require that the template not have any files in the new default
* tablespace. This avoids the need to merge two subdirectories. This
* could probably be improved later.
*/ */
rel = heap_openr(TableSpaceRelationName, AccessShareLock); rel = heap_openr(TableSpaceRelationName, AccessShareLock);
scan = heap_beginscan(rel, SnapshotNow, 0, NULL); scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
...@@ -333,7 +359,8 @@ createdb(const CreatedbStmt *stmt) ...@@ -333,7 +359,8 @@ createdb(const CreatedbStmt *stmt)
srcpath = GetDatabasePath(src_dboid, srctablespace); srcpath = GetDatabasePath(src_dboid, srctablespace);
if (stat(srcpath, &st) < 0 || !S_ISDIR(st.st_mode)) if (stat(srcpath, &st) < 0 || !S_ISDIR(st.st_mode) ||
directory_is_empty(srcpath))
{ {
/* Assume we can ignore it */ /* Assume we can ignore it */
pfree(srcpath); pfree(srcpath);
...@@ -352,7 +379,8 @@ createdb(const CreatedbStmt *stmt) ...@@ -352,7 +379,8 @@ createdb(const CreatedbStmt *stmt)
remove_dbtablespaces(dboid); remove_dbtablespaces(dboid);
ereport(ERROR, ereport(ERROR,
(errmsg("could not initialize database directory"), (errmsg("could not initialize database directory"),
errdetail("Directory \"%s\" already exists.", dstpath))); errdetail("Directory \"%s\" already exists.",
dstpath)));
} }
#ifndef WIN32 #ifndef WIN32
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.11 2004/08/30 02:54:38 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.12 2004/10/17 20:47:20 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -75,7 +75,6 @@ ...@@ -75,7 +75,6 @@
static bool remove_tablespace_directories(Oid tablespaceoid, bool redo); static bool remove_tablespace_directories(Oid tablespaceoid, bool redo);
static void set_short_version(const char *path); static void set_short_version(const char *path);
static bool directory_is_empty(const char *path);
/* /*
...@@ -680,8 +679,10 @@ set_short_version(const char *path) ...@@ -680,8 +679,10 @@ set_short_version(const char *path)
/* /*
* Check if a directory is empty. * Check if a directory is empty.
*
* This probably belongs somewhere else, but not sure where...
*/ */
static bool bool
directory_is_empty(const char *path) directory_is_empty(const char *path)
{ {
DIR *dirdesc; DIR *dirdesc;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/tablespace.h,v 1.5 2004/08/30 02:54:40 momjian Exp $ * $PostgreSQL: pgsql/src/include/commands/tablespace.h,v 1.6 2004/10/17 20:47:21 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -42,6 +42,8 @@ extern void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo); ...@@ -42,6 +42,8 @@ extern void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo);
extern Oid get_tablespace_oid(const char *tablespacename); extern Oid get_tablespace_oid(const char *tablespacename);
extern char *get_tablespace_name(Oid spc_oid); extern char *get_tablespace_name(Oid spc_oid);
extern bool directory_is_empty(const char *path);
extern void tblspc_redo(XLogRecPtr lsn, XLogRecord *rptr); extern void tblspc_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void tblspc_undo(XLogRecPtr lsn, XLogRecord *rptr); extern void tblspc_undo(XLogRecPtr lsn, XLogRecord *rptr);
extern void tblspc_desc(char *buf, uint8 xl_info, char *rec); extern void tblspc_desc(char *buf, uint8 xl_info, char *rec);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment