Here's a patch that implements the Phantom Command ID idea that has been discussed.

I didn't do anything about the system columns. We need to before applying the patch, because the HeapTupleHeaderGetCmin/max functions don't work properly if called outside the inserting/deleting transaction. In fact, SELECT cmin,cmax FROM foo will cause assertion failures if there's rows with phantom cids in the table.

I used the last free bit in t_infomask. At first I thought it wouldn't be necessary, because you could detect that a row has a phantom command id if both xmin and xmax are part of the current top-level transaction (TransactionIdIsCurrentTransactionId). But that doesn't work because we don't consider aborted subtransactions as current. Using the infomask bit seems more robust anyway.

--
 Heikki Linnakangas
 EnterpriseDB   http://www.enterprisedb.com

Index: src/backend/access/heap/heapam.c
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/access/heap/heapam.c,v
retrieving revision 1.219
diff -c -r1.219 heapam.c
*** src/backend/access/heap/heapam.c	18 Aug 2006 16:09:08 -0000	1.219
--- src/backend/access/heap/heapam.c	26 Sep 2006 11:44:22 -0000
***************
*** 1405,1412 ****
  	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
  	HeapTupleHeaderSetXmin(tup->t_data, xid);
  	HeapTupleHeaderSetCmin(tup->t_data, cid);
! 	HeapTupleHeaderSetXmax(tup->t_data, 0);		/* zero out Datum fields */
! 	HeapTupleHeaderSetCmax(tup->t_data, 0);		/* for cleanliness */
  	tup->t_tableOid = RelationGetRelid(relation);
  
  	/*
--- 1405,1411 ----
  	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
  	HeapTupleHeaderSetXmin(tup->t_data, xid);
  	HeapTupleHeaderSetCmin(tup->t_data, cid);
! 	HeapTupleHeaderSetXmax(tup->t_data, 0);
  	tup->t_tableOid = RelationGetRelid(relation);
  
  	/*
***************
*** 2045,2052 ****
  	newtup->t_data->t_infomask |= (HEAP_XMAX_INVALID | HEAP_UPDATED);
  	HeapTupleHeaderSetXmin(newtup->t_data, xid);
  	HeapTupleHeaderSetCmin(newtup->t_data, cid);
! 	HeapTupleHeaderSetXmax(newtup->t_data, 0);	/* zero out Datum fields */
! 	HeapTupleHeaderSetCmax(newtup->t_data, 0);	/* for cleanliness */
  
  	/*
  	 * If the toaster needs to be activated, OR if the new tuple will not fit
--- 2044,2050 ----
  	newtup->t_data->t_infomask |= (HEAP_XMAX_INVALID | HEAP_UPDATED);
  	HeapTupleHeaderSetXmin(newtup->t_data, xid);
  	HeapTupleHeaderSetCmin(newtup->t_data, cid);
! 	HeapTupleHeaderSetXmax(newtup->t_data, 0);
  
  	/*
  	 * If the toaster needs to be activated, OR if the new tuple will not fit
Index: src/backend/access/transam/xact.c
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/access/transam/xact.c,v
retrieving revision 1.226
diff -c -r1.226 xact.c
*** src/backend/access/transam/xact.c	27 Aug 2006 19:11:46 -0000	1.226
--- src/backend/access/transam/xact.c	27 Sep 2006 11:03:25 -0000
***************
*** 43,48 ****
--- 43,49 ----
  #include "utils/memutils.h"
  #include "utils/relcache.h"
  #include "utils/guc.h"
+ #include "utils/phantomcid.h"
  
  
  /*
***************
*** 1595,1600 ****
--- 1596,1602 ----
  	AtEOXact_Namespace(true);
  	/* smgrcommit already done */
  	AtEOXact_Files();
+ 	AtEOXact_PhantomCid();
  	pgstat_count_xact_commit();
  
  	CurrentResourceOwner = NULL;
***************
*** 1810,1815 ****
--- 1812,1818 ----
  	AtEOXact_Namespace(true);
  	/* smgrcommit already done */
  	AtEOXact_Files();
