### Eclipse Workspace Patch 1.0
#P Postgres-HEAD
Index: src/test/regress/parallel_schedule
===================================================================
RCS file: /root/cvsrepo/pgsql/src/test/regress/parallel_schedule,v
retrieving revision 1.50
diff -u -r1.50 parallel_schedule
--- src/test/regress/parallel_schedule	31 Oct 2008 09:17:16 -0000	1.50
+++ src/test/regress/parallel_schedule	8 Dec 2008 19:38:28 -0000
@@ -90,3 +90,25 @@
 
 # run tablespace by itself
 test: tablespace
+
+# --------
+# 2PC related tests
+# --------
+test: 2pc_persistent_table 
+test: 2pc_on_delete_rows_transaction
+test: 2pc_on_commit_drop_transaction
+test: 2pc_on_commit_drop_session
+test: 2pc_temp_table_transaction
+test: 2pc_temp_table_rollback 
+test: 2pc_temp_table_savepoint 
+test: 2pc_temp_table_failure
+test: 2pc_dirty_buffer_check 
+test: 2pc_temp_table_session
+test: 2pc_on_delete_rows_session
+# The following tests must be executing in sequence, 
+# do not alter the order nor try to execute them in parallel
+test: 2pc_temp_table_prepared_not_committed
+test: 2pc_temp_table_commit_prepared
+# This test must be run last to check if the database properly 
+# shutdowns with a prepared transaction that is not committed
+test: 2pc_temp_table_prepared_not_committed
Index: src/test/regress/serial_schedule
===================================================================
RCS file: /root/cvsrepo/pgsql/src/test/regress/serial_schedule,v
retrieving revision 1.47
diff -u -r1.47 serial_schedule
--- src/test/regress/serial_schedule	31 Oct 2008 09:17:16 -0000	1.47
+++ src/test/regress/serial_schedule	8 Dec 2008 19:38:28 -0000
@@ -119,3 +119,20 @@
 test: xml
 test: stats
 test: tablespace
+test: 2pc_persistent_table
+test: 2pc_on_delete_rows_transaction
+test: 2pc_on_commit_drop
+test: 2pc_temp_table_transaction
+test: 2pc_temp_table_rollback
+test: 2pc_temp_table_savepoint
+test: 2pc_dirty_buffer_check 
+test: 2pc_temp_table_session
+test: 2pc_on_delete_rows_session
+test: 2pc_temp_table_failure
+# The following tests must be executing in sequence, 
+# do not alter the order nor try to execute them in parallel
+test: 2pc_temp_table_prepared_not_committed
+test: 2pc_temp_table_commit_prepared
+# This test must be run last to check if the database properly 
+# shutdowns with a prepared transaction that is not committed
+test: 2pc_temp_table_prepared_not_committed
Index: src/backend/storage/lmgr/lock.c
===================================================================
RCS file: /root/cvsrepo/pgsql/src/backend/storage/lmgr/lock.c,v
retrieving revision 1.185
diff -u -r1.185 lock.c
--- src/backend/storage/lmgr/lock.c	2 Nov 2008 21:24:52 -0000	1.185
+++ src/backend/storage/lmgr/lock.c	8 Dec 2008 19:38:28 -0000
@@ -35,6 +35,7 @@
 #include "access/transam.h"
 #include "access/twophase.h"
 #include "access/twophase_rmgr.h"
+#include "commands/tablecmds.h"
 #include "miscadmin.h"
 #include "pg_trace.h"
 #include "pgstat.h"
@@ -1816,19 +1817,66 @@
 	return vxids;
 }
 
+/*
+ * A helper function to determine whether the given lock should be
+ * prepared
+ */
+static bool
+is_preparable_locktag(LOCKTAG *lock)
+{
+	/* Ignore nontransactional locks */
+	if (!LockMethods[lock->locktag_lockmethodid]->transactional)
+		return false;
+
+	/* Locks on temporary tables are dropped in PREPARE phase */
+	switch (lock->locktag_type)
+	{
+		case LOCKTAG_RELATION_EXTEND:
+		case LOCKTAG_PAGE:
+		case LOCKTAG_TUPLE:
+			/*
+			 * These lock types are only held transiently, we shouldn't
+			 * be holding any at the end of transaction.
+			 */
+			elog(ERROR, "unexpected lock type at PREPARE TRANSACTION");
+
+		case LOCKTAG_VIRTUALTRANSACTION:
+			/*
+			 * Ignore VXID locks.  We don't want those to be held by
+			 * prepared transactions, since they aren't meaningful after
+			 * a restart.
+			 */
+			return false;
+	
+		case LOCKTAG_RELATION:
+			/*
+			 * Locks on temporary relations are not persisted. That means
+			 * that they're dropped early, in the PREPARE phase. We only
+			 * allow that in some narrow cases, which
+			 * AtPrepare_on_commit_actions has already checked for.
+			 */
+			/* field1 is dboid, field2 is reloid for all of these */
+			if ((Oid) lock->locktag_field1 == InvalidOid)
+				break;   /* shared, so not temp */
+			if (is_temp_rel((Oid) lock->locktag_field2))
+				return false;
+		default:
+			break;
+	}
+	return true;
+}
 
 /*
  * AtPrepare_Locks
  *		Do the preparatory work for a PREPARE: make 2PC state file records
  *		for all locks currently held.
  *
- * Non-transactional locks are ignored, as are VXID locks.
+ * Non-transactional and VXID locks are ignored. Locks on temporary objects
+ * are also ignored, because that would mess up the current backend if it
+ * tries to exit before the prepared xact is committed.
  *
  * There are some special cases that we error out on: we can't be holding
- * any session locks (should be OK since only VACUUM uses those) and we
- * can't be holding any locks on temporary objects (since that would mess
- * up the current backend if it tries to exit before the prepared xact is
- * committed).
+ * any session locks (should be OK since only VACUUM uses those).
  */
 void
 AtPrepare_Locks(void)
@@ -1848,21 +1896,14 @@
 		LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
 		int			i;
 
