aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeModifyTable.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2013-03-10 19:18:49 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2013-03-10 19:18:49 -0400
commitcce7486127f27e6cf2ee56dfcfeb9e7c20a39b90 (patch)
treebd69be3d9afb5b360786f541b43e4e4bef1bc280 /src/backend/executor/nodeModifyTable.c
parentef2a82bebd991fc2ddc8a1ba37c657173b21910b (diff)
downloadpostgresql-cce7486127f27e6cf2ee56dfcfeb9e7c20a39b90.tar.gz
postgresql-cce7486127f27e6cf2ee56dfcfeb9e7c20a39b90.zip
Fix race condition in DELETE RETURNING.
When RETURNING is specified, ExecDelete would return a virtual-tuple slot that could contain pointers into an already-unpinned disk buffer. Another process could change the buffer contents before we get around to using the data, resulting in garbage results or even a crash. This seems of fairly low probability, which may explain why there are no known field reports of the problem, but it's definitely possible. Fix by forcing the result slot to be "materialized" before we release pin on the disk buffer. Back-patch to 9.0; in earlier branches there is no bug because ExecProcessReturning sent the tuple to the destination immediately. Also, this is already fixed in HEAD as part of the writable-foreign-tables patch (where the fix is necessary for DELETE RETURNING to work at all with postgres_fdw).
Diffstat (limited to 'src/backend/executor/nodeModifyTable.c')
-rw-r--r--src/backend/executor/nodeModifyTable.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index cb64cfc857a..d7c1e4a208b 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -439,6 +439,12 @@ ldelete:;
rslot = ExecProcessReturning(resultRelInfo->ri_projectReturning,
slot, planSlot);
+ /*
+ * Before releasing the target tuple again, make sure rslot has a
+ * local copy of any pass-by-reference values.
+ */
+ ExecMaterializeSlot(rslot);
+
ExecClearTuple(slot);
if (BufferIsValid(delbuffer))
ReleaseBuffer(delbuffer);