+ 	AtEOXact_PhantomCid();
  
  	CurrentResourceOwner = NULL;
  	ResourceOwnerDelete(TopTransactionResourceOwner);
***************
*** 1961,1966 ****
--- 1964,1970 ----
  	AtEOXact_Namespace(false);
  	smgrabort();
  	AtEOXact_Files();
+ 	AtEOXact_PhantomCid();
  	pgstat_count_xact_rollback();
  
  	/*
Index: src/backend/utils/time/Makefile
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/utils/time/Makefile,v
retrieving revision 1.10
diff -c -r1.10 Makefile
*** src/backend/utils/time/Makefile	29 Nov 2003 19:52:04 -0000	1.10
--- src/backend/utils/time/Makefile	20 Sep 2006 10:05:19 -0000
***************
*** 12,18 ****
  top_builddir = ../../../..
  include $(top_builddir)/src/Makefile.global
  
! OBJS = tqual.o
  
  all: SUBSYS.o
  
--- 12,18 ----
  top_builddir = ../../../..
  include $(top_builddir)/src/Makefile.global
  
! OBJS = tqual.o phantomcid.o
  
  all: SUBSYS.o
  
Index: src/backend/utils/time/phantomcid.c
===================================================================
RCS file: src/backend/utils/time/phantomcid.c
diff -N src/backend/utils/time/phantomcid.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- src/backend/utils/time/phantomcid.c	28 Sep 2006 09:43:13 -0000
***************
*** 0 ****
--- 1,274 ----
+ /*-------------------------------------------------------------------------
+  *
+  * phantomcid.c
+  *	  Phantom command id support routines
+  *
+  * Before version 8.3, HeapTupleHeaderData had separate fields for cmin
+  * and cmax. To reduce the header size, cmin and cmax are now overlayed
+  * in the same field in the header. That usually works because you rarely
+  * insert and delete a tuple in the transaction. To make it work when you 
+  * do, we create a phantom command id and store that in the tuple header
+  * instead of cmin and cmax. The phantom command id maps to the real cmin
+  * and cmax in a backend-private array. Other backends don't need them,
+  * because cmin and cmax are only interesting to the inserting/deleting
+  * transaction.
+  *
+  * To allow reusing existing phantom cids, we also keep a hash table that
+  * maps cmin,cmax pairs to phantom cids.
+  *
+  * The array and hash table are kept in TopTransactionContext, and are
+  * destroyed at the end of transaction.
+  *
+  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * IDENTIFICATION
+  *	  $PostgreSQL$
+  *
+  *-------------------------------------------------------------------------
+  */
+ 
+ #include "postgres.h"
+ 
+ #include "access/htup.h"
+ #include "access/xact.h"
+ #include "utils/memutils.h"
+ #include "utils/hsearch.h"
+ 
+ #define PHANTOMCID_DEBUG
+ 
+ 
+ /* Hash table to lookup phantom cids by cmin and cmax */
+ static HTAB *phantomHash = NULL;
+ 
+ /* Key and entry structures for the hash table */
+ typedef struct {
+ 	CommandId cmin;
+ 	CommandId cmax;
+ } PhantomCidKeyData;
+ 
+ typedef struct {
+ 	PhantomCidKeyData key;
+ 	CommandId phantomcid;
+ } PhantomCidEntryData;
+ 
+ typedef PhantomCidKeyData *PhantomCidKey;
+ typedef PhantomCidEntryData *PhantomCidEntry;
+ 
+ #define PCID_HASH_SIZE				100
+ 
+ 
+ /* An array of cmin,cmax pairs, indexed by phantom command id.
+  * To convert a phantom cid to cmin and cmax, you do a simple array
+  * lookup. */
+ static PhantomCidKey phantomCids = NULL;
+ static int usedPhantomCids = 0; /* number of elements in phantomCids */
+ static int sizePhantomCids = 0; /* size of phantomCids array */
+ 
+ /* Initial size of the array. It will be grown if it fills up */
+ #define PCID_ARRAY_INITIAL_SIZE		100
+ 
+ 
+ /* prototypes for internal functions */
+ static CommandId GetPhantomCommandId(CommandId cmin, CommandId cmax);
+ static CommandId GetRealCmin(CommandId phantomcid);
+ static CommandId GetRealCmax(CommandId phantomcid);
+ 
+ /**** External API ****/
+ 
+ /* All these functions rely on the caller to not call functions that don't make
+  * sense. You should only call cmin related functions in the inserting 
+  * transaction and cmax related functions in the deleting transaction.
+  */
+ 
+ CommandId
+ HeapTupleHeaderGetCmin(HeapTupleHeader tup)
+ {
+ 	CommandId cid = tup->t_choice.t_heap.t_field4.t_commandid;
+ 
+ 	Assert(!(tup->t_infomask & HEAP_MOVED));
+ 
+ 	if (tup->t_infomask & HEAP_PHANTOMCID)
+ 		return GetRealCmin(cid);
+ 	else
+ 		return cid;
+ }
+ 
+ void
+ HeapTupleHeaderSetCmin(HeapTupleHeader tup, CommandId cmin)
+ {
+ 	/* We never need to create a phantom cid for a new tuple. */
+ 	tup->t_choice.t_heap.t_field4.t_commandid = cmin;
+ }
+ 
+ CommandId
+ HeapTupleHeaderGetCmax(HeapTupleHeader tup)
+ {
+ 	CommandId cid = tup->t_choice.t_heap.t_field4.t_commandid;
+ 
+ 	Assert(!(tup->t_infomask & HEAP_MOVED));
+ 
+ 	if (tup->t_infomask & HEAP_PHANTOMCID)
+ 		return GetRealCmax(cid);
+ 	else
+ 		return cid;
+ }
+ 
+ void
+ HeapTupleHeaderSetCmax(HeapTupleHeader tup, CommandId cmax)
+ {
+ 	HeapTupleFields *t_heap = &tup->t_choice.t_heap;
+ 
+ 	if (!(tup->t_infomask & HEAP_XMIN_COMMITTED)
+ 		&& TransactionIdIsCurrentTransactionId(t_heap->t_xmin))
+ 	{
+ 		/* This row was inserted by our transaction, and now we're
+ 		 * deleting it. Need to use phantom cid. */
+ 		CommandId cmin = t_heap->t_field4.t_commandid;
+ 		t_heap->t_field4.t_commandid = GetPhantomCommandId(cmin, cmax);
+ 		tup->t_infomask |= HEAP_PHANTOMCID;
+ 	}
+ 	else {
+ 		t_heap->t_field4.t_commandid = cmax;
+ 		tup->t_infomask &= ~HEAP_PHANTOMCID;
+ 	}
+ }
+ /*
+  * Phantom command IDs are only interesting to the inserting and deleting 
+  * transaction, so we can forget about them at the end of transaction.
+  */
+ void
+ AtEOXact_PhantomCid()
+ {
+ 	usedPhantomCids = 0;
+ 	sizePhantomCids = 0;
+ 	/* Don't bother to pfree. These are allocated in TopTransactionContext,
+ 	 * so they're going to be freed at the end of transaction anyway. 
+ 	 */
+ 	phantomCids = NULL;
+ 	phantomHash = NULL;
+ }
+ 
+ 
+ /**** Internal routines ****/
+ 
+ /*
+  * Get a phantom command id that maps to cmin and cmax.
+  *
+  * We try to reuse old phantom command ids when possible.
+  */
+ static
+ CommandId GetPhantomCommandId(CommandId cmin, CommandId cmax)
+ {
+ 	CommandId phantomcid;
+ 	PhantomCidKeyData key;
+ 	PhantomCidEntry entry = NULL;
+ 	bool found;
+ 	
+ #ifdef PHANTOMCID_DEBUG
+ 	elog(LOG, "GetPhantomCommandId cmin: %d cmax: %d", cmin, cmax);
+ #endif
+ 
+ 	/* Create the array and hash table the first time we need to use
+ 	 * phantom cids in the transaction.
+ 	 */
+ 	if(phantomCids == NULL) 
+ 	{
+ 		HASHCTL hash_ctl;
+ 		MemoryContext oldcontext;
+ 
+ 		oldcontext = MemoryContextSwitchTo(TopTransactionContext);
+ 
+ 		phantomCids = 
+ 			palloc(sizeof(PhantomCidKeyData) * PCID_ARRAY_INITIAL_SIZE);
+ 		sizePhantomCids = PCID_ARRAY_INITIAL_SIZE;
+ 
+ 		memset(&hash_ctl, 0, sizeof(hash_ctl));
+ 		hash_ctl.keysize = sizeof(PhantomCidKeyData);
+ 		hash_ctl.entrysize = sizeof(PhantomCidEntryData);
+ 		hash_ctl.hash = tag_hash;
+ 		hash_ctl.hcxt = TopTransactionContext;
+ 
+ 		phantomHash =
+ 			hash_create("Phantom command id hash table",
+ 						PCID_HASH_SIZE, &hash_ctl,
+ 						HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
+ 
+ 		MemoryContextSwitchTo(TopTransactionContext);
+ 	}
+ 	
+ 	/* Try to find an old phantom cid with the same cmin and cmax for reuse */
+ 
+ 	key.cmin = cmin;
+ 	key.cmax = cmax;
+ 	entry = (PhantomCidEntry) 
+ 		hash_search(phantomHash, (void *) &key, HASH_ENTER, &found);
+ 
+ 	if (found)
+ 	{
+ #ifdef PHANTOMCID_DEBUG
+ 		elog(LOG, "result: %d (reused)", entry->phantomcid);
+ #endif
+ 		return entry->phantomcid;
+ 	} 
+ 	else 
+ 	{
+ 		/* We have to create a new phantom cid. Check that there's room
+ 		 * for it in the array, and grow it if there isn't */
+ 		if (usedPhantomCids >= sizePhantomCids)
+ 		{	
+ 			/* We need to grow the array */
+ 
+ 			MemoryContext oldcontext;
+ 			oldcontext = MemoryContextSwitchTo(TopTransactionContext);
+ 
+ 			/* XXX: Should we create a bigger hash table too? */
+ 			sizePhantomCids *= 2;
+ 			phantomCids = 
+ 				repalloc(phantomCids, 
+ 						 sizeof(PhantomCidKeyData) * sizePhantomCids);
+ 
+ 			MemoryContextSwitchTo(oldcontext);
+ 		}
+ 
+ 		phantomcid = usedPhantomCids;
+ 		entry->phantomcid = phantomcid;
+ 
+ 		phantomCids[phantomcid].cmin = cmin;
+ 		phantomCids[phantomcid].cmax = cmax;
+ 
+ 		usedPhantomCids++;
+ 
+ #ifdef PHANTOMCID_DEBUG
+ 		elog(LOG, "result: %d", phantomcid);
+ #endif
+ 	}
+ 
+ 	return phantomcid;
+ }
+ 
+ static CommandId
+ GetRealCmin(CommandId phantomcid)
+ {
+ 	Assert(phantomcid < usedPhantomCids);
+ 
+ #ifdef PHANTOMCID_DEBUG
+ 	elog(LOG, "GetRealCmin phantomcid: %d -> %d", phantomcid, phantomCids[phantomcid].cmin);
+ #endif
+ 	
+ 
+ 	return phantomCids[phantomcid].cmin;
+ }
+ 
+ static CommandId
+ GetRealCmax(CommandId phantomcid)
+ {
+ 	Assert(phantomcid < usedPhantomCids);
+ 
+ #ifdef PHANTOMCID_DEBUG
+ 	elog(LOG, "GetRealCmax phantomcid: %d -> %d", phantomcid, phantomCids[phantomcid].cmax);
+ #endif
+ 
+ 	return phantomCids[phantomcid].cmax;
+ }
+ 
Index: src/include/access/htup.h
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/access/htup.h,v
retrieving revision 1.85
diff -c -r1.85 htup.h
*** src/include/access/htup.h	13 Jul 2006 17:47:01 -0000	1.85
--- src/include/access/htup.h	28 Sep 2006 09:23:03 -0000
***************
*** 65,77 ****
   *			object ID (if HEAP_HASOID is set in t_infomask)
   *			user data fields
   *
!  * We store five "virtual" fields Xmin, Cmin, Xmax, Cmax, and Xvac in four
!  * physical fields.  Xmin, Cmin and Xmax are always really stored, but
!  * Cmax and Xvac share a field.  This works because we know that there are
!  * only a limited number of states that a tuple can be in, and that Cmax
!  * is only interesting for the lifetime of the deleting transaction.
!  * This assumes that VACUUM FULL never tries to move a tuple whose Cmax
!  * is still interesting (ie, delete-in-progress).
   *
   * Note that in 7.3 and 7.4 a similar idea was applied to Xmax and Cmin.
   * However, with the advent of subtransactions, a tuple may need both Xmax
--- 65,81 ----
   *			object ID (if HEAP_HASOID is set in t_infomask)
   *			user data fields
   *
!  * We store five "virtual" fields Xmin, Cmin, Xmax, Cmax, and Xvac in three
!  * physical fields.  Xmin and Xmax are always really stored, but Cmin, Cmax
!  * and Xvac share a field.  This works because we know that there are only
!  * a limited number of states that a tuple can be in, and that Cmax and Cmin
!  * are only interesting for the lifetime of the deleting or inserting 
!  * transaction. If a tuple is inserted and deleted in the same transaction,
!  * we use a phantom command id that maps to the real cmin and cmax. The 
!  * mapping is local to the backend. See phantomcid.c for more details.
!  *
!  * This assumes that VACUUM FULL never tries to move a tuple whose Cmax or 
!  * Cmin is still interesting (ie, delete- or insert-in-progress).
   *
   * Note that in 7.3 and 7.4 a similar idea was applied to Xmax and Cmin.
   * However, with the advent of subtransactions, a tuple may need both Xmax
***************
*** 103,114 ****
  typedef struct HeapTupleFields
  {
  	TransactionId t_xmin;		/* inserting xact ID */
- 	CommandId	t_cmin;			/* inserting command ID */
  	TransactionId t_xmax;		/* deleting or locking xact ID */
  
  	union
  	{
! 		CommandId	t_cmax;		/* deleting or locking command ID */
  		TransactionId t_xvac;	/* VACUUM FULL xact ID */
  	}			t_field4;
  } HeapTupleFields;
--- 107,121 ----
  typedef struct HeapTupleFields
  {
  	TransactionId t_xmin;		/* inserting xact ID */
  	TransactionId t_xmax;		/* deleting or locking xact ID */
  
  	union
  	{
! 		/* t_commandid is the inserting command ID (cmin), the deleting
! 		 * command ID (cmax), or a phantom cid that maps to cmin and cmax if 
! 		 * the tuple was inserted and deleted in the same transaction
! 		 */
! 		CommandId	t_commandid;
  		TransactionId t_xvac;	/* VACUUM FULL xact ID */
  	}			t_field4;
  } HeapTupleFields;
***************
*** 163,169 ****
  #define HEAP_HASCOMPRESSED		0x0008	/* has compressed stored attribute(s) */
  #define HEAP_HASEXTENDED		0x000C	/* the two above combined */
  #define HEAP_HASOID				0x0010	/* has an object-id field */
! /* 0x0020 is presently unused */
  #define HEAP_XMAX_EXCL_LOCK		0x0040	/* xmax is exclusive locker */
  #define HEAP_XMAX_SHARED_LOCK	0x0080	/* xmax is shared locker */
  /* if either LOCK bit is set, xmax hasn't deleted the tuple, only locked it */
--- 170,176 ----
  #define HEAP_HASCOMPRESSED		0x0008	/* has compressed stored attribute(s) */
  #define HEAP_HASEXTENDED		0x000C	/* the two above combined */
  #define HEAP_HASOID				0x0010	/* has an object-id field */
! #define HEAP_PHANTOMCID			0x0020	/* t_commandid is a phantom cid */
  #define HEAP_XMAX_EXCL_LOCK		0x0040	/* xmax is exclusive locker */
  #define HEAP_XMAX_SHARED_LOCK	0x0080	/* xmax is shared locker */
  /* if either LOCK bit is set, xmax hasn't deleted the tuple, only locked it */
***************
*** 210,243 ****
  	TransactionIdStore((xid), &(tup)->t_choice.t_heap.t_xmax) \
  )
  
