>From 4ba3789b3f37bfe9676ec8af0aa5c3daa2489ca6 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Thu, 21 Nov 2013 14:21:39 +0100
Subject: [PATCH 2/2] Updates to the patch from Andres

---
 contrib/pageinspect/heapfuncs.c       |  2 +-
 src/backend/access/common/heaptuple.c |  2 +-
 src/backend/access/heap/heapam.c      | 15 +++++++------
 src/backend/access/heap/pruneheap.c   |  4 ++--
 src/backend/access/heap/rewriteheap.c |  1 -
 src/backend/commands/typecmds.c       |  3 +--
 src/backend/commands/vacuumlazy.c     |  5 -----
 src/backend/optimizer/util/plancat.c  |  1 -
 src/backend/storage/lmgr/predicate.c  |  5 +----
 src/backend/utils/adt/ri_triggers.c   |  6 ++---
 src/backend/utils/cache/relcache.c    |  8 ++-----
 src/backend/utils/fmgr/fmgr.c         |  4 ++--
 src/backend/utils/time/combocid.c     |  6 ++---
 src/backend/utils/time/tqual.c        | 42 +++++++++++++++++------------------
 src/include/access/htup_details.h     | 25 +++++++++++++++++----
 src/pl/plperl/plperl.c                |  4 ++--
 src/pl/plpgsql/src/pl_comp.c          |  4 ++--
 src/pl/plpython/plpy_procedure.c      |  6 ++---
 src/pl/plpython/plpy_typeio.c         |  4 ++--
 src/pl/tcl/pltcl.c                    |  4 ++--
 20 files changed, 75 insertions(+), 76 deletions(-)

diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index 6d8f6f1..a78cff3 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -162,7 +162,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 			tuphdr = (HeapTupleHeader) PageGetItem(page, id);
 
-			values[4] = UInt32GetDatum(HeapTupleHeaderGetXmin(tuphdr));
+			values[4] = UInt32GetDatum(HeapTupleHeaderGetRawXmin(tuphdr));
 			values[5] = UInt32GetDatum(HeapTupleHeaderGetRawXmax(tuphdr));
 			values[6] = UInt32GetDatum(HeapTupleHeaderGetRawCommandId(tuphdr)); /* shared with xvac */
 			values[7] = PointerGetDatum(&tuphdr->t_ctid);
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index e39b977..347d616 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -539,7 +539,7 @@ heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
 			result = ObjectIdGetDatum(HeapTupleGetOid(tup));
 			break;
 		case MinTransactionIdAttributeNumber:
-			result = TransactionIdGetDatum(HeapTupleHeaderGetXmin(tup->t_data));
+			result = TransactionIdGetDatum(HeapTupleHeaderGetRawXmin(tup->t_data));
 			break;
 		case MaxTransactionIdAttributeNumber:
 			result = TransactionIdGetDatum(HeapTupleHeaderGetRawXmax(tup->t_data));
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index eb56230..fbc3043 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -1733,7 +1733,7 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
 		 */
 		if (TransactionIdIsValid(prev_xmax) &&
 			!TransactionIdEquals(prev_xmax,
-								 HeapTupleHeaderGetXmin(heapTuple->t_data)))
+								 HeapTupleHeaderGetRawXmin(heapTuple->t_data)))
 			break;
 
 		/*
@@ -2221,9 +2221,11 @@ heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
-	HeapTupleHeaderSetXmin(tup->t_data, xid);
 	if (options & HEAP_INSERT_FROZEN)
 		HeapTupleHeaderSetXminFrozen(tup->t_data);
+	else
+		HeapTupleHeaderSetXmin(tup->t_data, xid);
+
 	HeapTupleHeaderSetCmin(tup->t_data, cid);
 	HeapTupleHeaderSetXmax(tup->t_data, 0);		/* for cleanliness */
 	tup->t_tableOid = RelationGetRelid(relation);
