]> granicus.if.org Git - postgresql/commitdiff
Fix PREPARE TRANSACTION to reject the case where the transaction has dropped a
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 4 Mar 2008 19:54:23 +0000 (19:54 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 4 Mar 2008 19:54:23 +0000 (19:54 +0000)
temporary table; we can't support that because there's no way to clean up the
source backend's internal state if the eventual COMMIT PREPARED is done by
another backend.  This was checked correctly in 8.1 but I broke it in 8.2 :-(.
Patch by Heikki Linnakangas, original trouble report by John Smith.

src/backend/access/heap/heapam.c
src/backend/access/transam/xact.c
src/backend/storage/lmgr/lmgr.c
src/backend/storage/lmgr/lock.c
src/include/access/xact.h
src/include/storage/lmgr.h

index 1889d09784c62e13cb353d0ece4cc362f1e3f2d0..aade7a29c1349b100f2801eec0a856647d75f30a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.222.2.1 2007/02/04 20:00:49 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.222.2.2 2008/03/04 19:54:23 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -699,6 +699,10 @@ relation_open(Oid relationId, LOCKMODE lockmode)
        if (!RelationIsValid(r))
                elog(ERROR, "could not open relation with OID %u", relationId);
 
+       /* Make note that we've accessed a temporary relation */
+       if (r->rd_istemp)
+               MyXactAccessedTempRel = true;
+
        return r;
 }
 
@@ -741,6 +745,10 @@ try_relation_open(Oid relationId, LOCKMODE lockmode)
        if (!RelationIsValid(r))
                elog(ERROR, "could not open relation with OID %u", relationId);
 
+       /* Make note that we've accessed a temporary relation */
+       if (r->rd_istemp)
+               MyXactAccessedTempRel = true;
+
        return r;
 }
 
@@ -785,6 +793,10 @@ relation_open_nowait(Oid relationId, LOCKMODE lockmode)
        if (!RelationIsValid(r))
                elog(ERROR, "could not open relation with OID %u", relationId);
 
+       /* Make note that we've accessed a temporary relation */
+       if (r->rd_istemp)
+               MyXactAccessedTempRel = true;
+
        return r;
 }
 
index e000547b327663b50c63600ecab102071be4db64..6ef1f5a74202eaefcc46888dcfbebed4f63479b8 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.229.2.3 2008/01/03 21:23:45 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.229.2.4 2008/03/04 19:54:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -57,6 +57,13 @@ bool         XactReadOnly;
 int                    CommitDelay = 0;        /* precommit delay in microseconds */
 int                    CommitSiblings = 5; /* # concurrent xacts needed to sleep */
 
+/*
+ * MyXactAccessedTempRel is set when a temporary relation is accessed.
+ * We don't allow PREPARE TRANSACTION in that case.  (This is global
+ * so that it can be set from heapam.c.)
+ */
+bool           MyXactAccessedTempRel = false;
+
 
 /*
  *     transaction states - transaction state from server perspective
@@ -1389,6 +1396,7 @@ StartTransaction(void)
        FreeXactSnapshot();
        XactIsoLevel = DefaultXactIsoLevel;
        XactReadOnly = DefaultXactReadOnly;
+       MyXactAccessedTempRel = false;
 
        /*
         * reinitialize within-transaction counters
@@ -1715,6 +1723,26 @@ PrepareTransaction(void)
 
        /* NOTIFY and flatfiles will be handled below */
 
+       /*
+        * Don't allow PREPARE TRANSACTION if we've accessed a temporary table
+        * in this transaction.  Having the prepared xact hold locks on another
+        * backend's temp table seems a bad idea --- for instance it would prevent
+        * the backend from exiting.  There are other problems too, such as how
+        * to clean up the source backend's local buffers and ON COMMIT state
+        * if the prepared xact includes a DROP of a temp table.
+        *
+        * We must check this after executing any ON COMMIT actions, because
+        * they might still access a temp relation.
+        *
+        * XXX In principle this could be relaxed to allow some useful special
+        * cases, such as a temp table created and dropped all within the
+        * transaction.  That seems to require much more bookkeeping though.
+        */
+       if (MyXactAccessedTempRel)
+               ereport(ERROR,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("cannot PREPARE a transaction that has operated on temporary tables")));
+
        /* Prevent cancel/die interrupt while cleaning up */
        HOLD_INTERRUPTS();
 