! #define HeapTupleHeaderGetCmin(tup) \
! ( \
! 	(tup)->t_choice.t_heap.t_cmin \
! )
! 
! #define HeapTupleHeaderSetCmin(tup, cid) \
! ( \
! 	(tup)->t_choice.t_heap.t_cmin = (cid) \
! )
! 
! /*
!  * Note: GetCmax will produce wrong answers after SetXvac has been executed
!  * by a transaction other than the inserting one.  We could check
!  * HEAP_XMAX_INVALID and return FirstCommandId if it's clear, but since that
!  * bit will be set again if the deleting transaction aborts, there'd be no
!  * real gain in safety from the extra test.  So, just rely on the caller not
!  * to trust the value unless it's meaningful.
   */
- #define HeapTupleHeaderGetCmax(tup) \
- ( \
- 	(tup)->t_choice.t_heap.t_field4.t_cmax \
- )
- 
- #define HeapTupleHeaderSetCmax(tup, cid) \
- do { \
- 	Assert(!((tup)->t_infomask & HEAP_MOVED)); \
- 	(tup)->t_choice.t_heap.t_field4.t_cmax = (cid); \
- } while (0)
  
  #define HeapTupleHeaderGetXvac(tup) \
  ( \
--- 217,225 ----
  	TransactionIdStore((xid), &(tup)->t_choice.t_heap.t_xmax) \
  )
  