@@ -5118,7 +5120,7 @@ heap_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
 
 	if (!HeapTupleHeaderXminFrozen(tuple))
 	{
-		xid = HeapTupleHeaderGetXmin(tuple);
+		xid = HeapTupleHeaderGetRawXmin(tuple);
 		if (TransactionIdIsNormal(xid) &&
 			TransactionIdPrecedes(xid, cutoff_xid))
 		{
@@ -5470,7 +5472,7 @@ heap_tuple_needs_freeze(HeapTupleHeader tuple, TransactionId cutoff_xid,
 
 	if (!HeapTupleHeaderXminFrozen(tuple))
 	{
-		xid = HeapTupleHeaderGetXmin(tuple);
+		xid = HeapTupleHeaderGetRawXmin(tuple);
 		if (TransactionIdIsNormal(xid) &&
 			TransactionIdPrecedes(xid, cutoff_xid))
 			return true;
@@ -5597,14 +5599,13 @@ HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
 	 * updated/deleted by the inserting transaction.
 	 *
 	 * Look for a committed hint bit, or if no xmin bit is set, check clog.
-	 * This needs to work on both master and standby, where it is used to
+	 * This needs to work on both master, and standby where it is used to
 	 * assess btree delete records.
 	 */
 	if (HeapTupleHeaderXminCommitted(tuple) ||
 		(!HeapTupleHeaderXminInvalid(tuple) && TransactionIdDidCommit(xmin)))
 	{
-		if ((HeapTupleHeaderXminFrozen(tuple) || xmax != xmin) &&
-			TransactionIdFollows(xmax, *latestRemovedXid))
+		if (xmax != xmin && TransactionIdFollows(xmax, *latestRemovedXid))
 			*latestRemovedXid = xmax;
 	}
 
diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index 3ec10a0..d731e43 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -448,7 +448,7 @@ heap_prune_chain(Relation relation, Buffer buffer, OffsetNumber rootoffnum,
 		 * Check the tuple XMIN against prior XMAX, if any
 		 */
 		if (TransactionIdIsValid(priorXmax) &&
-			!TransactionIdEquals(HeapTupleHeaderGetXmin(htup), priorXmax))
+			!TransactionIdEquals(HeapTupleHeaderGetRawXmin(htup), priorXmax))
 			break;
 
 		/*
@@ -788,7 +788,7 @@ heap_get_root_tuples(Page page, OffsetNumber *root_offsets)
 			htup = (HeapTupleHeader) PageGetItem(page, lp);
 
 			if (TransactionIdIsValid(priorXmax) &&
-				!TransactionIdEquals(priorXmax, HeapTupleHeaderGetXmin(htup)))
+				!TransactionIdEquals(priorXmax, HeapTupleHeaderGetRawXmin(htup)))
 				break;
 
 			/* Remember the root line pointer for this item */
diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index f236a46..951894c 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -437,7 +437,6 @@ rewrite_heap_tuple(RewriteState state,
 		 * RECENTLY_DEAD if and only if the xmin is not before OldestXmin.
 		 */
 		if ((new_tuple->t_data->t_infomask & HEAP_UPDATED) &&
-			!HeapTupleHeaderXminFrozen(new_tuple->t_data) &&
 			!TransactionIdPrecedes(HeapTupleHeaderGetXmin(new_tuple->t_data),
 								   state->rs_oldest_xmin))
 		{
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 4ad8386..d4a14ca 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -1202,8 +1202,7 @@ AlterEnum(AlterEnumStmt *stmt, bool isTopLevel)
 	 * cases that could theoretically be safe; but fortunately pg_dump only
 	 * needs the simplest case.
 	 */
-	if (!HeapTupleHeaderXminFrozen(tup->t_data) &&
-		HeapTupleHeaderGetXmin(tup->t_data) == GetCurrentTransactionId() &&
+	if (HeapTupleHeaderGetXmin(tup->t_data) == GetCurrentTransactionId() &&
 		!(tup->t_data->t_infomask & HEAP_UPDATED))
 		 /* safe to do inside transaction block */ ;
 	else
diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c
index 7ac1352..cc8aaf7 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -818,13 +818,10 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 							break;
 						}
 
-
 						/*
 						 * The inserter definitely committed. But is it old
 						 * enough that everyone sees it as committed?
 						 */
-						if (HeapTupleHeaderXminFrozen(tuple.t_data))
-							break;
 						xmin = HeapTupleHeaderGetXmin(tuple.t_data);
 						if (!TransactionIdPrecedes(xmin, OldestXmin))
 						{
@@ -1749,8 +1746,6 @@ heap_page_is_all_visible(Relation rel, Buffer buf, TransactionId *visibility_cut
 					 * The inserter definitely committed. But is it old enough
 					 * that everyone sees it as committed?
 					 */
-					if (HeapTupleHeaderXminFrozen(tuple.t_data))
-						break;
 					xmin = HeapTupleHeaderGetXmin(tuple.t_data);
 					if (!TransactionIdPrecedes(xmin, OldestXmin))
 					{
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index e22be0e..954666c 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -188,7 +188,6 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 			 * src/backend/access/heap/README.HOT for discussion.
 			 */
 			if (index->indcheckxmin &&
-				!HeapTupleHeaderXminFrozen(indexRelation->rd_indextuple->t_data) &&
 				!TransactionIdPrecedes(HeapTupleHeaderGetXmin(indexRelation->rd_indextuple->t_data),
 									   TransactionXmin))
 			{
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 77d87c7..8143ed0 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -2475,10 +2475,7 @@ PredicateLockTuple(Relation relation, HeapTuple tuple, Snapshot snapshot)
 	{
 		TransactionId myxid;
 
-		if (HeapTupleHeaderXminFrozen(tuple->t_data))
-			targetxmin = FrozenTransactionId;
-		else
-			targetxmin = HeapTupleHeaderGetXmin(tuple->t_data);
+		targetxmin = HeapTupleHeaderGetXmin(tuple->t_data);
 
 		myxid = GetTopTransactionIdIfAny();
 		if (TransactionIdIsValid(myxid))
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index ed906ee..917130f 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -2166,8 +2166,7 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
 			 * UPDATE check.  (We could skip this if we knew the INSERT
 			 * trigger already fired, but there is no easy way to know that.)
 			 */
-			if (!HeapTupleHeaderXminFrozen(old_row->t_data) &&
-				TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(old_row->t_data)))
+			if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(old_row->t_data)))
 				return true;
 
 			/* If all old and new key values are equal, no check is needed */
@@ -2205,8 +2204,7 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
 			 * UPDATE check.  (We could skip this if we knew the INSERT
 			 * trigger already fired, but there is no easy way to know that.)
 			 */
-			if (!HeapTupleHeaderXminFrozen(old_row->t_data) &&
-				TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(old_row->t_data)))
+			if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(old_row->t_data)))
 				return true;
 
 			/* If all old and new key values are equal, no check is needed */
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 4b92fbf..d0acca8 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1764,7 +1764,6 @@ RelationReloadIndexInfo(Relation relation)
 	{
 		HeapTuple	tuple;
 		Form_pg_index index;
-		TransactionId xmin;
 
 		tuple = SearchSysCache1(INDEXRELID,
 								ObjectIdGetDatum(RelationGetRelid(relation)));
@@ -1790,11 +1789,8 @@ RelationReloadIndexInfo(Relation relation)
 		relation->rd_index->indislive = index->indislive;
 
 		/* Copy xmin too, as that is needed to make sense of indcheckxmin */
-		if (HeapTupleHeaderXminFrozen(relation->rd_indextuple->t_data))
-			xmin = FrozenTransactionId;
-		else
-			xmin = HeapTupleHeaderGetXmin(relation->rd_indextuple->t_data);
-		HeapTupleHeaderSetXmin(relation->rd_indextuple->t_data, xmin);
+		HeapTupleHeaderSetXmin(relation->rd_indextuple->t_data,
+							   HeapTupleHeaderGetXmin(tuple->t_data));
 
 		ReleaseSysCache(tuple);
 	}
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index 9246a00..cae1116 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -514,7 +514,7 @@ lookup_C_func(HeapTuple procedureTuple)
 					NULL);
 	if (entry == NULL)
 		return NULL;			/* no such entry */
-	if (entry->fn_xmin == HeapTupleHeaderGetXmin(procedureTuple->t_data) &&
+	if (entry->fn_xmin == HeapTupleHeaderGetRawXmin(procedureTuple->t_data) &&
 		ItemPointerEquals(&entry->fn_tid, &procedureTuple->t_self))
 		return entry;			/* OK */
 	return NULL;				/* entry is out of date */
@@ -552,7 +552,7 @@ record_C_func(HeapTuple procedureTuple,
 					HASH_ENTER,
 					&found);
 	/* OID is already filled in */
-	entry->fn_xmin = HeapTupleHeaderGetXmin(procedureTuple->t_data);
+	entry->fn_xmin = HeapTupleHeaderGetRawXmin(procedureTuple->t_data);
 	entry->fn_tid = procedureTuple->t_self;
 	entry->user_fn = user_fn;
 	entry->inforec = inforec;
diff --git a/src/backend/utils/time/combocid.c b/src/backend/utils/time/combocid.c
index baacd4a..08955f3 100644
--- a/src/backend/utils/time/combocid.c
+++ b/src/backend/utils/time/combocid.c
@@ -148,10 +148,8 @@ HeapTupleHeaderAdjustCmax(HeapTupleHeader tup,
 	/*
 	 * If we're marking a tuple deleted that was inserted by (any
 	 * subtransaction of) our transaction, we need to use a combo command id.
-	 * It's cheaper to test HeapTupleHeaderXminCommitted before checking
-	 * TransactionIdIsCurrentTransactionId, but it's also necessary for
-	 * correctness: if HeapTupleHeaderXminCommitted returns true, the tuple
-	 * might even be frozen.
+	 * Test for HeapTupleHeaderXminCommitted() first, because it's cheaper than a
+	 * TransactionIdIsCurrentTransactionId call.
 	 */
 	if (!HeapTupleHeaderXminCommitted(tup) &&
 		TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tup)))
diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c
index bf8c9919..341cc4c 100644
--- a/src/backend/utils/time/tqual.c
+++ b/src/backend/utils/time/tqual.c
@@ -210,7 +210,7 @@ HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
 				}
 			}
 		}
-		else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
+		else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
 		{
 			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */
 				return true;
@@ -243,11 +243,11 @@ HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
 
 			return false;
 		}
-		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
+		else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
 			return false;
-		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
+		else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
 			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-						HeapTupleHeaderGetXmin(tuple));
