diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 4fdb549099..0040913730 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -6800,9 +6800,11 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, xl_heap_freeze_tuple *frz, bool *totally_frozen_p) { bool changed = false; - bool freeze_xmax = false; + bool xmin_already_frozen; + bool xmax_already_frozen; + bool freeze_xmin; + bool freeze_xmax; TransactionId xid; - bool totally_frozen = true; frz->frzflags = 0; frz->t_infomask2 = tuple->t_infomask2; @@ -6811,7 +6813,11 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, /* Process xmin */ xid = HeapTupleHeaderGetXmin(tuple); - if (TransactionIdIsNormal(xid)) + + freeze_xmin = false; + if (HeapTupleHeaderXminFrozen(tuple)) + xmin_already_frozen = true; + else if (TransactionIdIsNormal(xid)) { if (TransactionIdPrecedes(xid, relfrozenxid)) ereport(ERROR, @@ -6827,11 +6833,15 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, errmsg_internal("uncommitted xmin %u from before xid cutoff %u needs to be frozen", xid, cutoff_xid))); - frz->t_infomask |= HEAP_XMIN_FROZEN; - changed = true; + freeze_xmin = true; } - else - totally_frozen = false; + } + + if (freeze_xmin) + { + Assert(!xmin_already_frozen); + frz->t_infomask |= HEAP_XMIN_FROZEN; + changed = true; } /* @@ -6854,9 +6864,9 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, relfrozenxid, relminmxid, cutoff_xid, cutoff_multi, &flags); - if (flags & FRM_INVALIDATE_XMAX) - freeze_xmax = true; - else if (flags & FRM_RETURN_IS_XID) + freeze_xmax = (flags & FRM_INVALIDATE_XMAX); + + if (flags & FRM_RETURN_IS_XID) { /* * NB -- some of these transformations are only valid because we @@ -6870,7 +6880,6 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, if (flags & FRM_MARK_COMMITTED) frz->t_infomask |= HEAP_XMAX_COMMITTED; changed = true; - totally_frozen = false; } else if (flags & FRM_RETURN_IS_MULTI) { @@ -6892,15 +6901,11 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, frz->xmax = newxmax; changed = true; - totally_frozen = false; - } - else - { - Assert(flags & FRM_NOOP); } } else if (TransactionIdIsNormal(xid)) { + freeze_xmax = false; if (TransactionIdPrecedes(xid, relfrozenxid)) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), @@ -6923,12 +6928,23 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, xid))); freeze_xmax = true; } - else - totally_frozen = false; + } + else if (((tuple->t_infomask & HEAP_XMAX_INVALID) == HEAP_XMAX_INVALID) || + !TransactionIdIsValid(HeapTupleHeaderGetRawXmax(tuple))) + { + freeze_xmax = false; + xmax_already_frozen = true; + } + else + { + /* XXX ERROR? */ + freeze_xmax = false; } if (freeze_xmax) { + Assert(!xmax_already_frozen); + frz->xmax = InvalidTransactionId; /* @@ -6981,7 +6997,8 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, } } - *totally_frozen_p = totally_frozen; + *totally_frozen_p = (freeze_xmin || xmin_already_frozen) && + (freeze_xmax || xmax_already_frozen); return changed; }