index 4a4c0990ad26329a123f53ba92381f35b1777736..25cd40cd1bdc3f065243566ad369374b23f28014 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.89 2006/10/04 00:29:57 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.89.2.1 2008/03/04 19:54:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "access/transam.h"
 #include "access/xact.h"
 #include "catalog/catalog.h"
-#include "catalog/namespace.h"
 #include "miscadmin.h"
 #include "storage/lmgr.h"
 #include "storage/procarray.h"
 #include "utils/inval.h"
-#include "utils/lsyscache.h"
 
 
 /*
@@ -598,40 +596,3 @@ UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
 
        LockRelease(&tag, lockmode, false);
 }
-
-
-/*
- * LockTagIsTemp
- *             Determine whether a locktag is for a lock on a temporary object
- *
- * We need this because 2PC cannot deal with temp objects
- */
-bool
-LockTagIsTemp(const LOCKTAG *tag)
-{
-       switch (tag->locktag_type)
-       {
-               case LOCKTAG_RELATION:
-               case LOCKTAG_RELATION_EXTEND:
-               case LOCKTAG_PAGE:
-               case LOCKTAG_TUPLE:
-                       /* check for lock on a temp relation */
-                       /* field1 is dboid, field2 is reloid for all of these */
-                       if ((Oid) tag->locktag_field1 == InvalidOid)
-                               return false;   /* shared, so not temp */
-                       if (isTempNamespace(get_rel_namespace((Oid) tag->locktag_field2)))
-                               return true;
-                       break;
-               case LOCKTAG_TRANSACTION:
-                       /* there are no temp transactions */
-                       break;
-               case LOCKTAG_OBJECT:
-                       /* there are currently no non-table temp objects */
-                       break;
-               case LOCKTAG_USERLOCK:
-               case LOCKTAG_ADVISORY:
-                       /* assume these aren't temp */
-                       break;
-       }
-       return false;                           /* default case */
-}
index a8d2ad01d9feb78ed17aeed120c4f335d7ee3603..a49002e4d0749060bf45de9098a1fc311ceed0c1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.174.2.1 2008/02/02 22:26:23 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.174.2.2 2008/03/04 19:54:23 tgl Exp $
  *
  * NOTES
  *       A lock table is a shared memory hash table.  When
@@ -37,7 +37,6 @@
 #include "access/twophase_rmgr.h"
 #include "miscadmin.h"
 #include "pgstat.h"
-#include "storage/lmgr.h"
 #include "utils/memutils.h"
 #include "utils/ps_status.h"
 #include "utils/resowner.h"
@@ -1849,12 +1848,6 @@ AtPrepare_Locks(void)
                                elog(ERROR, "cannot PREPARE when session locks exist");
                }
 
-               /* Can't handle it if the lock is on a temporary object */
-               if (LockTagIsTemp(&locallock->tag.lock))
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                        errmsg("cannot PREPARE a transaction that has operated on temporary tables")));
-
                /*
                 * Create a 2PC record.
                 */
index 5b4411d77be020da9790d2d941ff9428e15f299e..ede75c6518afef794699447380ed1b87cc5c3079 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/xact.h,v 1.83 2006/07/11 18:26:11 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/access/xact.h,v 1.83.2.1 2008/03/04 19:54:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -41,6 +41,9 @@ extern int    XactIsoLevel;
 extern bool DefaultXactReadOnly;
 extern bool XactReadOnly;
 
+/* Kluge for 2PC support */
+extern bool MyXactAccessedTempRel;
+
 /*
  *     start- and end-of-transaction callbacks for dynamically loaded modules
  */
index ea7a1bf948f0942815c3835098a5255241d7b7c7..832f3e201bce90a35e3001fe38366dbb95105b65 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/storage/lmgr.h,v 1.56 2006/08/18 16:09:13 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/lmgr.h,v 1.56.2.1 2008/03/04 19:54:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -66,7 +66,4 @@ extern void LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
 extern void UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
                                   LOCKMODE lockmode);
 
-/* Knowledge about which locktags describe temp objects */
-extern bool LockTagIsTemp(const LOCKTAG *tag);
-
 #endif   /* LMGR_H */