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;
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;
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;
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
XactIsoLevel = DefaultXactIsoLevel;
XactReadOnly = DefaultXactReadOnly;
forceSyncCommit = false;
+ MyXactAccessedTempRel = false;
/*
* reinitialize within-transaction counters
/* 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();
#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"
/*
}
-/*
- * 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.
*
#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"
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.
*/
/* Asynchronous commits */
extern bool XactSyncCommit;
+/* Kluge for 2PC support */
+extern bool MyXactAccessedTempRel;
+
/*
* start- and end-of-transaction callbacks for dynamically loaded modules
*/
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);