]> granicus.if.org Git - postgresql/commitdiff
Clean up after erroneous SELECT FOR UPDATE/SHARE on a sequence.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 2 Jun 2011 19:30:56 +0000 (15:30 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 2 Jun 2011 19:32:21 +0000 (15:32 -0400)
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

index 6a91a102dcd3f4e4d3ceca558c59ed1247bae831..383690270b8801fc12e8515832c1e45d1a31dd37 100644 (file)
@@ -1076,6 +1076,22 @@ read_info(SeqTable elm, Relation rel, Buffer *buf)
        Assert(ItemIdIsNormal(lp));
        tuple.t_data = (HeapTupleHeader) PageGetItem(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 */