From 1c7bf416cf445c8f65f8d511e6054e02308fa126 Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntalghosh.2007@gmail.com>
Date: Fri, 2 Oct 2020 23:03:18 +0530
Subject: [PATCH] Fix sanity check for HOT-updated tuple when freezing tuples

---
 src/backend/access/heap/heapam.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 1585861a02..127e6a84c4 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -6106,7 +6106,9 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
  *
  * It is assumed that the caller has checked the tuple with
  * HeapTupleSatisfiesVacuum() and determined that it is not HEAPTUPLE_DEAD
- * (else we should be removing the tuple, not freezing it).
+ * (else we should be removing the tuple, not freezing it).  But, there is an
+ * exception - if a tuple is HOT-updated then it must only be removed by a prune
+ * operation.  So, we can neither remove the tuple nor freeze the tuple.
  *
  * NB: cutoff_xid *must* be <= the current global xmin, to ensure that any
  * XID older than it could neither be running nor seen as running by any
@@ -6245,15 +6247,18 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
 			 * If we freeze xmax, make absolutely sure that it's not an XID
 			 * that is important.  (Note, a lock-only xmax can be removed
 			 * independent of committedness, since a committed lock holder has
-			 * released the lock).
+			 * released the lock.  Also, if the tuple is HOT-UPDATED, we can
+			 * neither remove it nor freeze it).
 			 */
 			if (!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) &&
-				TransactionIdDidCommit(xid))
+				TransactionIdDidCommit(xid) &&
+				!HeapTupleHeaderIsHotUpdated(tuple))
 				ereport(ERROR,
 						(errcode(ERRCODE_DATA_CORRUPTED),
 						 errmsg_internal("cannot freeze committed xmax %u",
 										 xid)));
-			freeze_xmax = true;
+
+			freeze_xmax = HeapTupleHeaderIsHotUpdated(tuple) ? false : true;
 		}
 		else
 			freeze_xmax = false;
-- 
2.27.0

