]> 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:42:55 +0000 (17:42 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 14 Nov 2005 17:42:55 +0000 (17:42 +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..c379802cafd8f43093758be210681e38dcb30b49 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.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
         * 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..d9bcd1cf6fee824efdfe5dd757af399ae9ba4eb8 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.127 2005/11/14 17:42:54 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..c638c28a02b346b3223c64c23261b6669319d4ed 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.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 */
        JunkFilter *es_junkFilter;      /* currently active junk filter */
 
+       TupleTableSlot *es_trig_tuple_slot;                     /* for trigger output tuples */
+
        Relation        es_into_relation_descriptor;    /* for SELECT INTO */
        bool            es_into_relation_use_wal;