Index: src/backend/access/heap/heapam.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/access/heap/heapam.c,v
retrieving revision 1.249.2.2
diff -c -p -r1.249.2.2 heapam.c
*** src/backend/access/heap/heapam.c	8 Mar 2008 21:58:07 -0000	1.249.2.2
--- src/backend/access/heap/heapam.c	10 Sep 2008 23:18:00 -0000
*************** heapgetpage(HeapScanDesc scan, BlockNumb
*** 212,217 ****
--- 212,218 ----
  	/*
  	 * Prune and repair fragmentation for the whole page, if possible.
  	 */
+ 	Assert(TransactionIdIsValid(RecentGlobalXmin));
  	heap_page_prune_opt(scan->rs_rd, buffer, RecentGlobalXmin);
  
  	/*
*************** heap_hot_search_buffer(ItemPointer tid, 
*** 1488,1493 ****
--- 1489,1496 ----
  	if (all_dead)
  		*all_dead = true;
  
+ 	Assert(TransactionIdIsValid(RecentGlobalXmin));
+ 
  	Assert(ItemPointerGetBlockNumber(tid) == BufferGetBlockNumber(buffer));
  	offnum = ItemPointerGetOffsetNumber(tid);
  	at_chain_start = true;
Index: src/backend/access/index/indexam.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/access/index/indexam.c,v
retrieving revision 1.101
diff -c -p -r1.101 indexam.c
*** src/backend/access/index/indexam.c	1 Jan 2008 19:45:46 -0000	1.101
--- src/backend/access/index/indexam.c	10 Sep 2008 23:18:00 -0000
*************** index_getnext(IndexScanDesc scan, ScanDi
*** 419,424 ****
--- 419,426 ----
  	SCAN_CHECKS;
  	GET_SCAN_PROCEDURE(amgettuple);
  
+ 	Assert(TransactionIdIsValid(RecentGlobalXmin));
+ 
  	/*
  	 * We always reset xs_hot_dead; if we are here then either we are just
  	 * starting the scan, or we previously returned a visible tuple, and in
Index: src/backend/commands/vacuum.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/commands/vacuum.c,v
retrieving revision 1.364.2.1
diff -c -p -r1.364.2.1 vacuum.c
*** src/backend/commands/vacuum.c	14 Mar 2008 17:26:00 -0000	1.364.2.1
--- src/backend/commands/vacuum.c	10 Sep 2008 23:21:34 -0000
*************** vac_update_datfrozenxid(void)
*** 781,794 ****
  	bool		dirty = false;
  
  	/*
! 	 * Initialize the "min" calculation with RecentGlobalXmin.	Any
! 	 * not-yet-committed pg_class entries for new tables must have
! 	 * relfrozenxid at least this high, because any other open xact must have
! 	 * RecentXmin >= its PGPROC.xmin >= our RecentGlobalXmin; see
! 	 * AddNewRelationTuple().  So we cannot produce a wrong minimum by
! 	 * starting with this.
  	 */
! 	newFrozenXid = RecentGlobalXmin;
  
  	/*
  	 * We must seqscan pg_class to find the minimum Xid, because there is no
--- 781,792 ----
  	bool		dirty = false;
  
  	/*
! 	 * Initialize the "min" calculation with GetOldestXmin, which is a
! 	 * reasonable approximation to the minimum relfrozenxid for not-yet-
! 	 * committed pg_class entries for new tables; see AddNewRelationTuple().
! 	 * Se we cannot produce a wrong minimum by starting with this.
  	 */
! 	newFrozenXid = GetOldestXmin(true, true);
  
  	/*
  	 * We must seqscan pg_class to find the minimum Xid, because there is no
*************** vacuum_rel(Oid relid, VacuumStmt *vacstm
*** 982,999 ****
  	/* Begin a transaction for vacuuming this relation */
  	StartTransactionCommand();
  
! 	if (vacstmt->full)
! 	{
! 		/* functions in indexes may want a snapshot set */
! 		ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
! 	}
! 	else
  	{
  		/*
! 		 * During a lazy VACUUM we do not run any user-supplied functions, and
! 		 * so it should be safe to not create a transaction snapshot.
! 		 *
! 		 * We can furthermore set the PROC_IN_VACUUM flag, which lets other
  		 * concurrent VACUUMs know that they can ignore this one while
  		 * determining their OldestXmin.  (The reason we don't set it during a
  		 * full VACUUM is exactly that we may have to run user- defined
--- 980,995 ----
  	/* Begin a transaction for vacuuming this relation */
  	StartTransactionCommand();
  
! 	/*
! 	 * Functions in indexes may want a snapshot set. Also, setting
! 	 * a snapshot ensures that RecentGlobalXmin is kept truly recent.
! 	 */
! 	ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
! 
! 	if (!vacstmt->full)
  	{
  		/*
! 		 * During a lazy VACUUM we can set the PROC_IN_VACUUM flag, which lets other
  		 * concurrent VACUUMs know that they can ignore this one while
  		 * determining their OldestXmin.  (The reason we don't set it during a
  		 * full VACUUM is exactly that we may have to run user- defined
Index: src/backend/executor/nodeBitmapHeapscan.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/executor/nodeBitmapHeapscan.c,v
retrieving revision 1.22
diff -c -p -r1.22 nodeBitmapHeapscan.c
*** src/backend/executor/nodeBitmapHeapscan.c	1 Jan 2008 19:45:49 -0000	1.22
--- src/backend/executor/nodeBitmapHeapscan.c	10 Sep 2008 23:22:26 -0000
***************
*** 36,41 ****
--- 36,42 ----
  #include "postgres.h"
  
  #include "access/heapam.h"
+ #include "access/transam.h"
  #include "executor/execdebug.h"
  #include "executor/nodeBitmapHeapscan.h"
  #include "pgstat.h"
*************** bitgetpage(HeapScanDesc scan, TBMIterate
*** 258,263 ****
--- 259,265 ----
  	/*
  	 * Prune and repair fragmentation for the whole page, if possible.
  	 */
+ 	Assert(TransactionIdIsValid(RecentGlobalXmin));
  	heap_page_prune_opt(scan->rs_rd, buffer, RecentGlobalXmin);
  
  	/*
Index: src/backend/utils/init/postinit.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/utils/init/postinit.c,v
retrieving revision 1.180
diff -c -p -r1.180 postinit.c
*** src/backend/utils/init/postinit.c	1 Jan 2008 19:45:53 -0000	1.180
--- src/backend/utils/init/postinit.c	10 Sep 2008 23:25:26 -0000
***************
*** 44,49 ****
--- 44,50 ----
  #include "utils/plancache.h"
  #include "utils/portal.h"
  #include "utils/relcache.h"
+ #include "utils/tqual.h"
  #include "utils/syscache.h"
  
  
*************** InitPostgres(const char *in_dbname, Oid 
*** 457,466 ****
  	on_shmem_exit(ShutdownPostgres, 0);
  
  	/*
! 	 * Start a new transaction here before first access to db
  	 */
  	if (!bootstrap)
  		StartTransactionCommand();
  
  	/*
  	 * Now that we have a transaction, we can take locks.  Take a writer's
--- 458,472 ----
  	on_shmem_exit(ShutdownPostgres, 0);
  
  	/*
! 	 * Start a new transaction here before first access to db, and get a
! 	 * snapshot.  We don't have a use for the snapshot itself, but we're
! 	 * interested in the secondary effect that it sets RecentGlobalXmin.
  	 */
  	if (!bootstrap)
+ 	{
  		StartTransactionCommand();
+ 		(void) GetTransactionSnapshot();
+ 	}
  
  	/*
  	 * Now that we have a transaction, we can take locks.  Take a writer's
Index: src/backend/utils/time/tqual.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/utils/time/tqual.c,v
retrieving revision 1.109
diff -c -p -r1.109 tqual.c
*** src/backend/utils/time/tqual.c	1 Jan 2008 19:45:55 -0000	1.109
--- src/backend/utils/time/tqual.c	10 Sep 2008 23:22:59 -0000
*************** Snapshot	ActiveSnapshot = NULL;
*** 75,84 ****
   * These are updated by GetSnapshotData.  We initialize them this way
   * for the convenience of TransactionIdIsInProgress: even in bootstrap
   * mode, we don't want it to say that BootstrapTransactionId is in progress.
   */
  TransactionId TransactionXmin = FirstNormalTransactionId;
  TransactionId RecentXmin = FirstNormalTransactionId;
! TransactionId RecentGlobalXmin = FirstNormalTransactionId;
  
  /* local functions */
  static bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot);
--- 75,88 ----
   * These are updated by GetSnapshotData.  We initialize them this way
   * for the convenience of TransactionIdIsInProgress: even in bootstrap
   * mode, we don't want it to say that BootstrapTransactionId is in progress.
+  *
+  * RecentGlobalXmin is initialized to InvalidTransactionId, to ensure that no
+  * one tries to use a stale value.  Readers should ensure that it has been set
+  * to something else before using it.
   */
  TransactionId TransactionXmin = FirstNormalTransactionId;
  TransactionId RecentXmin = FirstNormalTransactionId;
! TransactionId RecentGlobalXmin = InvalidTransactionId;
  
  /* local functions */
  static bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot);
