Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 76ce39e

Browse files
committed
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.
1 parent 08ee64e commit 76ce39e

File tree

3 files changed

+36
-10
lines changed

3 files changed

+36
-10
lines changed

src/backend/executor/execMain.c

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
*
2727
*
2828
* IDENTIFICATION
29-
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.256 2005/10/15 02:49:16 momjian Exp $
29+
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.257 2005/11/14 17:42:54 tgl Exp $
3030
*
3131
*-------------------------------------------------------------------------
3232
*/
@@ -582,7 +582,8 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly)
582582
* initialize the executor "tuple" table. We need slots for all the plan
583583
* nodes, plus possibly output slots for the junkfilter(s). At this point
584584
* we aren't sure if we need junkfilters, so just add slots for them
585-
* unconditionally.
585+
* unconditionally. Also, if it's not a SELECT, set up a slot for use
586+
* for trigger output tuples.
586587
*/
587588
{
588589
int nSlots = ExecCountSlotsNode(plan);
@@ -591,7 +592,14 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly)
591592
nSlots += list_length(parseTree->resultRelations);
592593
else
593594
nSlots += 1;
595+
if (operation != CMD_SELECT)
596+
nSlots++;
597+
594598
estate->es_tupleTable = ExecCreateTupleTable(nSlots);
599+
600+
if (operation != CMD_SELECT)
601+
estate->es_trig_tuple_slot =
602+
ExecAllocTableSlot(estate->es_tupleTable);
595603
}
596604

597605
/* mark EvalPlanQual not active */
@@ -1399,12 +1407,19 @@ ExecInsert(TupleTableSlot *slot,
13991407
if (newtuple != tuple) /* modified by Trigger(s) */
14001408
{
14011409
/*
1402-
* Insert modified tuple into tuple table slot, replacing the
1403-
* original. We assume that it was allocated in per-tuple memory
1410+
* Put the modified tuple into a slot for convenience of routines
1411+
* below. We assume the tuple was allocated in per-tuple memory
14041412
* context, and therefore will go away by itself. The tuple table
14051413
* slot should not try to clear it.
14061414
*/
1407-
ExecStoreTuple(newtuple, slot, InvalidBuffer, false);
1415+
TupleTableSlot *newslot = estate->es_trig_tuple_slot;
1416+
1417+
if (newslot->tts_tupleDescriptor != slot->tts_tupleDescriptor)
1418+
ExecSetSlotDescriptor(newslot,
1419+
slot->tts_tupleDescriptor,
1420+
false);
1421+
ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
1422+
slot = newslot;
14081423
tuple = newtuple;
14091424
}
14101425
}
@@ -1600,12 +1615,19 @@ ExecUpdate(TupleTableSlot *slot,
16001615
if (newtuple != tuple) /* modified by Trigger(s) */
16011616
{
16021617
/*
1603-
* Insert modified tuple into tuple table slot, replacing the
1604-
* original. We assume that it was allocated in per-tuple memory
1618+
* Put the modified tuple into a slot for convenience of routines
1619+
* below. We assume the tuple was allocated in per-tuple memory
16051620
* context, and therefore will go away by itself. The tuple table
16061621
* slot should not try to clear it.
16071622
*/
1608-
ExecStoreTuple(newtuple, slot, InvalidBuffer, false);
1623+
TupleTableSlot *newslot = estate->es_trig_tuple_slot;
1624+
1625+
if (newslot->tts_tupleDescriptor != slot->tts_tupleDescriptor)
1626+
ExecSetSlotDescriptor(newslot,
1627+
slot->tts_tupleDescriptor,
1628+
false);
1629+
ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
1630+
slot = newslot;
16091631
tuple = newtuple;
16101632
}
16111633
}

src/backend/executor/execUtils.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.126 2005/10/15 02:49:16 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.127 2005/11/14 17:42:54 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -187,6 +187,8 @@ CreateExecutorState(void)
187187

188188
estate->es_junkFilter = NULL;
189189

190+
estate->es_trig_tuple_slot = NULL;
191+
190192
estate->es_into_relation_descriptor = NULL;
191193
estate->es_into_relation_use_wal = false;
192194

src/include/nodes/execnodes.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.139 2005/10/15 02:49:45 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.140 2005/11/14 17:42:55 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -304,6 +304,8 @@ typedef struct EState
304304
ResultRelInfo *es_result_relation_info; /* currently active array elt */
305305
JunkFilter *es_junkFilter; /* currently active junk filter */
306306

307+
TupleTableSlot *es_trig_tuple_slot; /* for trigger output tuples */
308+
307309
Relation es_into_relation_descriptor; /* for SELECT INTO */
308310
bool es_into_relation_use_wal;
309311

0 commit comments

Comments
 (0)