-		/* Ignore nontransactional locks */
-		if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
-			continue;
-
-		/*
-		 * Ignore VXID locks.  We don't want those to be held by prepared
-		 * transactions, since they aren't meaningful after a restart.
-		 */
-		if (locallock->tag.lock.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
-			continue;
-
 		/* Ignore it if we don't actually hold the lock */
 		if (locallock->nLocks <= 0)
 			continue;
 
+		/* Does the lock need to be persisted? */
+		if (!is_preparable_locktag(&locallock->tag.lock))
+			continue;
+	
 		/* Scan to verify there are no session locks */
 		for (i = locallock->numLockOwners - 1; i >= 0; i--)
 		{
@@ -1936,12 +1977,8 @@
 			continue;
 		}
 
-		/* Ignore nontransactional locks */
-		if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
-			continue;
-
-		/* Ignore VXID locks */
-		if (locallock->tag.lock.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
+		/* Does the lock need to be persisted? */
+		if (!is_preparable_locktag(&locallock->tag.lock))
 			continue;
 
 		/* We already checked there are no session locks */
@@ -1985,12 +2022,8 @@
 
 			lock = proclock->tag.myLock;
 
-			/* Ignore nontransactional locks */
-			if (!LockMethods[LOCK_LOCKMETHOD(*lock)]->transactional)
-				goto next_item;
-
-			/* Ignore VXID locks */
-			if (lock->tag.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
+			/* Does the lock need to be persisted? */
+			if (!is_preparable_locktag(&lock->tag))
 				goto next_item;
 
 			PROCLOCK_PRINT("PostPrepare_Locks", proclock);
Index: src/backend/catalog/heap.c
===================================================================
RCS file: /root/cvsrepo/pgsql/src/backend/catalog/heap.c,v
retrieving revision 1.342
diff -u -r1.342 heap.c
--- src/backend/catalog/heap.c	2 Nov 2008 01:45:27 -0000	1.342
+++ src/backend/catalog/heap.c	8 Dec 2008 19:38:28 -0000
@@ -39,6 +39,7 @@
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/indexing.h"
+#include "catalog/namespace.h"
 #include "catalog/pg_attrdef.h"
 #include "catalog/pg_constraint.h"
 #include "catalog/pg_inherits.h"
@@ -1037,10 +1038,10 @@
 	StoreConstraints(new_rel_desc, cooked_constraints);
 
 	/*
-	 * If there's a special on-commit action, remember it
+	 * Register to the on commit action handler, if it's a temporary table.
 	 */
-	if (oncommit != ONCOMMIT_NOOP)
-		register_on_commit_action(relid, oncommit);
+	if (isTempOrToastNamespace(relnamespace))
+		register_temp_rel(relid, relkind, oncommit);
 
 	/*
 	 * ok, the relation has been cataloged, so close our relations and return
@@ -1418,9 +1419,9 @@
 	relation_close(rel, NoLock);
 
 	/*
-	 * Forget any ON COMMIT action for the rel
+	 * Unregister any ON COMMIT action for the relation.
 	 */
-	remove_on_commit_action(relid);
+	unregister_temp_rel(relid);
 
 	/*
 	 * Flush the relation from the relcache.  We want to do this before
Index: src/backend/catalog/index.c
===================================================================
RCS file: /root/cvsrepo/pgsql/src/backend/catalog/index.c,v
retrieving revision 1.307
diff -u -r1.307 index.c
--- src/backend/catalog/index.c	2 Nov 2008 01:45:27 -0000	1.307
+++ src/backend/catalog/index.c	8 Dec 2008 19:38:28 -0000
@@ -883,6 +883,14 @@
 	}
 
 	/*
+	 * Register to the on commit action handler, if it's a temporary table.
+	 * Indexes can't have any ON COMMIT actions, but the registration is
+	 * still needed to handle PREPARE TRANSACTION correctly.
+	 */
+	if (isTempOrToastNamespace(namespaceId))
+		register_temp_rel(indexRelationId, RELKIND_INDEX, ONCOMMIT_NOOP);
+
+	/*
 	 * Close the heap and index; but we keep the locks that we acquired above
 	 * until end of transaction.
 	 */
@@ -963,6 +971,11 @@
 	heap_close(indexRelation, RowExclusiveLock);
 
 	/*
+	 * Unregister from the on commit action handler.
+	 */
+	unregister_temp_rel(indexId);
+
+	/*
 	 * if it has any expression columns, we might have stored statistics about
 	 * them.
 	 */
Index: src/include/access/xact.h
===================================================================
RCS file: /root/cvsrepo/pgsql/src/include/access/xact.h,v
retrieving revision 1.95
diff -u -r1.95 xact.h
--- src/include/access/xact.h	11 Aug 2008 11:05:11 -0000	1.95
+++ src/include/access/xact.h	8 Dec 2008 19:38:28 -0000
@@ -44,9 +44,6 @@
 /* Asynchronous commits */
 extern bool XactSyncCommit;
 
-/* Kluge for 2PC support */
-extern bool MyXactAccessedTempRel;
-
 /*
  *	start- and end-of-transaction callbacks for dynamically loaded modules
  */
Index: src/backend/access/transam/xact.c
===================================================================
RCS file: /root/cvsrepo/pgsql/src/backend/access/transam/xact.c,v
retrieving revision 1.266
diff -u -r1.266 xact.c
--- src/backend/access/transam/xact.c	20 Oct 2008 19:18:18 -0000	1.266
+++ src/backend/access/transam/xact.c	8 Dec 2008 19:38:28 -0000
@@ -66,14 +66,6 @@
 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
  */
 typedef enum TransState
@@ -1466,7 +1458,6 @@
 	XactIsoLevel = DefaultXactIsoLevel;
 	XactReadOnly = DefaultXactReadOnly;
 	forceSyncCommit = false;
-	MyXactAccessedTempRel = false;
 
 	/*
 	 * reinitialize within-transaction counters
@@ -1797,26 +1788,6 @@
 
 	/* 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();
 
@@ -1860,6 +1831,7 @@
 	AtPrepare_Notify();
 	AtPrepare_UpdateFlatFiles();
 	AtPrepare_Inval();
+	AtPrepare_on_commit_actions();
 	AtPrepare_Locks();
 	AtPrepare_PgStat();
 
Index: src/backend/access/heap/heapam.c
===================================================================
RCS file: /root/cvsrepo/pgsql/src/backend/access/heap/heapam.c,v
retrieving revision 1.268
diff -u -r1.268 heapam.c
--- src/backend/access/heap/heapam.c	31 Oct 2008 19:40:26 -0000	1.268
+++ src/backend/access/heap/heapam.c	8 Dec 2008 19:38:28 -0000
@@ -51,6 +51,7 @@
 #include "access/xlogutils.h"
 #include "catalog/catalog.h"
 #include "catalog/namespace.h"
+#include "commands/tablecmds.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "storage/bufmgr.h"
@@ -878,7 +879,7 @@
 
 	/* Make note that we've accessed a temporary relation */
 	if (r->rd_istemp)
-		MyXactAccessedTempRel = true;
+		register_temp_rel_access(relationId);
 
 	pgstat_initstats(r);
 
@@ -926,7 +927,7 @@
 
 	/* Make note that we've accessed a temporary relation */
 	if (r->rd_istemp)
-		MyXactAccessedTempRel = true;
+		register_temp_rel_access(relationId);
 
 	pgstat_initstats(r);
 
@@ -976,7 +977,7 @@
 
 	/* Make note that we've accessed a temporary relation */
 	if (r->rd_istemp)
-		MyXactAccessedTempRel = true;
+		register_temp_rel_access(relationId);
 
 	pgstat_initstats(r);
 
Index: src/include/commands/tablecmds.h
===================================================================
RCS file: /root/cvsrepo/pgsql/src/include/commands/tablecmds.h,v
retrieving revision 1.41
diff -u -r1.41 tablecmds.h
--- src/include/commands/tablecmds.h	19 Jun 2008 00:46:06 -0000	1.41
+++ src/include/commands/tablecmds.h	8 Dec 2008 19:38:28 -0000
@@ -61,9 +61,12 @@
 extern AttrNumber *varattnos_map_schema(TupleDesc old, List *schema);
 extern void change_varattnos_of_a_node(Node *node, const AttrNumber *newattno);
 
-extern void register_on_commit_action(Oid relid, OnCommitAction action);
-extern void remove_on_commit_action(Oid relid);
+extern void register_temp_rel(Oid relid, char relkind, OnCommitAction action);
+extern void unregister_temp_rel(Oid relid);
+extern void register_temp_rel_access(Oid relid);
+extern bool is_temp_rel(Oid relid);
 
+extern void AtPrepare_on_commit_actions(void);
 extern void PreCommit_on_commit_actions(void);
 extern void AtEOXact_on_commit_actions(bool isCommit);
 extern void AtEOSubXact_on_commit_actions(bool isCommit,
Index: src/include/executor/executor.h
===================================================================
RCS file: /root/cvsrepo/pgsql/src/include/executor/executor.h,v
retrieving revision 1.152
diff -u -r1.152 executor.h
--- src/include/executor/executor.h	31 Oct 2008 21:07:55 -0000	1.152
+++ src/include/executor/executor.h	8 Dec 2008 19:38:28 -0000
@@ -155,6 +155,8 @@
 extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids);
 extern void ExecConstraints(ResultRelInfo *resultRelInfo,
 				TupleTableSlot *slot, EState *estate);
+extern const char *ExecRelCheck(ResultRelInfo *resultRelInfo,
+			 TupleTableSlot *slot, EState *estate);
 extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
 			 ItemPointer tid, TransactionId priorXmax);
 extern PlanState *ExecGetActivePlanTree(QueryDesc *queryDesc);
Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /root/cvsrepo/pgsql/src/backend/commands/tablecmds.c,v
retrieving revision 1.269
diff -u -r1.269 tablecmds.c
--- src/backend/commands/tablecmds.c	2 Nov 2008 01:45:27 -0000	1.269
+++ src/backend/commands/tablecmds.c	8 Dec 2008 19:38:28 -0000
@@ -83,6 +83,7 @@
 typedef struct OnCommitItem
 {
 	Oid			relid;			/* relid of relation */
+	char		relkind;		/* relkind of relation */
 	OnCommitAction oncommit;	/* what to do at end of xact */
 
 	/*
@@ -94,9 +95,10 @@
 	 */
 	SubTransactionId creating_subid;
 	SubTransactionId deleting_subid;
+	SubTransactionId accessing_subid;
 } OnCommitItem;
 
-static List *on_commits = NIL;
+static HTAB *on_commits = NULL;
 
 
 /*
@@ -295,7 +297,7 @@
 static void ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
 						  FkConstraint *fkconstraint);
 static void ATExecDropConstraint(Relation rel, const char *constrName,
-								 DropBehavior behavior, 
+								 DropBehavior behavior,
 								 bool recurse, bool recursing);
 static void ATPrepAlterColumnType(List **wqueue,
 					  AlteredTableInfo *tab, Relation rel,
@@ -7573,40 +7575,53 @@
 
 
 /*
- * This code supports
+ * This code keeps track of all temporary relations in the current session,
+ * to support
  *	CREATE TEMP TABLE ... ON COMMIT { DROP | PRESERVE ROWS | DELETE ROWS }
  *
+ * and to implement the special handling of temporary relations at
+ * PREPARE TRANSACTION.
+ *
  * Because we only support this for TEMP tables, it's sufficient to remember
  * the state in a backend-local data structure.
  */
 
 /*
- * Register a newly-created relation's ON COMMIT action.
+ * Register a newly-created temporary relation.
  */
 void
-register_on_commit_action(Oid relid, OnCommitAction action)
+register_temp_rel(Oid relid, char relkind, OnCommitAction action)
 {
 	OnCommitItem *oc;
-	MemoryContext oldcxt;
+	bool		  found;
 
-	/*
-	 * We needn't bother registering the relation unless there is an ON COMMIT
-	 * action we need to take.
-	 */
-	if (action == ONCOMMIT_NOOP || action == ONCOMMIT_PRESERVE_ROWS)
-		return;
+	if (on_commits == NULL)
+	{
+		HASHCTL		hash_ctl;
+
+		/* Initialize hash table */
+		memset(&hash_ctl, 0, sizeof(hash_ctl));
+		hash_ctl.keysize = sizeof(Oid);
+		hash_ctl.entrysize = sizeof(OnCommitItem);
+		hash_ctl.hcxt = CacheMemoryContext;
+		hash_ctl.hash = oid_hash;
+
+		on_commits = hash_create("On commit actions",
+								 4, /* small initial size to make scans fast */
+								 &hash_ctl,
+								 HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
+	}
 
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+	oc = (OnCommitItem *) hash_search(on_commits, &relid, HASH_ENTER, &found);
+	if (found)
+		elog(ERROR, "relid already in on commit action table");
 
-	oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
 	oc->relid = relid;
+	oc->relkind = relkind;
 	oc->oncommit = action;
 	oc->creating_subid = GetCurrentSubTransactionId();
 	oc->deleting_subid = InvalidSubTransactionId;
-
-	on_commits = lcons(oc, on_commits);
-
-	MemoryContextSwitchTo(oldcxt);
+	oc->accessing_subid = InvalidSubTransactionId;
 }
 
 /*
@@ -7615,20 +7630,33 @@
  * Actually, we only mark the OnCommitItem entry as to be deleted after commit.
  */
 void
-remove_on_commit_action(Oid relid)
+unregister_temp_rel(Oid relid)
 {
-	ListCell   *l;
+	OnCommitItem *oc;
 
-	foreach(l, on_commits)
-	{
-		OnCommitItem *oc = (OnCommitItem *) lfirst(l);
+	if (on_commits == NULL)
+		return;
 
-		if (oc->relid == relid)
-		{
-			oc->deleting_subid = GetCurrentSubTransactionId();
-			break;
-		}
-	}
+	oc = (OnCommitItem *) hash_search(on_commits, &relid, HASH_FIND, NULL);
+
+	if (oc != NULL)
+		oc->deleting_subid = GetCurrentSubTransactionId();
+}
+
+
+/*
+ * Make note that a temporary relation has been accessed in this transaction.
+ * This should be called whenever a lock is acquired on the relation, except
+ * for transient locks that are always released before commit.
+ * relation_open() will usually do that for you.
+ */
+void
+register_temp_rel_access(Oid relid)
+{
+	OnCommitItem *oc;
+
+	oc = (OnCommitItem *) hash_search(on_commits, &relid, HASH_FIND, NULL);
+	oc->accessing_subid = GetCurrentSubTransactionId();
 }
 
 /*
@@ -7640,45 +7668,57 @@
 void
 PreCommit_on_commit_actions(void)
 {
-	ListCell   *l;
+	HASH_SEQ_STATUS seq_status;
 	List	   *oids_to_truncate = NIL;
+	OnCommitItem *oc;
 
-	foreach(l, on_commits)
-	{
-		OnCommitItem *oc = (OnCommitItem *) lfirst(l);
-
-		/* Ignore entry if already dropped in this xact */
-		if (oc->deleting_subid != InvalidSubTransactionId)
-			continue;
+	if (on_commits == NULL)
+		return;
 
-		switch (oc->oncommit)
+	hash_seq_init(&seq_status, on_commits);
+	PG_TRY();
+	{
+		while ((oc = hash_seq_search(&seq_status)) != NULL)
 		{
-			case ONCOMMIT_NOOP:
-			case ONCOMMIT_PRESERVE_ROWS:
-				/* Do nothing (there shouldn't be such entries, actually) */
-				break;
-			case ONCOMMIT_DELETE_ROWS:
-				oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
-				break;
-			case ONCOMMIT_DROP:
-				{
-					ObjectAddress object;
-
-					object.classId = RelationRelationId;
-					object.objectId = oc->relid;
-					object.objectSubId = 0;
-					performDeletion(&object, DROP_CASCADE);
+			/* Ignore entry if already dropped in this xact */
+			if (oc->deleting_subid != InvalidSubTransactionId)
+				continue;
 
-					/*
-					 * Note that table deletion will call
-					 * remove_on_commit_action, so the entry should get marked
-					 * as deleted.
-					 */
-					Assert(oc->deleting_subid != InvalidSubTransactionId);
+			switch (oc->oncommit)
+			{
+				case ONCOMMIT_NOOP:
+				case ONCOMMIT_PRESERVE_ROWS:
+					/* Do nothing */
 					break;
-				}
+				case ONCOMMIT_DELETE_ROWS:
+					oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
+					break;
+				case ONCOMMIT_DROP:
+					{
+						ObjectAddress object;
+
+						object.classId = RelationRelationId;
+						object.objectId = oc->relid;
+						object.objectSubId = 0;
+						performDeletion(&object, DROP_CASCADE);
+
+						/*
+						 * Note that table deletion will call
+						 * remove_on_commit_action, so the entry should get
+						 * marked as deleted.
+						 */
+						Assert(oc->deleting_subid != InvalidSubTransactionId);
+						break;
+					}
+			}
 		}
 	}
+	PG_CATCH();
+	{
+		hash_seq_term(&seq_status);
+	}
+	PG_END_TRY();
+
 	if (oids_to_truncate != NIL)
 	{
 		heap_truncate(oids_to_truncate);
@@ -7687,6 +7727,108 @@
 }
 
 /*
+ * 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.
+ *
+ * However, since PostgreSQL 8.4, we do allow PREPARE TRANSATION if the
+ * transaction has accessed a temporary table with ON COMMIT DELETE ROWS
+ * action, as long as the transaction hasn't created or dropped one.  We
+ * work around the lock problem by releasing the locks early, in the PREPARE
+ * phase. That doesn't violate the two-phase locking protocol (not to be
+ * confused with two-phase commit), as the lock would be released at the
+ * 2nd phase commit or rollback anyway, and the transaction won't acquire
+ * any more locks after PREPARE.
+ *
+ * The reason why we only allow that for ON COMMIT DELETE ROWS tables, is that
+ * some commands like VACUUM FULL and CREATE INDEX get confused if there's
+ * xids in the table that belong to an in-progress transaction. They don't
+ * normally encounter such tuples because they grab an AccessExclusiveLock.
+ *
+ * XXX In principle this could be relaxed to allow some other useful special
+ * cases, such as a temp table created and dropped all within the
+ * transaction.  We would need to at least drop the local buffers, however.
+ * It might also be possible to allow read-only access to temp tables, they
+ * shouldn't pose a problem to commands like VACUUM FULL and CREATE INDEX.
+ */
+void
+AtPrepare_on_commit_actions(void)
+{
+	HASH_SEQ_STATUS seq_status;
+	OnCommitItem *oc;
+
+	if (on_commits == NULL)
+		return;
+
+	hash_seq_init(&seq_status, on_commits);
+	while ((oc = hash_seq_search(&seq_status)) != NULL)
+	{
+		/*
+		 * If the transaction hasn't touched the relation at all, we're fine.
+		 */
+		if (oc->accessing_subid == InvalidSubTransactionId &&
+			oc->creating_subid == InvalidSubTransactionId &&
+			oc->deleting_subid == InvalidSubTransactionId)
+			continue;
+
+		/*
+		 * Allow access to temporary tables that have been created AND dropped
+		 * in this transaction.
+		 */
+		if (oc->creating_subid == oc->deleting_subid && oc->creating_subid != InvalidSubTransactionId)
+		{
+			/*
+			 * XXX If we could release the locks on the relation here,
+			 * AtPrepare_Locks() wouldn't need to treat temp locks specially,
+			 * and we wouldn't need the is_temp_rel() function below. But we
+			 * don't know what locks we're holding, and there's no function
+			 * to release all our locks on a given object.
+			 */
+			continue;
+		}
+		else
+		{
+			hash_seq_term(&seq_status);
+			/* Determine appropriate error message */
+			if (oc->creating_subid != InvalidSubTransactionId)
+				ereport(ERROR,
+						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+						 errmsg("cannot PREPARE a transaction that has created but not dropped a temporary relation")));
+			else if (oc->deleting_subid != InvalidSubTransactionId)
+				ereport(ERROR,
+						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+						 errmsg("cannot PREPARE a transaction that has dropped a temporary relation not created in the transaction")));
+			else
+				ereport(ERROR,
+						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+						 errmsg("cannot PREPARE a transaction that has accessed a temporary tables that was not created and dropped in the transaction")));
+		}
+	}
+}
+
+/*
+ * Is the given relation a temporary table in this backend?
+ */
+bool
+is_temp_rel(Oid relid)
+{
+	OnCommitItem *oc;
+
+	if (on_commits== NULL)
+		return false;
+
+	oc = (OnCommitItem *) hash_search(on_commits, &relid, HASH_FIND, NULL);
+
+	return (oc != NULL);
+}
+
+/*
  * Post-commit or post-abort cleanup for ON COMMIT management.
  *
  * All we do here is remove no-longer-needed OnCommitItem entries.
@@ -7697,34 +7839,27 @@
 void
 AtEOXact_on_commit_actions(bool isCommit)
 {
-	ListCell   *cur_item;
-	ListCell   *prev_item;
+	HASH_SEQ_STATUS seq_status;
+	OnCommitItem *oc;
 
-	prev_item = NULL;
-	cur_item = list_head(on_commits);
+	if (on_commits == NULL)
+		return;
 
-	while (cur_item != NULL)
+	hash_seq_init(&seq_status, on_commits);
+	while ((oc = hash_seq_search(&seq_status)) != NULL)
 	{
-		OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
-
 		if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
 			oc->creating_subid != InvalidSubTransactionId)
 		{
-			/* cur_item must be removed */
-			on_commits = list_delete_cell(on_commits, cur_item, prev_item);
-			pfree(oc);
-			if (prev_item)
-				cur_item = lnext(prev_item);
-			else
-				cur_item = list_head(on_commits);
+			/* current item must be removed */
+			hash_search(on_commits, &oc->relid, HASH_REMOVE, NULL);
 		}
 		else
 		{
-			/* cur_item must be preserved */
+			/* current item must be preserved */
 			oc->creating_subid = InvalidSubTransactionId;
 			oc->deleting_subid = InvalidSubTransactionId;
-			prev_item = cur_item;
-			cur_item = lnext(prev_item);
+			oc->accessing_subid = InvalidSubTransactionId;
 		}
 	}
 }
