]> granicus.if.org Git - postgresql/commitdiff
Prevent ExecInsert() and ExecUpdate() from scribbling on the result tuple
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 14 Nov 2005 17:43:13 +0000 (17:43 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 14 Nov 2005 17:43:13 +0000 (17:43 +0000)
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.

src/backend/executor/execMain.c
src/backend/executor/execUtils.c
src/include/nodes/execnodes.h

index 2a96a161c812fd6587b3178cc90d83be90ea47c8..48efdeb59e5240c1f9d18fdae3633be448a65594 100644 (file)
@@ -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;
                }
        }
index 05bfc08dc7da15752d21970b51f870ea1130edbd..cab0e6179fa4dcda04c8a7529ac4cddcef980351 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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.126.2.1 2005/11/14 17:43:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -187,6 +187,8 @@ CreateExecutorState(void)
 
        estate->es_junkFilter = NULL;
 
+       estate->es_trig_tuple_slot = NULL;
+
        estate->es_into_relation_descriptor = NULL;
        estate->es_into_relation_use_wal = false;
 
index 8b06e2897d905f91e45bfae3fb32a4914f244998..0c96e7545f9b584f016504a28c297feb7164f3ed 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * 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.139.2.1 2005/11/14 17:43:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -341,6 +341,12 @@ typedef struct EState
        bool       *es_evTupleNull; /* local array of EPQ status */
        HeapTuple  *es_evTuple;         /* shared array of EPQ substitute tuples */
        bool            es_useEvalPlan; /* evaluating EPQ tuples? */
+
+       /*
+        * this field added at end of struct to avoid post-release ABI breakage
+        * in 8.1 series.  It'll be in a more logical place in 8.2.
+        */
+       TupleTableSlot *es_trig_tuple_slot;                     /* for trigger output tuples */
 } EState;