Disallow DROP TABLE/DROP INDEX inside a transaction block.
authorTom Lane
Sun, 5 Sep 1999 17:43:47 +0000 (17:43 +0000)
committerTom Lane
Sun, 5 Sep 1999 17:43:47 +0000 (17:43 +0000)
We can't support these properly, since once the relation's physical files
are unlinked, there's no way to roll back the transaction.  I suppose
we could postpone the unlink till transaction commit, but then what of
BEGIN; DROP TABLE foo; CREATE TABLE foo; ?
The code does allow dropping a table/index created in the current
transaction block, however, since the post-abort state would be that
the table doesn't exist anyway.

src/backend/catalog/heap.c
src/backend/catalog/index.c

index b571cf3f817931af2d01b637ccc5a9e4614f0919..561cb21a418d2479ad30cdd14eedae3cd5a1e0a9 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.94 1999/09/04 22:00:29 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.95 1999/09/05 17:43:47 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -30,6 +30,7 @@
 #include "miscadmin.h"
 
 #include "access/heapam.h"
+#include "access/xact.h"
 #include "catalog/catalog.h"
 #include "catalog/catname.h"
 #include "catalog/heap.h"
@@ -1232,7 +1233,7 @@ heap_destroy_with_catalog(char *relname)
    bool        istemp = (get_temp_rel_by_name(relname) != NULL);
 
    /* ----------------
-    *  first open the relation.  if the relation does exist,
+    *  first open the relation.  if the relation doesn't exist,
     *  heap_openr() returns NULL.
     * ----------------
     */
@@ -1253,6 +1254,17 @@ heap_destroy_with_catalog(char *relname)
        elog(ERROR, "System relation '%s' cannot be destroyed",
             &rel->rd_rel->relname);
 
+   /* ----------------
+    *  We do not allow DROP TABLE within a transaction block, because
+    *  if the transaction is later rolled back there would be no way to
+    *  undo the unlink of the relation's physical file.  The sole exception
+    *  is for relations created in the current transaction, since the post-
+    *  abort state would be that they don't exist anyway.
+    * ----------------
+    */
+   if (IsTransactionBlock() && ! rel->rd_myxactonly)
+       elog(ERROR, "Cannot destroy relation within a transaction block");
+
    /* ----------------
     *  remove inheritance information
     * ----------------
@@ -1307,17 +1319,10 @@ heap_destroy_with_catalog(char *relname)
     */
    ReleaseRelationBuffers(rel);
 
-   /* ----------------
-    *  flush the relation from the relcache
-    * ----------------
-    * Does nothing!!! Flushing moved below.    - vadim 06/04/97
-   RelationIdInvalidateRelationCacheByRelationId(rel->rd_id);
-    */
-
    RemoveConstraints(rel);
 
    /* ----------------
-    *  unlink the relation and finish up.
+    *  unlink the relation's physical file and finish up.
     * ----------------
     */
    if (!(rel->rd_isnoname) || !(rel->rd_nonameunlinked))
@@ -1329,6 +1334,10 @@ heap_destroy_with_catalog(char *relname)
 
    heap_close(rel);
 
+   /* ----------------
+    *  flush the relation from the relcache
+    * ----------------
+    */
    RelationForgetRelation(rid);
 }
 
index d52731bac237e13c032135720ac5e35ce8c4edad..c90c27fd5de55c64cfb922714d07e37ceb865e25 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.88 1999/09/04 22:00:29 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.89 1999/09/05 17:43:47 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -23,6 +23,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/istrat.h"
+#include "access/xact.h"
 #include "bootstrap/bootstrap.h"
 #include "catalog/catname.h"
 #include "catalog/heap.h"
@@ -1105,6 +1106,17 @@ index_destroy(Oid indexId)
    /* Open now to obtain lock by referencing table?  bjm */
    userindexRelation = index_open(indexId);
 
+   /* ----------------
+    *  We do not allow DROP INDEX within a transaction block, because
+    *  if the transaction is later rolled back there would be no way to
+    *  undo the unlink of the relation's physical file.  The sole exception
+    *  is for relations created in the current transaction, since the post-
+    *  abort state would be that they don't exist anyway.
+    * ----------------
+    */
+   if (IsTransactionBlock() && ! userindexRelation->rd_myxactonly)
+       elog(ERROR, "Cannot destroy index within a transaction block");
+
    /* ----------------
     * fix RELATION relation
     * ----------------
@@ -1164,7 +1176,7 @@ index_destroy(Oid indexId)
    ReleaseRelationBuffers(userindexRelation);
 
    if (smgrunlink(DEFAULT_SMGR, userindexRelation) != SM_SUCCESS)
-       elog(ERROR, "amdestroyr: unlink: %m");
+       elog(ERROR, "index_destroy: unlink: %m");
 
    index_close(userindexRelation);
    RelationForgetRelation(RelationGetRelid(userindexRelation));