heapam: Move logic to handle HEAP_MOVED into a helper function master github/master
authorAndres Freund <[email protected]>
Fri, 19 Dec 2025 18:28:34 +0000 (13:28 -0500)
committerAndres Freund <[email protected]>
Fri, 19 Dec 2025 18:28:34 +0000 (13:28 -0500)
Before we dealt with this in 6 near identical and one very similar copy.

The helper function errors out when encountering a
HEAP_MOVED_IN/HEAP_MOVED_OUT tuple with xvac considered current or
in-progress. It'd be preferrable to do that change separately, but otherwise
it'd not be possible to deduplicate the handling in
HeapTupleSatisfiesVacuum().

Reviewed-by: Heikki Linnakangas <[email protected]>
Discussion: https://postgr.es/m/lxzj26ga6ippdeunz6kuncectr5gfuugmm2ry22qu6hcx6oid6@lzx3sjsqhmt6
Discussion: https://postgr.es/m/6rgb2nvhyvnszz4ul3wfzlf5rheb2kkwrglthnna7qhe24onwr@vw27225tkyar

src/backend/access/heap/heapam_visibility.c

index 05f6946fe60d274597735fae982d78dc9be538da..bf899c2d2c698dc69ae867127cc1a27000d37bf9 100644 (file)
@@ -144,6 +144,55 @@ HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer,
    SetHintBits(tuple, buffer, infomask, xid);
 }
 
