aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2012-11-30 13:56:00 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2012-11-30 13:56:00 -0500
commit1c316e3a02e7eb8aaf8e04a441fc176aef06e317 (patch)
treef75c9d944c66784f4bcea2adeb2bbf7c6189c62a /src/backend
parent2c55189b2b9e71a14bba1496da6be84614595983 (diff)
downloadpostgresql-1c316e3a02e7eb8aaf8e04a441fc176aef06e317.tar.gz
postgresql-1c316e3a02e7eb8aaf8e04a441fc176aef06e317.zip
Add missing buffer lock acquisition in GetTupleForTrigger().
If we had not been holding buffer pin continuously since the tuple was initially fetched by the UPDATE or DELETE query, it would be possible for VACUUM or a page-prune operation to move the tuple while we're trying to copy it. This would result in a garbage "old" tuple value being passed to an AFTER ROW UPDATE or AFTER ROW DELETE trigger. The preconditions for this are somewhat improbable, and the timing constraints are very tight; so it's not so surprising that this hasn't been reported from the field, even though the bug has been there a long time. Problem found by Andres Freund. Back-patch to all active branches.
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/commands/trigger.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 70721a272d0..f546d9426fb 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -2663,6 +2663,16 @@ ltrmark:;
buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
+ /*
+ * Although we already know this tuple is valid, we must lock the
+ * buffer to ensure that no one has a buffer cleanup lock; otherwise
+ * they might move the tuple while we try to copy it. But we can
+ * release the lock before actually doing the heap_copytuple call,
+ * since holding pin is sufficient to prevent anyone from getting a
+ * cleanup lock they don't already hold.
+ */
+ LockBuffer(buffer, BUFFER_LOCK_SHARE);
+
page = BufferGetPage(buffer);
lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
@@ -2672,6 +2682,8 @@ ltrmark:;
tuple.t_len = ItemIdGetLength(lp);
tuple.t_self = *tid;
tuple.t_tableOid = RelationGetRelid(relation);
+
+ LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
}
result = heap_copytuple(&tuple);