! /* HeapTupleHeaderGetCmin, HeapTupleHeaderGetCmax, and ..SetCmin and ..SetCmax
!  * are defined in phantomcid.h
   */
  
  #define HeapTupleHeaderGetXvac(tup) \
  ( \
***************
*** 613,616 ****
--- 595,605 ----
  
  #define SizeOfHeapInplace	(offsetof(xl_heap_inplace, target) + SizeOfHeapTid)
  
+ /* prototypes of HeapTupleHeader* functions implemented in 
+  * utils/time/phantomcid.c */
+ extern CommandId HeapTupleHeaderGetCmin(HeapTupleHeader tup);
+ extern void HeapTupleHeaderSetCmin(HeapTupleHeader tup, CommandId cmin);
+ extern CommandId HeapTupleHeaderGetCmax(HeapTupleHeader tup);
+ extern void HeapTupleHeaderSetCmax(HeapTupleHeader tup, CommandId cmax);
+ 
  #endif   /* HTUP_H */
Index: src/include/utils/phantomcid.h
===================================================================
RCS file: src/include/utils/phantomcid.h
diff -N src/include/utils/phantomcid.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- src/include/utils/phantomcid.h	28 Sep 2006 09:12:11 -0000
***************
*** 0 ****
--- 1,25 ----
+ /*-------------------------------------------------------------------------
+  *
+  * phantomcid.h
+  *	  Phantom cid function definitions
+  *
+  *
+  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * $PostgreSQL$
+  *
+  *-------------------------------------------------------------------------
+  */
+ #ifndef PHANTOMCID_H
+ #define PHANTOMCID_H
+ 
+ /* HeapTupleHeaderGetCmin, *SetCmin, *GetCmax and *SetCmax
+  * function prototypes are in access/htup.h, because that's
+  * where the macro definitions that the functions replaced
+  * used to be.
+  */
+ 
+ extern void AtEOXact_PhantomCid(void);
+ 
+ #endif   /* PHANTOMCID_H */
Index: src/test/regress/parallel_schedule
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/test/regress/parallel_schedule,v
retrieving revision 1.35
diff -c -r1.35 parallel_schedule
*** src/test/regress/parallel_schedule	30 Aug 2006 23:34:22 -0000	1.35
--- src/test/regress/parallel_schedule	27 Sep 2006 12:53:04 -0000
***************
*** 61,67 ****
  # ----------
  # The fourth group of parallel test
  # ----------
! test: select_into select_distinct select_distinct_on select_implicit select_having subselect union case join aggregates transactions random portals arrays btree_index hash_index update namespace prepared_xacts delete
  
  test: privileges
  test: misc
--- 61,67 ----
  # ----------
  # The fourth group of parallel test
  # ----------
! test: select_into select_distinct select_distinct_on select_implicit select_having subselect union case join aggregates transactions random portals arrays btree_index hash_index update namespace prepared_xacts delete phantomcid
  
  test: privileges
  test: misc
Index: src/test/regress/serial_schedule
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/test/regress/serial_schedule,v
retrieving revision 1.33
diff -c -r1.33 serial_schedule
*** src/test/regress/serial_schedule	30 Aug 2006 23:34:22 -0000	1.33
--- src/test/regress/serial_schedule	27 Sep 2006 12:52:34 -0000
***************
*** 104,106 ****
--- 104,107 ----
  test: returning
  test: stats
  test: tablespace
+ test: phantomcid
Index: src/test/regress/expected/phantomcid.out
===================================================================
RCS file: src/test/regress/expected/phantomcid.out
diff -N src/test/regress/expected/phantomcid.out
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- src/test/regress/expected/phantomcid.out	28 Sep 2006 08:51:09 -0000
***************
*** 0 ****
--- 1,28 ----
+ CREATE TEMP TABLE phantomcidtest (foobar int);
+ BEGIN;
+ INSERT INTO phantomcidtest VALUES (1);
+ SELECT * FROM phantomcidtest;
+  foobar 
+ --------
+       1
+ (1 row)
+ 
+ DELETE FROM phantomcidtest;
+ SELECT * FROM phantomcidtest;
+  foobar 
+ --------
+ (0 rows)
+ 
+ COMMIT;
+ /* Test phantom cids with portals */
+ BEGIN;
+ INSERT INTO phantomcidtest VALUES (1);
+ DECLARE c CURSOR FOR SELECT * FROM phantomcidtest;
+ DELETE FROM phantomcidtest;
+ FETCH ALL FROM c;
+  foobar 
+ --------
+       1
+ (1 row)
+ 
+ COMMIT;
Index: src/test/regress/sql/phantomcid.sql
===================================================================
RCS file: src/test/regress/sql/phantomcid.sql
diff -N src/test/regress/sql/phantomcid.sql
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- src/test/regress/sql/phantomcid.sql	27 Sep 2006 12:54:18 -0000
***************
*** 0 ****
--- 1,27 ----
+ CREATE TEMP TABLE phantomcidtest (foobar int);
+ 
+ 
+ BEGIN;
+ 
+ INSERT INTO phantomcidtest VALUES (1);
+ 
+ SELECT * FROM phantomcidtest;
+ 
+ DELETE FROM phantomcidtest;
+ 
+ SELECT * FROM phantomcidtest;
+ 
+ COMMIT;
+ 
+ /* Test phantom cids with portals */
+ BEGIN;
+ 
+ INSERT INTO phantomcidtest VALUES (1);
+ 
+ DECLARE c CURSOR FOR SELECT * FROM phantomcidtest;
+ 
+ DELETE FROM phantomcidtest;
+ 
+ FETCH ALL FROM c;
+ 
+ COMMIT;
---------------------------(end of broadcast)---------------------------
TIP 5: don't forget to increase your free space map settings

Reply via email to