+						HeapTupleHeaderGetRawXmin(tuple));
 		else
 		{
 			/* it must have aborted or crashed */
@@ -481,7 +481,7 @@ HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
 				}
 			}
 		}
-		else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
+		else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
 		{
 			if (HeapTupleHeaderGetCmin(tuple) >= curcid)
 				return HeapTupleInvisible;		/* inserted after scan started */
@@ -527,11 +527,11 @@ HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
 			else
 				return HeapTupleInvisible;		/* updated before scan started */
 		}
-		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
+		else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
 			return HeapTupleInvisible;
-		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
+		else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
 			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-						HeapTupleHeaderGetXmin(tuple));
+						HeapTupleHeaderGetRawXmin(tuple));
 		else
 		{
 			/* it must have aborted or crashed */
@@ -709,7 +709,7 @@ HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot,
 				}
 			}
 		}
-		else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
+		else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
 		{
 			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */
 				return true;
@@ -742,15 +742,15 @@ HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot,
 
 			return false;
 		}
-		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
+		else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
 		{
-			snapshot->xmin = HeapTupleHeaderGetXmin(tuple);
+			snapshot->xmin = HeapTupleHeaderGetRawXmin(tuple);
 			/* XXX shouldn't we fall through to look at xmax? */
 			return true;		/* in insertion by other */
 		}
