diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2005-11-14 17:43:13 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2005-11-14 17:43:13 +0000 |
commit | 431178ae678f61ee20f6fa90ee7eb2f3ead254fb (patch) | |
tree | a98a139f364ac0ca7656ff3bac0ee26f3630da01 /src/backend/executor/execMain.c | |
parent | f82df77c9d7e443796bf730f4277e730c514863c (diff) | |
download | postgresql-431178ae678f61ee20f6fa90ee7eb2f3ead254fb.tar.gz postgresql-431178ae678f61ee20f6fa90ee7eb2f3ead254fb.zip |
Prevent ExecInsert() and ExecUpdate() from scribbling on the result tuple
slot of the topmost plan node when a trigger returns a modified tuple.
These appear to be the only places where a plan node's caller did not
treat the result slot as read-only, which is an assumption that nodeUnique
makes as of 8.1. Fixes trigger-vs-DISTINCT bug reported by Frank van Vugt.
Diffstat (limited to 'src/backend/executor/execMain.c')
-rw-r--r-- | src/backend/executor/execMain.c | 38 |
1 files changed, 30 insertions, 8 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 2a96a161c81..48efdeb59e5 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -26,7 +26,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.256 2005/10/15 02:49:16 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.256.2.1 2005/11/14 17:43:12 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -582,7 +582,8 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly) * initialize the executor "tuple" table. We need slots for all the plan * nodes, plus possibly output slots for the junkfilter(s). At this point * we aren't sure if we need junkfilters, so just add slots for them - * unconditionally. + * unconditionally. Also, if it's not a SELECT, set up a slot for use + * for trigger output tuples. */ { int nSlots = ExecCountSlotsNode(plan); @@ -591,7 +592,14 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly) nSlots += list_length(parseTree->resultRelations); else nSlots += 1; + if (operation != CMD_SELECT) + nSlots++; + estate->es_tupleTable = ExecCreateTupleTable(nSlots); + + if (operation != CMD_SELECT) + estate->es_trig_tuple_slot = + ExecAllocTableSlot(estate->es_tupleTable); } /* mark EvalPlanQual not active */ @@ -1399,12 +1407,19 @@ ExecInsert(TupleTableSlot *slot, if (newtuple != tuple) /* modified by Trigger(s) */ { /* - * Insert modified tuple into tuple table slot, replacing the - * original. We assume that it was allocated in per-tuple memory + * Put the modified tuple into a slot for convenience of routines + * below. We assume the tuple was allocated in per-tuple memory * context, and therefore will go away by itself. The tuple table * slot should not try to clear it. */ - ExecStoreTuple(newtuple, slot, InvalidBuffer, false); + TupleTableSlot *newslot = estate->es_trig_tuple_slot; + + if (newslot->tts_tupleDescriptor != slot->tts_tupleDescriptor) + ExecSetSlotDescriptor(newslot, + slot->tts_tupleDescriptor, + false); + ExecStoreTuple(newtuple, newslot, InvalidBuffer, false); + slot = newslot; tuple = newtuple; } } @@ -1600,12 +1615,19 @@ ExecUpdate(TupleTableSlot *slot, if (newtuple != tuple) /* modified by Trigger(s) */ { /* - * Insert modified tuple into tuple table slot, replacing the - * original. We assume that it was allocated in per-tuple memory + * Put the modified tuple into a slot for convenience of routines + * below. We assume the tuple was allocated in per-tuple memory * context, and therefore will go away by itself. The tuple table * slot should not try to clear it. */ - ExecStoreTuple(newtuple, slot, InvalidBuffer, false); + TupleTableSlot *newslot = estate->es_trig_tuple_slot; + + if (newslot->tts_tupleDescriptor != slot->tts_tupleDescriptor) + ExecSetSlotDescriptor(newslot, + slot->tts_tupleDescriptor, + false); + ExecStoreTuple(newtuple, newslot, InvalidBuffer, false); + slot = newslot; tuple = newtuple; } } |