@@ -7740,35 +7875,29 @@
 AtEOSubXact_on_commit_actions(bool isCommit, SubTransactionId mySubid,
 							  SubTransactionId parentSubid)
 {
-	ListCell   *cur_item;
-	ListCell   *prev_item;
+	HASH_SEQ_STATUS seq_status;
+	OnCommitItem *oc;
 
-	prev_item = NULL;
-	cur_item = list_head(on_commits);
+	if (on_commits == NULL)
+		return;
 
-	while (cur_item != NULL)
+	hash_seq_init(&seq_status, on_commits);
+	while ((oc = hash_seq_search(&seq_status)) != NULL)
 	{
-		OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
-
 		if (!isCommit && oc->creating_subid == mySubid)
 		{
-			/* cur_item must be removed */
-			on_commits = list_delete_cell(on_commits, cur_item, prev_item);
-			pfree(oc);
-			if (prev_item)
-				cur_item = lnext(prev_item);
-			else
-				cur_item = list_head(on_commits);
+			/* current item must be removed */
+			hash_search(on_commits, &oc->relid, HASH_REMOVE, NULL);
 		}
 		else
 		{
-			/* cur_item must be preserved */
+			/* current item must be preserved */
 			if (oc->creating_subid == mySubid)
 				oc->creating_subid = parentSubid;
 			if (oc->deleting_subid == mySubid)
 				oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
-			prev_item = cur_item;
-			cur_item = lnext(prev_item);
+			if (oc->accessing_subid == mySubid)
+				oc->accessing_subid = isCommit ? parentSubid : InvalidSubTransactionId;
 		}
 	}
 }