-		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
+		else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
 			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-						HeapTupleHeaderGetXmin(tuple));
+						HeapTupleHeaderGetRawXmin(tuple));
 		else
 		{
 			/* it must have aborted or crashed */
@@ -899,7 +899,7 @@ HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
 				}
 			}
 		}
-		else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
+		else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
 		{
 			if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
 				return false;	/* inserted after scan started */
@@ -940,11 +940,11 @@ HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
 			else
 				return false;	/* deleted before scan started */
 		}
-		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
+		else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
 			return false;
-		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
+		else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
 			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-						HeapTupleHeaderGetXmin(tuple));
+						HeapTupleHeaderGetRawXmin(tuple));
 		else
 		{
 			/* it must have aborted or crashed */
@@ -959,7 +959,7 @@ HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
 	 * when...
 	 */
 	if (!HeapTupleHeaderXminFrozen(tuple)
-		&& XidInMVCCSnapshot(HeapTupleHeaderGetXmin(tuple), snapshot))
+		&& XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
 		return false;			/* treat as still in progress */
 
 	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */
@@ -1100,7 +1100,7 @@ HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin,
 				return HEAPTUPLE_DEAD;
 			}
 		}
-		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
+		else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
 		{
 			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */
 				return HEAPTUPLE_INSERT_IN_PROGRESS;
@@ -1111,9 +1111,9 @@ HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin,
 			/* inserted and then deleted by same xact */
 			return HEAPTUPLE_DELETE_IN_PROGRESS;
 		}
