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.
This commit is contained in:
Tom Lane 2004-10-17 20:47:21 +00:00
parent fae7ce83fe
commit 830c168e5c
3 changed files with 43 additions and 12 deletions

View File

@ -9,7 +9,7 @@
*
*
* 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)
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
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
{
@ -311,11 +342,6 @@ createdb(const CreatedbStmt *stmt)
/*
* Iterate through all tablespaces of the template database, and copy
* 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);
scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
@ -333,7 +359,8 @@ createdb(const CreatedbStmt *stmt)
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 */
pfree(srcpath);
@ -352,7 +379,8 @@ createdb(const CreatedbStmt *stmt)
remove_dbtablespaces(dboid);
ereport(ERROR,
(errmsg("could not initialize database directory"),
errdetail("Directory \"%s\" already exists.", dstpath)));
errdetail("Directory \"%s\" already exists.",
dstpath)));
}
#ifndef WIN32

View File

@ -45,7 +45,7 @@
*
*
* 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 @@
static bool remove_tablespace_directories(Oid tablespaceoid, bool redo);
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)
/*
* Check if a directory is empty.
*
* This probably belongs somewhere else, but not sure where...
*/
static bool
bool
directory_is_empty(const char *path)
{
DIR *dirdesc;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
* 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);
extern Oid get_tablespace_oid(const char *tablespacename);
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_undo(XLogRecPtr lsn, XLogRecord *rptr);
extern void tblspc_desc(char *buf, uint8 xl_info, char *rec);