Index: src/test/regress/expected/2pc_temp_table_savepoint.out
===================================================================
RCS file: src/test/regress/expected/2pc_temp_table_savepoint.out
diff -N src/test/regress/expected/2pc_temp_table_savepoint.out
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_temp_table_savepoint.out	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,8 @@
+-- Rollback to savepoint test case
+BEGIN;
+SAVEPOINT sp;
+CREATE TEMP TABLE foo(bar int4);
+INSERT INTO foo VALUES (1);
+ROLLBACK TO sp;
+PREPARE TRANSACTION 'savepointTestCase_archives.postgresql.org_pgsql-hackers_2008-03_msg00017.php';
+COMMIT PREPARED 'savepointTestCase_archives.postgresql.org_pgsql-hackers_2008-03_msg00017.php';
Index: src/test/regress/expected/2pc_temp_table_transaction.out
===================================================================
RCS file: src/test/regress/expected/2pc_temp_table_transaction.out
diff -N src/test/regress/expected/2pc_temp_table_transaction.out
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_temp_table_transaction.out	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,9 @@
+-- Transaction-scope dropped temp table use case
+begin;
+create temp table foo(x serial primary key);
+NOTICE:  CREATE TABLE will create implicit sequence "foo_x_seq" for serial column "foo.x"
+NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
+insert into foo values(1);
+drop table foo;
+prepare transaction 'dropTempTableShouldSucceed';
+commit prepared 'dropTempTableShouldSucceed';
Index: src/test/regress/sql/2pc_temp_table_rollback.sql
===================================================================
RCS file: src/test/regress/sql/2pc_temp_table_rollback.sql
diff -N src/test/regress/sql/2pc_temp_table_rollback.sql
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_temp_table_rollback.sql	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,5 @@
+-- Rollback prepared
+BEGIN;
+CREATE TEMP TABLE foo(bar int4);
+PREPARE TRANSACTION 'rollbackTestCase_archives.postgresql.org_pgsql-hackers_2008-03_msg00017.php';
+ROLLBACK PREPARED 'rollbackTestCase_archives.postgresql.org_pgsql-hackers_2008-03_msg00017.php';
Index: src/test/regress/sql/2pc_on_delete_rows_transaction.sql
===================================================================
RCS file: src/test/regress/sql/2pc_on_delete_rows_transaction.sql
diff -N src/test/regress/sql/2pc_on_delete_rows_transaction.sql
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_on_delete_rows_transaction.sql	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,13 @@
+-- Temp table with ON DELETE ROWS option (transaction scope)
+begin;
+create temp table foo(x int) on commit delete rows;
+insert into foo values(1);
+prepare transaction 'onCommitDeleteRowsTempTableShouldSucceed';
+commit prepared 'onCommitDeleteRowsTempTableShouldSucceed';
+select * from foo;
+begin;
+insert into foo values(2);
+prepare transaction 'onCommitDeleteRowsTempTableShouldSucceed';
+commit prepared 'onCommitDeleteRowsTempTableShouldSucceed';
+select * from foo;
+drop table foo;
Index: src/test/regress/expected/2pc_on_delete_rows_transaction.out
===================================================================
RCS file: src/test/regress/expected/2pc_on_delete_rows_transaction.out
diff -N src/test/regress/expected/2pc_on_delete_rows_transaction.out
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_on_delete_rows_transaction.out	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,26 @@
+-- Temp table with ON DELETE ROWS option (transaction scope)
+begin;
+create temp table foo(x int) on commit delete rows;
+insert into foo values(1);
+prepare transaction 'onCommitDeleteRowsTempTableShouldSucceed';
+ERROR:  cannot PREPARE a transaction that has created but not dropped a temporary relation
+commit prepared 'onCommitDeleteRowsTempTableShouldSucceed';
+ERROR:  prepared transaction with identifier "onCommitDeleteRowsTempTableShouldSucceed" does not exist
+select * from foo;
+ERROR:  relation "foo" does not exist
+LINE 1: select * from foo;
+                      ^
+begin;
+insert into foo values(2);
+ERROR:  relation "foo" does not exist
+LINE 1: insert into foo values(2);
+                    ^
+prepare transaction 'onCommitDeleteRowsTempTableShouldSucceed';
+commit prepared 'onCommitDeleteRowsTempTableShouldSucceed';
+ERROR:  prepared transaction with identifier "onCommitDeleteRowsTempTableShouldSucceed" does not exist
+select * from foo;
+ERROR:  relation "foo" does not exist
+LINE 1: select * from foo;
+                      ^
+drop table foo;
+ERROR:  table "foo" does not exist
Index: src/test/regress/sql/2pc_temp_table_prepared_not_committed.sql
===================================================================
RCS file: src/test/regress/sql/2pc_temp_table_prepared_not_committed.sql
diff -N src/test/regress/sql/2pc_temp_table_prepared_not_committed.sql
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_temp_table_prepared_not_committed.sql	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,17 @@
+-- The purpose of this test is to test the proper termination of
+-- a session with a prepared transaction that has accessed a temp table
+--
+-- Session-scope temp table use case but exit after prepared
+-- see 2pc_temp_table_commit_prepared.sql for committing that transaction
+create temp table foo1(x int);
+insert into foo1 values(1);
+begin;
+delete from foo1;
+prepare transaction 'preparedNonCommittedFoo1';
+select * from foo1;
+begin;
+create temp table foo2(x serial primary key);
+insert into foo2 values(1);
+drop table foo2;
+prepare transaction 'preparedNonCommittedFoo2';
+VACUUM FULL ANALYZE;
Index: src/test/regress/sql/2pc_temp_table_savepoint.sql
===================================================================
RCS file: src/test/regress/sql/2pc_temp_table_savepoint.sql
diff -N src/test/regress/sql/2pc_temp_table_savepoint.sql
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_temp_table_savepoint.sql	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,8 @@
+-- Rollback to savepoint test case
+BEGIN;
+SAVEPOINT sp;
+CREATE TEMP TABLE foo(bar int4);
+INSERT INTO foo VALUES (1);
+ROLLBACK TO sp;
+PREPARE TRANSACTION 'savepointTestCase_archives.postgresql.org_pgsql-hackers_2008-03_msg00017.php';
+COMMIT PREPARED 'savepointTestCase_archives.postgresql.org_pgsql-hackers_2008-03_msg00017.php';
Index: src/test/regress/sql/2pc_persistent_table.sql
===================================================================
RCS file: src/test/regress/sql/2pc_persistent_table.sql
diff -N src/test/regress/sql/2pc_persistent_table.sql
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_persistent_table.sql	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,12 @@
+-- Creation of a persistent table (not temp)
+begin;
+create table paul(x serial primary key);
+insert into paul values(1);
+prepare transaction 'persistentTableShouldSucceed';
+commit prepared 'persistentTableShouldSucceed';
+
+-- Drop of a persistent table (not temp)
+begin;
+drop table paul;
+prepare transaction 'dropPersistentTableShouldSucceed';
+commit prepared 'dropPersistentTableShouldSucceed';
Index: src/test/regress/expected/2pc_persistent_table.out
===================================================================
RCS file: src/test/regress/expected/2pc_persistent_table.out
diff -N src/test/regress/expected/2pc_persistent_table.out
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_persistent_table.out	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,13 @@
+-- Creation of a persistent table (not temp)
+begin;
+create table paul(x serial primary key);
+NOTICE:  CREATE TABLE will create implicit sequence "paul_x_seq" for serial column "paul.x"
+NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "paul_pkey" for table "paul"
+insert into paul values(1);
+prepare transaction 'persistentTableShouldSucceed';
+commit prepared 'persistentTableShouldSucceed';
+-- Drop of a persistent table (not temp)
+begin;
+drop table paul;
+prepare transaction 'dropPersistentTableShouldSucceed';
+commit prepared 'dropPersistentTableShouldSucceed';
Index: src/test/regress/expected/2pc_temp_table_session.out
===================================================================
RCS file: src/test/regress/expected/2pc_temp_table_session.out
diff -N src/test/regress/expected/2pc_temp_table_session.out
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_temp_table_session.out	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,12 @@
+-- Session-scope temp table use case
+create temp table foo(x serial primary key);
+NOTICE:  CREATE TABLE will create implicit sequence "foo_x_seq" for serial column "foo.x"
+NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
+begin;
+insert into foo values(1);
+delete from foo;
+prepare transaction 'deleteTempTableShouldFail';
+ERROR:  cannot PREPARE a transaction that has accessed a temporary tables that was not created and dropped in the transaction
+commit prepared 'deleteTempTableShouldFail';
+ERROR:  prepared transaction with identifier "deleteTempTableShouldFail" does not exist
+drop table foo;
Index: src/test/regress/expected/2pc_temp_table_commit_prepared.out
===================================================================
RCS file: src/test/regress/expected/2pc_temp_table_commit_prepared.out
diff -N src/test/regress/expected/2pc_temp_table_commit_prepared.out
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_temp_table_commit_prepared.out	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,13 @@
+-- The purpose of this test is to test the proper termination of
+-- a session with a prepared transaction that has accessed a temp table
+--
+-- This test has to be called in sequence after 2pc_temp_table_prepared_not_committed.sql
+commit prepared 'preparedNonCommittedFoo1';
+ERROR:  prepared transaction with identifier "preparedNonCommittedFoo1" does not exist
+-- The table should not exist anymore in this session
+drop table foo1;
+ERROR:  table "foo1" does not exist
+commit prepared 'preparedNonCommittedFoo2';
+-- The table should not exist anymore in this session
+drop table foo2;
+ERROR:  table "foo2" does not exist
Index: src/test/regress/expected/2pc_on_commit_drop_transaction.out
===================================================================
RCS file: src/test/regress/expected/2pc_on_commit_drop_transaction.out
diff -N src/test/regress/expected/2pc_on_commit_drop_transaction.out
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_on_commit_drop_transaction.out	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,8 @@
+-- Temp table with ON COMMIT DROP option
+begin;
+create temp table foo(x serial primary key) on commit drop;
+NOTICE:  CREATE TABLE will create implicit sequence "foo_x_seq" for serial column "foo.x"
+NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
+insert into foo values(1);
+prepare transaction 'onCommitDropTempTableShouldSucceed';
+commit prepared 'onCommitDropTempTableShouldSucceed';
Index: src/test/regress/expected/2pc_temp_table_failure.out
===================================================================
RCS file: src/test/regress/expected/2pc_temp_table_failure.out
diff -N src/test/regress/expected/2pc_temp_table_failure.out
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_temp_table_failure.out	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,21 @@
+-- Existing non-empty temp table at commit time should still fail
+begin;
+create temp table foo(x serial primary key);
+NOTICE:  CREATE TABLE will create implicit sequence "foo_x_seq" for serial column "foo.x"
+NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
+insert into foo values(1);
+prepare transaction 'existingTempTableShouldFail';
+ERROR:  cannot PREPARE a transaction that has created but not dropped a temporary relation
+commit prepared 'existingTempTableShouldFail';
+ERROR:  prepared transaction with identifier "existingTempTableShouldFail" does not exist
+create temp table foo(x serial primary key);
+NOTICE:  CREATE TABLE will create implicit sequence "foo_x_seq" for serial column "foo.x"
+NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
+begin;
+insert into foo values (1);
+prepare transaction 'accessTempTableShouldFail';
+ERROR:  cannot PREPARE a transaction that has accessed a temporary tables that was not created and dropped in the transaction
+begin;
+drop table foo;
+prepare transaction 'dropTempTableShouldFail';
+ERROR:  cannot PREPARE a transaction that has dropped a temporary relation not created in the transaction
Index: src/test/regress/expected/2pc_on_delete_rows_session.out
===================================================================
RCS file: src/test/regress/expected/2pc_on_delete_rows_session.out
diff -N src/test/regress/expected/2pc_on_delete_rows_session.out
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_on_delete_rows_session.out	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,27 @@
+-- Temp table with ON DELETE ROWS option (session scope)
+create temp table foo(x serial primary key) on commit delete rows;
+NOTICE:  CREATE TABLE will create implicit sequence "foo_x_seq" for serial column "foo.x"
+NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
+begin;
+insert into foo values(1);
+prepare transaction 'onCommitDeleteRowsTempTableShouldSucceed';
+ERROR:  cannot PREPARE a transaction that has accessed a temporary tables that was not created and dropped in the transaction
+commit prepared 'onCommitDeleteRowsTempTableShouldSucceed';
+ERROR:  prepared transaction with identifier "onCommitDeleteRowsTempTableShouldSucceed" does not exist
+select * from foo;
+ x
+---
+(0 rows)
+
+begin;
+insert into foo values(2);
+prepare transaction 'onCommitDeleteRowsTempTableShouldSucceed';
+ERROR:  cannot PREPARE a transaction that has accessed a temporary tables that was not created and dropped in the transaction
+commit prepared 'onCommitDeleteRowsTempTableShouldSucceed';
+ERROR:  prepared transaction with identifier "onCommitDeleteRowsTempTableShouldSucceed" does not exist
+select * from foo;
+ x
+---
+(0 rows)
+
+drop table foo;
Index: src/test/regress/sql/2pc_dirty_buffer_check.sql
===================================================================
RCS file: src/test/regress/sql/2pc_dirty_buffer_check.sql
diff -N src/test/regress/sql/2pc_dirty_buffer_check.sql
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_dirty_buffer_check.sql	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,52 @@
+-- 2PC Dirty buffer check
+begin;
+create temp table foo(a int, b int, c int) on commit drop;
+insert into foo values(1,1,1);
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+prepare transaction 'bcd';
+commit prepared 'bcd';
+begin;
+create temp table bar(a int, b int, c int) on commit drop;
+insert into bar values(1,1,1);
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+commit;
Index: src/test/regress/expected/2pc_on_commit_drop_session.out
===================================================================
RCS file: src/test/regress/expected/2pc_on_commit_drop_session.out
diff -N src/test/regress/expected/2pc_on_commit_drop_session.out
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_on_commit_drop_session.out	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,10 @@
+-- Temp table with ON COMMIT DROP option
+create temp table foo(x serial primary key) on commit drop;
+NOTICE:  CREATE TABLE will create implicit sequence "foo_x_seq" for serial column "foo.x"
+NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
+begin;
+insert into foo values(1);
+ERROR:  relation "foo" does not exist
+LINE 1: insert into foo values(1);
+                    ^
+rollback;
Index: src/test/regress/expected/2pc_temp_table_prepared_not_committed.out
===================================================================
RCS file: src/test/regress/expected/2pc_temp_table_prepared_not_committed.out
diff -N src/test/regress/expected/2pc_temp_table_prepared_not_committed.out
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_temp_table_prepared_not_committed.out	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,25 @@
+-- The purpose of this test is to test the proper termination of
+-- a session with a prepared transaction that has accessed a temp table
+--
+-- Session-scope temp table use case but exit after prepared
+-- see 2pc_temp_table_commit_prepared.sql for committing that transaction
+create temp table foo1(x int);
+insert into foo1 values(1);
+begin;
+delete from foo1;
+prepare transaction 'preparedNonCommittedFoo1';
+ERROR:  cannot PREPARE a transaction that has accessed a temporary tables that was not created and dropped in the transaction
+select * from foo1;
+ x
+---
+ 1
+(1 row)
+
+begin;
+create temp table foo2(x serial primary key);
+NOTICE:  CREATE TABLE will create implicit sequence "foo2_x_seq" for serial column "foo2.x"
+NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "foo2_pkey" for table "foo2"
+insert into foo2 values(1);
+drop table foo2;
+prepare transaction 'preparedNonCommittedFoo2';
+VACUUM FULL ANALYZE;
Index: src/test/regress/sql/2pc_on_delete_rows_session.sql
===================================================================
RCS file: src/test/regress/sql/2pc_on_delete_rows_session.sql
diff -N src/test/regress/sql/2pc_on_delete_rows_session.sql
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_on_delete_rows_session.sql	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,13 @@
+-- Temp table with ON DELETE ROWS option (session scope)
+create temp table foo(x serial primary key) on commit delete rows;
+begin;
+insert into foo values(1);
+prepare transaction 'onCommitDeleteRowsTempTableShouldSucceed';
+commit prepared 'onCommitDeleteRowsTempTableShouldSucceed';
+select * from foo;
+begin;
+insert into foo values(2);
+prepare transaction 'onCommitDeleteRowsTempTableShouldSucceed';
+commit prepared 'onCommitDeleteRowsTempTableShouldSucceed';
+select * from foo;
+drop table foo;
Index: src/test/regress/expected/2pc_dirty_buffer_check.out
===================================================================
RCS file: src/test/regress/expected/2pc_dirty_buffer_check.out
diff -N src/test/regress/expected/2pc_dirty_buffer_check.out
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_dirty_buffer_check.out	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,52 @@
+-- 2PC Dirty buffer check
+begin;
+create temp table foo(a int, b int, c int) on commit drop;
+insert into foo values(1,1,1);
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+prepare transaction 'bcd';
+commit prepared 'bcd';
+begin;
+create temp table bar(a int, b int, c int) on commit drop;
+insert into bar values(1,1,1);
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+commit;
Index: src/test/regress/sql/2pc_on_commit_drop_session.sql
===================================================================
RCS file: src/test/regress/sql/2pc_on_commit_drop_session.sql
diff -N src/test/regress/sql/2pc_on_commit_drop_session.sql
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_on_commit_drop_session.sql	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,5 @@
+-- Temp table with ON COMMIT DROP option
+create temp table foo(x serial primary key) on commit drop;
+begin;
+insert into foo values(1);
+rollback;
Index: src/test/regress/sql/2pc_temp_table_commit_prepared.sql
===================================================================
RCS file: src/test/regress/sql/2pc_temp_table_commit_prepared.sql
diff -N src/test/regress/sql/2pc_temp_table_commit_prepared.sql
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_temp_table_commit_prepared.sql	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,10 @@
+-- The purpose of this test is to test the proper termination of
+-- a session with a prepared transaction that has accessed a temp table
+--
+-- This test has to be called in sequence after 2pc_temp_table_prepared_not_committed.sql
+commit prepared 'preparedNonCommittedFoo1';
+-- The table should not exist anymore in this session
+drop table foo1;
+commit prepared 'preparedNonCommittedFoo2';
+-- The table should not exist anymore in this session
+drop table foo2;
Index: src/test/regress/sql/2pc_on_commit_drop_transaction.sql
===================================================================
RCS file: src/test/regress/sql/2pc_on_commit_drop_transaction.sql
diff -N src/test/regress/sql/2pc_on_commit_drop_transaction.sql
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_on_commit_drop_transaction.sql	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,6 @@
+-- Temp table with ON COMMIT DROP option
+begin;
+create temp table foo(x serial primary key) on commit drop;
+insert into foo values(1);
+prepare transaction 'onCommitDropTempTableShouldSucceed';
+commit prepared 'onCommitDropTempTableShouldSucceed';
Index: src/test/regress/sql/2pc_temp_table_transaction.sql
===================================================================
RCS file: src/test/regress/sql/2pc_temp_table_transaction.sql
diff -N src/test/regress/sql/2pc_temp_table_transaction.sql
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_temp_table_transaction.sql	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,7 @@
+-- Transaction-scope dropped temp table use case
+begin;
+create temp table foo(x serial primary key);
+insert into foo values(1);
+drop table foo;
+prepare transaction 'dropTempTableShouldSucceed';
+commit prepared 'dropTempTableShouldSucceed';
Index: src/test/regress/sql/2pc_temp_table_failure.sql
===================================================================
RCS file: src/test/regress/sql/2pc_temp_table_failure.sql
diff -N src/test/regress/sql/2pc_temp_table_failure.sql
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_temp_table_failure.sql	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,13 @@
+-- Existing non-empty temp table at commit time should still fail
+begin;
+create temp table foo(x serial primary key);
+insert into foo values(1);
+prepare transaction 'existingTempTableShouldFail';
+commit prepared 'existingTempTableShouldFail';
+create temp table foo(x serial primary key);
+begin;
+insert into foo values (1);
+prepare transaction 'accessTempTableShouldFail';
+begin;
+drop table foo;
+prepare transaction 'dropTempTableShouldFail';
Index: src/test/regress/expected/2pc_temp_table_rollback.out
===================================================================
RCS file: src/test/regress/expected/2pc_temp_table_rollback.out
diff -N src/test/regress/expected/2pc_temp_table_rollback.out
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_temp_table_rollback.out	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,7 @@
+-- Rollback prepared
+BEGIN;
+CREATE TEMP TABLE foo(bar int4);
+PREPARE TRANSACTION 'rollbackTestCase_archives.postgresql.org_pgsql-hackers_2008-03_msg00017.php';
+ERROR:  cannot PREPARE a transaction that has created but not dropped a temporary relation
+ROLLBACK PREPARED 'rollbackTestCase_archives.postgresql.org_pgsql-hackers_2008-03_msg00017.php';
+ERROR:  prepared transaction with identifier "rollbackTestCase_archives.postgresql.org_pgsql-hackers_2008-03_msg00017.php" does not exist
Index: src/test/regress/sql/2pc_temp_table_session.sql
===================================================================
RCS file: src/test/regress/sql/2pc_temp_table_session.sql
diff -N src/test/regress/sql/2pc_temp_table_session.sql
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_temp_table_session.sql	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,8 @@
+-- Session-scope temp table use case
+create temp table foo(x serial primary key);
+begin;
+insert into foo values(1);
+delete from foo;
+prepare transaction 'deleteTempTableShouldFail';
+commit prepared 'deleteTempTableShouldFail';
+drop table foo;