+/*
+ * If HEAP_MOVED_OFF or HEAP_MOVED_IN are set on the tuple, remove them and
+ * adjust hint bits. See the comment for SetHintBits() for more background.
+ *
+ * This helper returns false if the row ought to be invisible, true otherwise.
+ */
+static inline bool
+HeapTupleCleanMoved(HeapTupleHeader tuple, Buffer buffer)
+{
+   TransactionId xvac;
+
+   /* only used by pre-9.0 binary upgrades */
+   if (likely(!(tuple->t_infomask & (HEAP_MOVED_OFF | HEAP_MOVED_IN))))
+       return true;
+
+   xvac = HeapTupleHeaderGetXvac(tuple);
+
+   if (TransactionIdIsCurrentTransactionId(xvac))
+       elog(ERROR, "encountered tuple with HEAP_MOVED considered current");
+
+   if (TransactionIdIsInProgress(xvac))
+       elog(ERROR, "encountered tuple with HEAP_MOVED considered in-progress");
+
+   if (tuple->t_infomask & HEAP_MOVED_OFF)
+   {
+       if (TransactionIdDidCommit(xvac))
+       {
+           SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
+                       InvalidTransactionId);
+           return false;
+       }
+       SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
+                   InvalidTransactionId);
+   }
+   else if (tuple->t_infomask & HEAP_MOVED_IN)
+   {
+       if (TransactionIdDidCommit(xvac))
+           SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
+                       InvalidTransactionId);
+       else
+       {
+           SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
+                       InvalidTransactionId);
+           return false;
+       }
+   }
+
+   return true;
+}
 
 /*
  * HeapTupleSatisfiesSelf
@@ -179,45 +228,8 @@ HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
        if (HeapTupleHeaderXminInvalid(tuple))
            return false;
 
-       /* Used by pre-9.0 binary upgrades */
-       if (tuple->t_infomask & HEAP_MOVED_OFF)
-       {
-           TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
-
-           if (TransactionIdIsCurrentTransactionId(xvac))
-               return false;
-           if (!TransactionIdIsInProgress(xvac))
-           {
-               if (TransactionIdDidCommit(xvac))
-               {
-                   SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
-                               InvalidTransactionId);
-                   return false;
-               }
-               SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-                           InvalidTransactionId);
-           }
-       }
-       /* Used by pre-9.0 binary upgrades */
-       else if (tuple->t_infomask & HEAP_MOVED_IN)
-       {
-           TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
-
-           if (!TransactionIdIsCurrentTransactionId(xvac))
-           {
-               if (TransactionIdIsInProgress(xvac))
-                   return false;
-               if (TransactionIdDidCommit(xvac))
-                   SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-                               InvalidTransactionId);
-               else
-               {
-                   SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
-                               InvalidTransactionId);
-                   return false;
-               }
-           }
-       }
+       if (!HeapTupleCleanMoved(tuple, buffer))
+           return false;
        else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
        {
            if (tuple->t_infomask & HEAP_XMAX_INVALID)  /* xid invalid */
@@ -372,45 +384,8 @@ HeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot,
        if (HeapTupleHeaderXminInvalid(tuple))
            return false;
 
-       /* Used by pre-9.0 binary upgrades */
-       if (tuple->t_infomask & HEAP_MOVED_OFF)
-       {
-           TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
-
-           if (TransactionIdIsCurrentTransactionId(xvac))
-               return false;
-           if (!TransactionIdIsInProgress(xvac))
-           {
-               if (TransactionIdDidCommit(xvac))
-               {
-                   SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
-                               InvalidTransactionId);
-                   return false;
-               }
-               SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-                           InvalidTransactionId);
-           }
-       }
-       /* Used by pre-9.0 binary upgrades */
-       else if (tuple->t_infomask & HEAP_MOVED_IN)
-       {
-           TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
-
-           if (!TransactionIdIsCurrentTransactionId(xvac))
-           {
-               if (TransactionIdIsInProgress(xvac))
-                   return false;
-               if (TransactionIdDidCommit(xvac))
-                   SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-                               InvalidTransactionId);
-               else
-               {
-                   SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
-                               InvalidTransactionId);
-                   return false;
-               }
-           }
-       }
+       if (!HeapTupleCleanMoved(tuple, buffer))
+           return false;
 
        /*
         * An invalid Xmin can be left behind by a speculative insertion that
@@ -468,45 +443,8 @@ HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
        if (HeapTupleHeaderXminInvalid(tuple))
            return TM_Invisible;
 
-       /* Used by pre-9.0 binary upgrades */
-       if (tuple->t_infomask & HEAP_MOVED_OFF)
-       {
-           TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
-
-           if (TransactionIdIsCurrentTransactionId(xvac))
-               return TM_Invisible;
-           if (!TransactionIdIsInProgress(xvac))
-           {
-               if (TransactionIdDidCommit(xvac))
-               {
-                   SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
-                               InvalidTransactionId);
-                   return TM_Invisible;
-               }
-               SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-                           InvalidTransactionId);
-           }
-       }
-       /* Used by pre-9.0 binary upgrades */
-       else if (tuple->t_infomask & HEAP_MOVED_IN)
-       {
-           TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
-
-           if (!TransactionIdIsCurrentTransactionId(xvac))
-           {
-               if (TransactionIdIsInProgress(xvac))
-                   return TM_Invisible;
-               if (TransactionIdDidCommit(xvac))
-                   SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-                               InvalidTransactionId);
-               else
-               {
-                   SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
-                               InvalidTransactionId);
-                   return TM_Invisible;
-               }
-           }
-       }
+       else if (!HeapTupleCleanMoved(tuple, buffer))
+           return TM_Invisible;
        else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
        {
            if (HeapTupleHeaderGetCmin(tuple) >= curcid)
@@ -756,45 +694,8 @@ HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot,
        if (HeapTupleHeaderXminInvalid(tuple))
            return false;
 
-       /* Used by pre-9.0 binary upgrades */
-       if (tuple->t_infomask & HEAP_MOVED_OFF)
-       {
-           TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
-
-           if (TransactionIdIsCurrentTransactionId(xvac))
-               return false;
-           if (!TransactionIdIsInProgress(xvac))
-           {
-               if (TransactionIdDidCommit(xvac))
-               {
-                   SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
-                               InvalidTransactionId);
-                   return false;
-               }
-               SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-                           InvalidTransactionId);
-           }
-       }
-       /* Used by pre-9.0 binary upgrades */
-       else if (tuple->t_infomask & HEAP_MOVED_IN)
-       {
-           TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
-
-           if (!TransactionIdIsCurrentTransactionId(xvac))
-           {
-               if (TransactionIdIsInProgress(xvac))
-                   return false;
-               if (TransactionIdDidCommit(xvac))
-                   SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-                               InvalidTransactionId);
-               else
-               {
-                   SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
-                               InvalidTransactionId);
-                   return false;
-               }
-           }
-       }
+       if (!HeapTupleCleanMoved(tuple, buffer))
+           return false;
        else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
        {
            if (tuple->t_infomask & HEAP_XMAX_INVALID)  /* xid invalid */
@@ -979,45 +880,8 @@ HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
        if (HeapTupleHeaderXminInvalid(tuple))
            return false;
 
-       /* Used by pre-9.0 binary upgrades */
-       if (tuple->t_infomask & HEAP_MOVED_OFF)
-       {
-           TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
-
-           if (TransactionIdIsCurrentTransactionId(xvac))
-               return false;
-           if (!XidInMVCCSnapshot(xvac, snapshot))
-           {
-               if (TransactionIdDidCommit(xvac))
-               {
-                   SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
-                               InvalidTransactionId);
-                   return false;
-               }
-               SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-                           InvalidTransactionId);
-           }
-       }
-       /* Used by pre-9.0 binary upgrades */
-       else if (tuple->t_infomask & HEAP_MOVED_IN)
-       {
-           TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
-
-           if (!TransactionIdIsCurrentTransactionId(xvac))
-           {
-               if (XidInMVCCSnapshot(xvac, snapshot))
-                   return false;
-               if (TransactionIdDidCommit(xvac))
-                   SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-                               InvalidTransactionId);
-               else
-               {
-                   SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
-                               InvalidTransactionId);
-                   return false;
-               }
-           }
-       }
+       if (!HeapTupleCleanMoved(tuple, buffer))
+           return false;
        else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
        {
            if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
@@ -1222,43 +1086,8 @@ HeapTupleSatisfiesVacuumHorizon(HeapTuple htup, Buffer buffer, TransactionId *de
    {
        if (HeapTupleHeaderXminInvalid(tuple))
            return HEAPTUPLE_DEAD;
-       /* Used by pre-9.0 binary upgrades */
-       else if (tuple->t_infomask & HEAP_MOVED_OFF)
-       {
-           TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
-
-           if (TransactionIdIsCurrentTransactionId(xvac))
-               return HEAPTUPLE_DELETE_IN_PROGRESS;
-           if (TransactionIdIsInProgress(xvac))
-               return HEAPTUPLE_DELETE_IN_PROGRESS;
-           if (TransactionIdDidCommit(xvac))
-           {
-               SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
-                           InvalidTransactionId);
-               return HEAPTUPLE_DEAD;
-           }
-           SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-                       InvalidTransactionId);
-       }
-       /* Used by pre-9.0 binary upgrades */
-       else if (tuple->t_infomask & HEAP_MOVED_IN)
-       {
-           TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
-
-           if (TransactionIdIsCurrentTransactionId(xvac))
-               return HEAPTUPLE_INSERT_IN_PROGRESS;
-           if (TransactionIdIsInProgress(xvac))
-               return HEAPTUPLE_INSERT_IN_PROGRESS;
-           if (TransactionIdDidCommit(xvac))
-               SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-                           InvalidTransactionId);
-           else
-           {
-               SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
-                           InvalidTransactionId);
-               return HEAPTUPLE_DEAD;
-           }
-       }
+       else if (!HeapTupleCleanMoved(tuple, buffer))
+           return HEAPTUPLE_DEAD;
        else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
        {
            if (tuple->t_infomask & HEAP_XMAX_INVALID)  /* xid invalid */