diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index c3a45b98db..166fed7233 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.249 2008/01/30 18:35:55 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.250 2008/03/04 19:54:06 tgl Exp $ * * * INTERFACE ROUTINES @@ -868,6 +868,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; + pgstat_initstats(r); return r; @@ -912,6 +916,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; + pgstat_initstats(r); return r; @@ -958,6 +966,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; + pgstat_initstats(r); return r; diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 13c3a0378b..65611089c4 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.257 2008/01/15 18:56:59 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.258 2008/03/04 19:54:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -62,6 +62,13 @@ bool XactSyncCommit = true; 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 @@ -1445,6 +1452,7 @@ StartTransaction(void) XactIsoLevel = DefaultXactIsoLevel; XactReadOnly = DefaultXactReadOnly; forceSyncCommit = false; + MyXactAccessedTempRel = false; /* * reinitialize within-transaction counters @@ -1770,6 +1778,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(); diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c index a882f4e432..67bb2ba9fb 100644 --- a/src/backend/storage/lmgr/lmgr.c +++ b/src/backend/storage/lmgr/lmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.96 2008/01/08 23:18:50 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.97 2008/03/04 19:54:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,12 +19,10 @@ #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" /* @@ -663,44 +661,6 @@ UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid, } -/* - * 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 ((LockTagType) 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 (isTempOrToastNamespace(get_rel_namespace((Oid) tag->locktag_field2))) - return true; - break; - case LOCKTAG_TRANSACTION: - case LOCKTAG_VIRTUALTRANSACTION: - /* 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 */ -} - - /* * Append a description of a lockable object to buf. * diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index 24f9b7782e..c8ba3538cf 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.181 2008/02/02 22:26:17 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.182 2008/03/04 19:54:06 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" @@ -1871,12 +1870,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. */ diff --git a/src/include/access/xact.h b/src/include/access/xact.h index c0020c8bcd..dff05c73db 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/xact.h,v 1.93 2008/01/01 19:45:56 momjian Exp $ + * $PostgreSQL: pgsql/src/include/access/xact.h,v 1.94 2008/03/04 19:54:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -44,6 +44,9 @@ extern bool XactReadOnly; /* Asynchronous commits */ extern bool XactSyncCommit; +/* Kluge for 2PC support */ +extern bool MyXactAccessedTempRel; + /* * start- and end-of-transaction callbacks for dynamically loaded modules */ diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h index b89d0c6c8d..05150afbac 100644 --- a/src/include/storage/lmgr.h +++ b/src/include/storage/lmgr.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/storage/lmgr.h,v 1.60 2008/01/01 19:45:59 momjian Exp $ + * $PostgreSQL: pgsql/src/include/storage/lmgr.h,v 1.61 2008/03/04 19:54:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -72,9 +72,6 @@ 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); - /* Describe a locktag for error messages */ extern void DescribeLockTag(StringInfo buf, const LOCKTAG *tag);