diff --git a/src/backend/access/common/heapvalid.c b/src/backend/access/common/heapvalid.c
index fdf333092fb5dc017566624e6db79fda2e41005a..f0b4f3f3458f7da25f923093e82823403c30e1ec 100644
--- a/src/backend/access/common/heapvalid.c
+++ b/src/backend/access/common/heapvalid.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/access/common/Attic/heapvalid.c,v 1.12 1996/11/10 02:56:47 momjian Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/access/common/Attic/heapvalid.c,v 1.13 1997/03/28 07:03:53 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,7 @@
 #include <storage/bufpage.h>
 #include <utils/rel.h>
 #include <utils/tqual.h>
+#include <storage/bufmgr.h>
 
 /* ----------------
  *	heap_keytest
@@ -89,14 +90,16 @@ heap_keytest(HeapTuple t,
 HeapTuple
 heap_tuple_satisfies(ItemId itemId,
 		     Relation relation,
+		     Buffer buffer,
 		     PageHeader disk_page,
 		     TimeQual	qual,
 		     int nKeys,
 		     ScanKey key)
 {
-    HeapTuple	tuple;
+    HeapTuple	tuple, result;
     bool res;
-    
+    TransactionId old_tmin, old_tmax;
+
     if (! ItemIdIsUsed(itemId))
 	return NULL;
     
@@ -107,12 +110,26 @@ heap_tuple_satisfies(ItemId itemId,
 			   nKeys, key);
     else
 	res = TRUE;
-    
-    if (res && (relation->rd_rel->relkind == RELKIND_UNCATALOGED
-		|| HeapTupleSatisfiesTimeQual(tuple,qual)))
-	return tuple;
-    
-    return (HeapTuple) NULL;
+
+    result = (HeapTuple)NULL;
+    if (res) {
+	if(relation->rd_rel->relkind == RELKIND_UNCATALOGED) {
+	    result = tuple;
+	} else {
+	    old_tmin = tuple->t_tmin;
+	    old_tmax = tuple->t_tmax;
+	    res = HeapTupleSatisfiesTimeQual(tuple,qual);
+	    if(tuple->t_tmin != old_tmin ||
+	       tuple->t_tmax != old_tmax) {
+		SetBufferCommitInfoNeedsSave(buffer);
+	    }
+	    if(res) {
+		result = tuple;
+	    }
+	}
+    }
+
+    return result;
 }
 
 /*
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index d559a3da6d4775cb88de7468862085df6a02d4af..67806925b171855424d56d7cd20e401954d962df 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.10 1997/01/23 05:59:47 momjian Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.11 1997/03/28 07:04:11 scrappy Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -388,7 +388,7 @@ heapgettup(Relation relation,
 	     *	if current tuple qualifies, return it.
 	     * ----------------
 	     */
