]> granicus.if.org Git - postgresql/commitdiff
Give a more user-friendly error message in situation where CREATE DATABASE
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 17 Oct 2004 20:47:21 +0000 (20:47 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 17 Oct 2004 20:47:21 +0000 (20:47 +0000)
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.

src/backend/commands/dbcommands.c
src/backend/commands/tablespace.c
src/include/commands/tablespace.h

index 1c9425789aa0d8a575ba0a8556b3633a44a508d0..917429c2b525b673d72e82ce8f393d3c8ea6384f 100644 (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
index b9fbd2b5eabe7bd0013edcd69f6d7a330b01e098..1cbeef657aed9c80a0784da2dab6ee570936883a 100644 (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;
index 7e99c7e6b78f60f4bcab071d0d3f9bec099f720b..58ad23ae161c14cc855339add6710504ff0a2807 100644 (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);