summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2011-06-02 15:31:22 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2011-06-02 15:31:22 -0400
commit19fed6429575ce4f6bc5d24e434f56ca029595fa (patch)
treee03e6080d1e686dd7efdb605e15def0741e929b5
parentd369ddd9f1d5908e36616e5b9e953ecefde43be4 (diff)
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.
-rw-r--r--src/backend/commands/sequence.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index fe4ab667ec0..4066f6e72b0 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -949,6 +949,22 @@ read_info(SeqTable elm, Relation rel, Buffer *buf)
Assert(ItemIdIsNormal(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);
/* this is a handy place to update our copy of the increment */