-	    if ((rtup = heap_tuple_satisfies(lpp, relation, (PageHeader) dp,
+	    if ((rtup = heap_tuple_satisfies(lpp, relation, *b, (PageHeader) dp,
 					     timeQual, nkeys, key)) != NULL) {
 		ItemPointer iptr = &(rtup->t_ctid); 
 		if (ItemPointerGetBlockNumber(iptr) != page) {
@@ -1009,7 +1009,7 @@ heap_fetch(Relation relation,
      * ----------------
      */
     
-    tuple = heap_tuple_satisfies(lp, relation, dp,
+    tuple = heap_tuple_satisfies(lp, relation, buffer, dp,
 				 timeQual, 0,(ScanKey)NULL);
     
     if (tuple == NULL)
@@ -1154,7 +1154,7 @@ heap_delete(Relation relation, ItemPointer tid)
      *	check that we're deleteing a valid item
      * ----------------
      */
-    if (!(tp = heap_tuple_satisfies(lp, relation, dp,
+    if (!(tp = heap_tuple_satisfies(lp, relation, b, dp,
 				    NowTimeQual, 0, (ScanKey) NULL))) {
 	
 	/* XXX call something else */
@@ -1282,6 +1282,7 @@ heap_replace(Relation relation, ItemPointer otid, HeapTuple tup)
      */
     if (!heap_tuple_satisfies(lp,
 			      relation,
+			      buffer,
 			      (PageHeader)dp,
 			      NowTimeQual,
 			      0,
diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c
index 7613971df7e7f7b403d282f5186e9d92692771e7..dcfebd0d433ae6e3345da32a4493363ffd4dbd5e 100644
--- a/src/backend/storage/buffer/buf_init.c
+++ b/src/backend/storage/buffer/buf_init.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.7 1997/01/26 00:45:25 momjian Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.8 1997/03/28 07:04:52 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -64,6 +64,8 @@ extern IpcSemaphoreId      WaitIOSemId;
 
 long	*PrivateRefCount;	/* also used in freelist.c */
 long	*LastRefCount;  /* refcounts of last ExecMain level */
+long    *CommitInfoNeedsSave;  /* to write buffers where we have filled in */
+                               /* t_tmin (or t_tmax)                       */
 
 /*
  * Data Structures:
@@ -236,6 +238,7 @@ InitBufferPool(IPCKey key)
 #endif
     PrivateRefCount = (long *) calloc(NBuffers, sizeof(long));
     LastRefCount = (long *) calloc(NBuffers, sizeof(long));
+    CommitInfoNeedsSave = (long *) calloc(NBuffers, sizeof(long));
 }
 
 /* -----------------------------------------------------
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index b40b0b0e0451f727ac2f25c9ec9570920f82f6ac..5331ab3fbe2dbf84e4e7a78bff9a146adfd722e9 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.10 1997/01/23 19:43:23 scrappy Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.11 1997/03/28 07:05:03 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -848,6 +848,10 @@ ReleaseAndReadBuffer(Buffer buffer,
 		    AddBufferToFreelist(bufHdr);
 		    bufHdr->flags |= BM_FREE;
 		}
+		if(CommitInfoNeedsSave[buffer - 1]) {
+		    bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED);
+		    CommitInfoNeedsSave[buffer - 1] = 0;
+		}
 		retbuf = ReadBufferWithBufferLock(relation, blockNum, true);
 		return retbuf;
 	    }
@@ -1083,6 +1087,7 @@ ResetBufferPool()
 {
     register int i;
     for (i=1; i<=NBuffers; i++) {
+	CommitInfoNeedsSave[i - 1] = 0;
 	if (BufferIsValid(i)) {
 	    while(PrivateRefCount[i - 1] > 0) {
 		ReleaseBuffer(i);
@@ -1498,6 +1503,10 @@ ReleaseBuffer(Buffer buffer)
 	    AddBufferToFreelist(bufHdr);
 	    bufHdr->flags |= BM_FREE;
 	}
+	if(CommitInfoNeedsSave[buffer - 1]) {
+	    bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED);
+	    CommitInfoNeedsSave[buffer - 1] = 0;
+	}
 	SpinRelease(BufMgrLock);
     }
     
@@ -1734,3 +1743,8 @@ int SetBufferWriteMode (int mode)
     WriteMode = mode;
     return (old);
 }
+
+void SetBufferCommitInfoNeedsSave(Buffer buffer)
+{
+    CommitInfoNeedsSave[buffer - 1]++;
+}
diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c
index dd115b69885cb0c2f01315c81c768846cfb2c91d..5c2f8271fa8c9780d4038b2d59a01c237dfcc3b6 100644
--- a/src/backend/utils/time/tqual.c
+++ b/src/backend/utils/time/tqual.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.1.1.1 1996/07/09 06:22:10 scrappy Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.2 1997/03/28 07:05:28 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -478,6 +478,8 @@ HeapTupleSatisfiesTimeQual(HeapTuple tuple, TimeQual qual)
 /*
  * HeapTupleSatisfiesItself --
  *	True iff heap tuple is valid for "itself."
+ *      "{it}self" means valid as of everything that's happened
+ *      in the current transaction, _including_ the current command.
  *
  * Note:
  *	Assumes heap tuple is valid.
@@ -485,11 +487,15 @@ HeapTupleSatisfiesTimeQual(HeapTuple tuple, TimeQual qual)
 /*
  * The satisfaction of "itself" requires the following:
  *
- * ((Xmin == my-transaction && (Xmax is null [|| Xmax != my-transaction)])
+ * ((Xmin == my-transaction &&              the row was updated by the current transaction, and
+ *      (Xmax is null                       it was not deleted
+ *       [|| Xmax != my-transaction)])          [or it was deleted by another transaction]
  * ||
  *
- * (Xmin is committed &&
- *	(Xmax is null || (Xmax != my-transaction && Xmax is not committed)))
+ * (Xmin is committed &&                    the row was modified by a committed transaction, and
+ *	(Xmax is null ||                    the row has not been deleted, or
+ *          (Xmax != my-transaction &&          the row was deleted by another transaction
+ *           Xmax is not committed)))           that has not been committed
  */
 static bool
 HeapTupleSatisfiesItself(HeapTuple tuple)
@@ -508,6 +514,8 @@ HeapTupleSatisfiesItself(HeapTuple tuple)
 	if (!TransactionIdDidCommit((TransactionId)tuple->t_xmin)) {
 	    return (false);
 	}
+
+	tuple->t_tmin = TransactionIdGetCommitTime(tuple->t_xmin);	
     }
     /* the tuple was inserted validly */
     
@@ -522,13 +530,23 @@ HeapTupleSatisfiesItself(HeapTuple tuple)
     if (TransactionIdIsCurrentTransactionId((TransactionId)tuple->t_xmax)) {
 	return (false);
     }
+
+    if (!TransactionIdDidCommit((TransactionId)tuple->t_xmax)) {
+	return (true);
+    }
     
-    return ((bool)!TransactionIdDidCommit((TransactionId)tuple->t_xmax));
+    /* by here, deleting transaction has committed */
+    tuple->t_tmax = TransactionIdGetCommitTime(tuple->t_xmax);
+
+    return (false);
 }
 
 /*
  * HeapTupleSatisfiesNow --
  *	True iff heap tuple is valid "now."
+ *      "now" means valid including everything that's happened
+ *       in the current transaction _up to, but not including,_
+ *       the current command.
  *
  * Note:
  *	Assumes heap tuple is valid.
@@ -536,13 +554,19 @@ HeapTupleSatisfiesItself(HeapTuple tuple)
 /*
  * The satisfaction of "now" requires the following:
  *
- * ((Xmin == my-transaction && Cmin != my-command &&
- *	(Xmax is null || (Xmax == my-transaction && Cmax != my-command)))
- * ||
+ * ((Xmin == my-transaction &&              changed by the current transaction
+ *   Cmin != my-command &&                  but not by this command, and
+ *      (Xmax is null ||                        the row has not been deleted, or
+ *          (Xmax == my-transaction &&          it was deleted by the current transaction
+ *           Cmax != my-command)))              but not by this command,
+ * ||                                       or
  *
- * (Xmin is committed &&
- *	(Xmax is null || (Xmax == my-transaction && Cmax == my-command) ||
- *		(Xmax is not committed && Xmax != my-transaction))))
+ *  (Xmin is committed &&                   the row was modified by a committed transaction, and
+ *      (Xmax is null ||                    the row has not been deleted, or
+ *          (Xmax == my-transaction &&          the row is being deleted by this command, or
+ *           Cmax == my-command) ||
+ *	    (Xmax is not committed &&           the row was deleted by another transaction
+ *           Xmax != my-transaction))))         that has not been committed
  *
  *	mao says 17 march 1993:  the tests in this routine are correct;
  *	if you think they're not, you're wrong, and you should think
@@ -605,6 +629,13 @@ HeapTupleSatisfiesNow(HeapTuple tuple)
 	if (!TransactionIdDidCommit((TransactionId)tuple->t_xmin)) {
 	    return (false);
 	}
+
+	/* 
+	 * the transaction has been committed--store the commit time _now_
+	 * instead of waiting for a vacuum so we avoid the expensive call
+	 * next time.
+	 */
+	tuple->t_tmin = TransactionIdGetCommitTime(tuple->t_xmin);	
     }
     
     /* by here, the inserting transaction has committed */
@@ -615,12 +646,18 @@ HeapTupleSatisfiesNow(HeapTuple tuple)
     if (TransactionIdIsCurrentTransactionId((TransactionId)tuple->t_xmax)) {
 	return (false);
     }
-    
+
+    if (AbsoluteTimeIsBackwardCompatiblyReal(tuple->t_tmax)) {
+	return (false);
+    }
+
     if (!TransactionIdDidCommit((TransactionId)tuple->t_xmax)) {
-	return (true);
+       return (true);
     }
-    
-    /* by here, deleting transaction has committed */
+
+    /* xmax transaction committed, but no tmax set.  so set it. */
+    tuple->t_tmax = TransactionIdGetCommitTime(tuple->t_xmax);
+
     return (false);
 }
 
diff --git a/src/include/access/valid.h b/src/include/access/valid.h
index 4ab525dec96c595bf60b68a91843268312f9c8f8..ca209a16e5a475590b0b6dc59586f81b989e7787 100644
--- a/src/include/access/valid.h
+++ b/src/include/access/valid.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: valid.h,v 1.3 1996/11/05 10:37:07 scrappy Exp $
+ * $Id: valid.h,v 1.4 1997/03/28 07:05:54 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,7 +26,9 @@ extern bool heap_keytest(HeapTuple t, TupleDesc tupdesc,
 			 int nkeys, ScanKey keys);
 
 extern HeapTuple heap_tuple_satisfies(ItemId itemId, Relation relation,
-       PageHeader disk_page, TimeQual qual, int nKeys, ScanKey key);
+				      Buffer buffer, PageHeader disk_page, 
+				      TimeQual qual, int nKeys, 
+				      ScanKey key);
 
 extern bool TupleUpdatedByCurXactAndCmd(HeapTuple t);
 
diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h
index 356d2d8e2d021aa237aa90498695aaa51b867fad..4fada24503b8267a9e6eeb1b5a76b0a2622ade09 100644
--- a/src/include/storage/buf_internals.h
+++ b/src/include/storage/buf_internals.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: buf_internals.h,v 1.11 1997/01/25 03:09:33 momjian Exp $
+ * $Id: buf_internals.h,v 1.12 1997/03/28 07:06:48 scrappy Exp $
  *
  * NOTE
  *	If BUFFERPAGE0 is defined, then 0 will be used as a
@@ -216,6 +216,7 @@ extern BufferDesc 	*BufferDescriptors;
 extern BufferBlock 	BufferBlocks;
 extern long		*PrivateRefCount;
 extern long		*LastRefCount;
+extern long             *CommitInfoNeedsSave;
 extern SPINLOCK		BufMgrLock;
 
 /* localbuf.c */
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index e4e376e000ddccd3f6ba0eb5d48658ae3441ace8..fc239caeed678b4b462f61d9d8648fdc0ac3affc 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: bufmgr.h,v 1.9 1997/01/16 07:53:27 vadim Exp $
+ * $Id: bufmgr.h,v 1.10 1997/03/28 07:06:53 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -114,6 +114,7 @@ extern int ReleaseAndReadBuffer_Debug(char *file,
 extern void BufferRefCountReset(int *refcountsave);
 extern void BufferRefCountRestore(int *refcountsave);
 extern int SetBufferWriteMode (int mode);
+extern void SetBufferCommitInfoNeedsSave(Buffer buffer);
 
 #endif	/* !defined(BufMgrIncluded) */