Skip to content

Commit bc0550f

Browse files
committed
Clean up after erroneous SELECT FOR UPDATE/SHARE on a sequence.
My previous commit disallowed this operation, but did nothing about cleaning up the damage if one had already been done. With the operation disallowed, it's okay to just forcibly clear xmax in a sequence's tuple, since any value seen there could not represent a live transaction's lock. So, any sequence-specific operation will repair the problem automatically, whether or not the user has already seen "could not access status of transaction" failures.
1 parent c117838 commit bc0550f

File tree

1 file changed

+16
-0
lines changed

1 file changed

+16
-0
lines changed

src/backend/commands/sequence.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,22 @@ read_info(SeqTable elm, Relation rel, Buffer *buf)
982982
Assert(ItemIdIsNormal(lp));
983983
tuple.t_data = (HeapTupleHeader) PageGetItem(page, lp);
984984

985+
/*
986+
* Previous releases of Postgres neglected to prevent SELECT FOR UPDATE
987+
* on a sequence, which would leave a non-frozen XID in the sequence
988+
* tuple's xmax, which eventually leads to clog access failures or worse.
989+
* If we see this has happened, clean up after it. We treat this like a
990+
* hint bit update, ie, don't bother to WAL-log it, since we can certainly
991+
* do this again if the update gets lost.
992+
*/
993+
if (HeapTupleHeaderGetXmax(tuple.t_data) != InvalidTransactionId)
994+
{
995+
HeapTupleHeaderSetXmax(tuple.t_data, InvalidTransactionId);
996+
tuple.t_data->t_infomask &= ~HEAP_XMAX_COMMITTED;
997+
tuple.t_data->t_infomask |= HEAP_XMAX_INVALID;
998+
SetBufferCommitInfoNeedsSave(*buf);
999+
}
1000+
9851001
seq = (Form_pg_sequence) GETSTRUCT(&tuple);
9861002

9871003
/* this is a handy place to update our copy of the increment */

0 commit comments

Comments
 (0)