-		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
+		else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
 			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-						HeapTupleHeaderGetXmin(tuple));
+						HeapTupleHeaderGetRawXmin(tuple));
 		else
 		{
 			/*
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index f91dbc1..b3b8894 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -17,6 +17,7 @@
 #include "access/htup.h"
 #include "access/tupdesc.h"
 #include "access/tupmacs.h"
+#include "access/transam.h"
 #include "storage/bufpage.h"
 
 /*
@@ -245,11 +246,24 @@ struct HeapTupleHeaderData
  * macros evaluate their other argument only once.
  */
 
-#define HeapTupleHeaderGetXmin(tup) \
+/*
+ * HeapTupleHeaderGetRawXmin returns the "raw" xmin field - it might actually
+ * be frozen in which case it may never be used for anything but diagnostics
+ * purposes. Use HeapTupleHeaderGetXmin if not interested in such values or
+ * check for frozen xids with HeapTupleHeaderXminFrozen(). Not that even using
+ * *RawXmin might return FrozenTransactionId in pg_upgrade'd clusters.
+ */
+#define HeapTupleHeaderGetRawXmin(tup) \
 ( \
 	(tup)->t_choice.t_heap.t_xmin \
 )
 
+#define HeapTupleHeaderGetXmin(tup) \
+( \
+	HeapTupleHeaderXminFrozen(tup) ? \
+		FrozenTransactionId : HeapTupleHeaderGetRawXmin(tup) \
+)
+
 #define HeapTupleHeaderSetXmin(tup, xid) \
 ( \
 	(tup)->t_choice.t_heap.t_xmin = (xid) \
@@ -257,17 +271,18 @@ struct HeapTupleHeaderData
 
 #define HeapTupleHeaderXminCommitted(tup) \
 ( \
-	((tup)->t_infomask & HEAP_XMIN_COMMITTED) == HEAP_XMIN_COMMITTED \
+	(tup)->t_infomask & HEAP_XMIN_COMMITTED \
 )
+
 #define HeapTupleHeaderXminInvalid(tup) \
 ( \
 	((tup)->t_infomask & (HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID)) == \
 		HEAP_XMIN_INVALID \
 )
+
 #define HeapTupleHeaderXminFrozen(tup) \
 ( \
-	((tup)->t_infomask & (HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID)) == \
-		HEAP_XMIN_FROZEN \
+	((tup)->t_infomask & (HEAP_XMIN_FROZEN)) == HEAP_XMIN_FROZEN \
 )
 
 #define HeapTupleHeaderSetXminCommitted(tup) \
@@ -275,11 +290,13 @@ struct HeapTupleHeaderData
 	AssertMacro(!HeapTupleHeaderXminInvalid(tup)), \
 	((tup)->t_infomask |= HEAP_XMIN_COMMITTED) \
 )
+
 #define HeapTupleHeaderSetXminInvalid(tup) \
 ( \
 	AssertMacro(!HeapTupleHeaderXminCommitted(tup)), \
 	((tup)->t_infomask |= HEAP_XMIN_INVALID) \
 )
+
 #define HeapTupleHeaderSetXminFrozen(tup) \
 ( \
 	AssertMacro(!HeapTupleHeaderXminInvalid(tup)), \
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index de8cb0e..5d418c1 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -2399,7 +2399,7 @@ validate_plperl_function(plperl_proc_ptr *proc_ptr, HeapTuple procTup)
 		 * This is needed because CREATE OR REPLACE FUNCTION can modify the
 		 * function's pg_proc entry without changing its OID.
 		 ************************************************************/
-		uptodate = (prodesc->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
+		uptodate = (prodesc->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) &&
 					ItemPointerEquals(&prodesc->fn_tid, &procTup->t_self));
 
 		if (uptodate)
@@ -2517,7 +2517,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
 					(errcode(ERRCODE_OUT_OF_MEMORY),
 					 errmsg("out of memory")));
 		}
