Hi, While working on another logical replication feature, I noticed a bug: the apply worker uses a raw xmin that may have been frozen when fetching tuple info for conflict detection and reporting.
The reason is that, GetTupleTransactionInfo() used slot_getsysattr() with MinTransactionIdAttributeNumber to fetch the local tuple's xmin. However, heap_getsysattr() calls HeapTupleHeaderGetRawXmin(), which returns the raw 32-bit t_xmin from the tuple header even when the tuple is marked frozen (HEAP_XMIN_FROZEN). Once a tuple is frozen, its raw t_xmin is retained only for debugging purposes; its commit timestamp entry may no longer be valid, or the 32-bit XID may have wrapped around and been reassigned in a later epoch. Using the raw xmin of a frozen tuple could therefore trigger spurious update_origin_differs or delete_origin_differs conflicts, or report bogus transaction ID, origin, and commit timestamp details for unique constraint conflicts. Attaching a patch fixing this by fetching the tuple via ExecFetchSlotHeapTuple() and calling HeapTupleHeaderGetXmin(), returning InvalidTransactionId and skipping the commit timestamp lookup when the tuple's xmin is not a normal transaction ID. Also update errdetail_apply_conflict() to omit the transaction ID from unique-conflict detail messages when localxmin is invalid. -- Best Regards, Zhijie Hou
v1-0001-Avoid-using-raw-xmin-of-frozen-tuples-in-conflict.patch
Description: Binary data
