From f0d72ef638899ea1042e895c0573ba1d4af4d942 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 2 Jun 2011 15:31:28 -0400 Subject: [PATCH] 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. --- src/backend/commands/sequence.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 9404efa379f..84ac3a0d0f7 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -950,6 +950,22 @@ read_info(SeqTable elm, Relation rel, Buffer *buf) Assert(ItemIdIsUsed(lp)); tuple.t_data = (HeapTupleHeader) PageGetItem((Page) page, lp); + /* + * Previous releases of Postgres neglected to prevent SELECT FOR UPDATE + * on a sequence, which would leave a non-frozen XID in the sequence + * tuple's xmax, which eventually leads to clog access failures or worse. + * If we see this has happened, clean up after it. We treat this like a + * hint bit update, ie, don't bother to WAL-log it, since we can certainly + * do this again if the update gets lost. + */ + if (HeapTupleHeaderGetXmax(tuple.t_data) != InvalidTransactionId) + { + HeapTupleHeaderSetXmax(tuple.t_data, InvalidTransactionId); + tuple.t_data->t_infomask &= ~HEAP_XMAX_COMMITTED; + tuple.t_data->t_infomask |= HEAP_XMAX_INVALID; + SetBufferCommitInfoNeedsSave(*buf); + } + seq = (Form_pg_sequence) GETSTRUCT(&tuple); elm->increment = seq->increment_by; -- 2.39.5