mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-21 08:29:39 +08:00
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.
This commit is contained in:
parent
08ee64ebf5
commit
76ce39e386
@ -26,7 +26,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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.257 2005/11/14 17:42:54 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -582,7 +582,8 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly)
|
|||||||
* initialize the executor "tuple" table. We need slots for all the plan
|
* initialize the executor "tuple" table. We need slots for all the plan
|
||||||
* nodes, plus possibly output slots for the junkfilter(s). At this point
|
* 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
|
* 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);
|
int nSlots = ExecCountSlotsNode(plan);
|
||||||
@ -591,7 +592,14 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly)
|
|||||||
nSlots += list_length(parseTree->resultRelations);
|
nSlots += list_length(parseTree->resultRelations);
|
||||||
else
|
else
|
||||||
nSlots += 1;
|
nSlots += 1;
|
||||||
|
if (operation != CMD_SELECT)
|
||||||
|
nSlots++;
|
||||||
|
|
||||||
estate->es_tupleTable = ExecCreateTupleTable(nSlots);
|
estate->es_tupleTable = ExecCreateTupleTable(nSlots);
|
||||||
|
|
||||||
|
if (operation != CMD_SELECT)
|
||||||
|
estate->es_trig_tuple_slot =
|
||||||
|
ExecAllocTableSlot(estate->es_tupleTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mark EvalPlanQual not active */
|
/* mark EvalPlanQual not active */
|
||||||
@ -1399,12 +1407,19 @@ ExecInsert(TupleTableSlot *slot,
|
|||||||
if (newtuple != tuple) /* modified by Trigger(s) */
|
if (newtuple != tuple) /* modified by Trigger(s) */
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Insert modified tuple into tuple table slot, replacing the
|
* Put the modified tuple into a slot for convenience of routines
|
||||||
* original. We assume that it was allocated in per-tuple memory
|
* below. We assume the tuple was allocated in per-tuple memory
|
||||||
* context, and therefore will go away by itself. The tuple table
|
* context, and therefore will go away by itself. The tuple table
|
||||||
* slot should not try to clear it.
|
* 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;
|
tuple = newtuple;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1600,12 +1615,19 @@ ExecUpdate(TupleTableSlot *slot,
|
|||||||
if (newtuple != tuple) /* modified by Trigger(s) */
|
if (newtuple != tuple) /* modified by Trigger(s) */
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Insert modified tuple into tuple table slot, replacing the
|
* Put the modified tuple into a slot for convenience of routines
|
||||||
* original. We assume that it was allocated in per-tuple memory
|
* below. We assume the tuple was allocated in per-tuple memory
|
||||||
* context, and therefore will go away by itself. The tuple table
|
* context, and therefore will go away by itself. The tuple table
|
||||||
* slot should not try to clear it.
|
* 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;
|
tuple = newtuple;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.126 2005/10/15 02:49:16 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.127 2005/11/14 17:42:54 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -187,6 +187,8 @@ CreateExecutorState(void)
|
|||||||
|
|
||||||
estate->es_junkFilter = NULL;
|
estate->es_junkFilter = NULL;
|
||||||
|
|
||||||
|
estate->es_trig_tuple_slot = NULL;
|
||||||
|
|
||||||
estate->es_into_relation_descriptor = NULL;
|
estate->es_into_relation_descriptor = NULL;
|
||||||
estate->es_into_relation_use_wal = false;
|
estate->es_into_relation_use_wal = false;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.139 2005/10/15 02:49:45 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.140 2005/11/14 17:42:55 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -304,6 +304,8 @@ typedef struct EState
|
|||||||
ResultRelInfo *es_result_relation_info; /* currently active array elt */
|
ResultRelInfo *es_result_relation_info; /* currently active array elt */
|
||||||
JunkFilter *es_junkFilter; /* currently active junk filter */
|
JunkFilter *es_junkFilter; /* currently active junk filter */
|
||||||
|
|
||||||
|
TupleTableSlot *es_trig_tuple_slot; /* for trigger output tuples */
|
||||||
|
|
||||||
Relation es_into_relation_descriptor; /* for SELECT INTO */
|
Relation es_into_relation_descriptor; /* for SELECT INTO */
|
||||||
bool es_into_relation_use_wal;
|
bool es_into_relation_use_wal;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user