From 5ab0ad5c7e70dd44d87dcdad58d9064fe10aa3e3 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 11 Jan 2002 20:07:03 +0000
Subject: [PATCH] VACUUM must make sure that a HEAP_MARKED_FOR_UPDATE tuple
 gets marked as either HEAP_XMAX_COMMITTED or HEAP_XMAX_INVALID once the
 updating transaction is gone.  Otherwise some other transaction may come
 along and try to test the commit status of t_xmax later --- which could be
 after VACUUM has recycled the CLOG status for that xact.  Bug introduced in
 post-beta4 bug fix.

---
 src/backend/utils/time/tqual.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c
index 6c7f579312e..b71b97088bf 100644
--- a/src/backend/utils/time/tqual.c
+++ b/src/backend/utils/time/tqual.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.45 2001/12/19 17:18:39 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.46 2002/01/11 20:07:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -742,7 +742,21 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin)
 
 	if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
 	{
-		/* "deleting" xact really only marked it for update */
+		/*
+		 * "Deleting" xact really only marked it for update, so the tuple
+		 * is live in any case.  However, we must make sure that either
+		 * XMAX_COMMITTED or XMAX_INVALID gets set once the xact is gone;
+		 * otherwise it is unsafe to recycle CLOG status after vacuuming.
+		 */
+		if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
+		{
+			if (TransactionIdIsInProgress(tuple->t_xmax))
+				return HEAPTUPLE_LIVE;
+			if (TransactionIdDidCommit(tuple->t_xmax))
+				tuple->t_infomask |= HEAP_XMAX_COMMITTED;
+			else				/* it's either aborted or crashed */
+				tuple->t_infomask |= HEAP_XMAX_INVALID;
+		}
 		return HEAPTUPLE_LIVE;
 	}
 
-- 
GitLab