-		prodesc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
+		prodesc->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data);
 		prodesc->fn_tid = procTup->t_self;
 
 		/* Remember if function is STABLE/IMMUTABLE */
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 426aeb5..9a16b0d 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -167,7 +167,7 @@ recheck:
 	if (function)
 	{
 		/* We have a compiled function, but is it still valid? */
-		if (function->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
+		if (function->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) &&
 			ItemPointerEquals(&function->fn_tid, &procTup->t_self))
 			function_valid = true;
 		else
@@ -345,7 +345,7 @@ do_compile(FunctionCallInfo fcinfo,
 
 	function->fn_signature = format_procedure(fcinfo->flinfo->fn_oid);
 	function->fn_oid = fcinfo->flinfo->fn_oid;
-	function->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
+	function->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data);
 	function->fn_tid = procTup->t_self;
 	function->fn_input_collation = fcinfo->fncollation;
 	function->fn_cxt = func_cxt;
diff --git a/src/pl/plpython/plpy_procedure.c b/src/pl/plpython/plpy_procedure.c
index d278d6e..fad80b2 100644
--- a/src/pl/plpython/plpy_procedure.c
+++ b/src/pl/plpython/plpy_procedure.c
@@ -157,7 +157,7 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger)
 	proc = PLy_malloc(sizeof(PLyProcedure));
 	proc->proname = PLy_strdup(NameStr(procStruct->proname));
 	proc->pyname = PLy_strdup(procName);
-	proc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
+	proc->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data);
 	proc->fn_tid = procTup->t_self;
 	/* Remember if function is STABLE/IMMUTABLE */
 	proc->fn_readonly =
@@ -446,7 +446,7 @@ PLy_procedure_argument_valid(PLyTypeInfo *arg)
 		elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid);
 
 	/* If it has changed, the cached data is not valid */
-	valid = (arg->typrel_xmin == HeapTupleHeaderGetXmin(relTup->t_data) &&
+	valid = (arg->typrel_xmin == HeapTupleHeaderGetRawXmin(relTup->t_data) &&
 			 ItemPointerEquals(&arg->typrel_tid, &relTup->t_self));
 
 	ReleaseSysCache(relTup);
@@ -466,7 +466,7 @@ PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup)
 	Assert(proc != NULL);
 
 	/* If the pg_proc tuple has changed, it's not valid */
-	if (!(proc->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
+	if (!(proc->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) &&
 		  ItemPointerEquals(&proc->fn_tid, &procTup->t_self)))
 		return false;
 
diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c
index caccbf9..40c67ca 100644
--- a/src/pl/plpython/plpy_typeio.c
+++ b/src/pl/plpython/plpy_typeio.c
@@ -157,7 +157,7 @@ PLy_input_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
 			elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid);
 
 		/* Remember XMIN and TID for later validation if cache is still OK */
-		arg->typrel_xmin = HeapTupleHeaderGetXmin(relTup->t_data);
+		arg->typrel_xmin = HeapTupleHeaderGetRawXmin(relTup->t_data);
 		arg->typrel_tid = relTup->t_self;
 
 		ReleaseSysCache(relTup);
@@ -221,7 +221,7 @@ PLy_output_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
 			elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid);
 
 		/* Remember XMIN and TID for later validation if cache is still OK */
-		arg->typrel_xmin = HeapTupleHeaderGetXmin(relTup->t_data);
+		arg->typrel_xmin = HeapTupleHeaderGetRawXmin(relTup->t_data);
 		arg->typrel_tid = relTup->t_self;
 
 		ReleaseSysCache(relTup);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index c94d0d8..b703bda 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1205,7 +1205,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, bool pltrusted)
 	{
 		bool		uptodate;
 
-		uptodate = (prodesc->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
+		uptodate = (prodesc->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) &&
 					ItemPointerEquals(&prodesc->fn_tid, &procTup->t_self));
 
 		if (!uptodate)
@@ -1267,7 +1267,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, bool pltrusted)
 			ereport(ERROR,
 					(errcode(ERRCODE_OUT_OF_MEMORY),
 					 errmsg("out of memory")));
-		prodesc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
+		prodesc->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data);
 		prodesc->fn_tid = procTup->t_self;
 
 		/* Remember if function is STABLE/IMMUTABLE */
-- 
1.8.5.rc2.dirty

