@@ -1909,12 +1909,13 @@ ExecASInsertTriggers(EState *estate, ResultRelInfo *relinfo)
19091909 false,NULL ,NULL ,NIL ,NULL );
19101910}
19111911
1912- HeapTuple
1912+ TupleTableSlot *
19131913ExecBRInsertTriggers (EState * estate ,ResultRelInfo * relinfo ,
1914- HeapTuple trigtuple )
1914+ TupleTableSlot * slot )
19151915{
19161916TriggerDesc * trigdesc = relinfo -> ri_TrigDesc ;
1917- HeapTuple newtuple = trigtuple ;
1917+ HeapTuple slottuple = ExecMaterializeSlot (slot );
1918+ HeapTuple newtuple = slottuple ;
19181919HeapTuple oldtuple ;
19191920TriggerData LocTriggerData ;
19201921int i ;
@@ -1947,12 +1948,29 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
19471948relinfo -> ri_TrigFunctions ,
19481949relinfo -> ri_TrigInstrument ,
19491950GetPerTupleMemoryContext (estate ));
1950- if (oldtuple != newtuple && oldtuple != trigtuple )
1951+ if (oldtuple != newtuple && oldtuple != slottuple )
19511952heap_freetuple (oldtuple );
19521953if (newtuple == NULL )
1953- break ;
1954+ return NULL ;/* "do nothing" */
1955+ }
1956+
1957+ if (newtuple != slottuple )
1958+ {
1959+ /*
1960+ * Return the modified tuple using the es_trig_tuple_slot. We assume
1961+ * the tuple was allocated in per-tuple memory context, and therefore
1962+ * will go away by itself. The tuple table slot should not try to
1963+ * clear it.
1964+ */
1965+ TupleTableSlot * newslot = estate -> es_trig_tuple_slot ;
1966+ TupleDesc tupdesc = RelationGetDescr (relinfo -> ri_RelationDesc );
1967+
1968+ if (newslot -> tts_tupleDescriptor != tupdesc )
1969+ ExecSetSlotDescriptor (newslot ,tupdesc );
1970+ ExecStoreTuple (newtuple ,newslot ,InvalidBuffer , false);
1971+ slot = newslot ;
19541972}
1955- return newtuple ;
1973+ return slot ;
19561974}
19571975
19581976void
@@ -1966,12 +1984,13 @@ ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo,
19661984 true,NULL ,trigtuple ,recheckIndexes ,NULL );
19671985}
19681986
1969- HeapTuple
1987+ TupleTableSlot *
19701988ExecIRInsertTriggers (EState * estate ,ResultRelInfo * relinfo ,
1971- HeapTuple trigtuple )
1989+ TupleTableSlot * slot )
19721990{
19731991TriggerDesc * trigdesc = relinfo -> ri_TrigDesc ;
1974- HeapTuple newtuple = trigtuple ;
1992+ HeapTuple slottuple = ExecMaterializeSlot (slot );
1993+ HeapTuple newtuple = slottuple ;
19751994HeapTuple oldtuple ;
19761995TriggerData LocTriggerData ;
19771996int i ;
@@ -2004,12 +2023,29 @@ ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
20042023relinfo -> ri_TrigFunctions ,
20052024relinfo -> ri_TrigInstrument ,
20062025GetPerTupleMemoryContext (estate ));
2007- if (oldtuple != newtuple && oldtuple != trigtuple )
2026+ if (oldtuple != newtuple && oldtuple != slottuple )
20082027heap_freetuple (oldtuple );
20092028if (newtuple == NULL )
2010- break ;
2029+ return NULL ;/* "do nothing" */
2030+ }
2031+
2032+ if (newtuple != slottuple )
2033+ {
2034+ /*
2035+ * Return the modified tuple using the es_trig_tuple_slot. We assume
2036+ * the tuple was allocated in per-tuple memory context, and therefore
2037+ * will go away by itself. The tuple table slot should not try to
2038+ * clear it.
2039+ */
2040+ TupleTableSlot * newslot = estate -> es_trig_tuple_slot ;
2041+ TupleDesc tupdesc = RelationGetDescr (relinfo -> ri_RelationDesc );
2042+
2043+ if (newslot -> tts_tupleDescriptor != tupdesc )
2044+ ExecSetSlotDescriptor (newslot ,tupdesc );
2045+ ExecStoreTuple (newtuple ,newslot ,InvalidBuffer , false);
2046+ slot = newslot ;
20112047}
2012- return newtuple ;
2048+ return slot ;
20132049}
20142050
20152051void
@@ -2257,32 +2293,44 @@ ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
22572293GetModifiedColumns (relinfo ,estate ));
22582294}
22592295
2260- HeapTuple
2296+ TupleTableSlot *
22612297ExecBRUpdateTriggers (EState * estate ,EPQState * epqstate ,
22622298ResultRelInfo * relinfo ,
2263- ItemPointer tupleid ,HeapTuple newtuple )
2299+ ItemPointer tupleid ,TupleTableSlot * slot )
22642300{
22652301TriggerDesc * trigdesc = relinfo -> ri_TrigDesc ;
2302+ HeapTuple slottuple = ExecMaterializeSlot (slot );
2303+ HeapTuple newtuple = slottuple ;
22662304TriggerData LocTriggerData ;
22672305HeapTuple trigtuple ;
22682306HeapTuple oldtuple ;
2269- HeapTuple intuple = newtuple ;
22702307TupleTableSlot * newSlot ;
22712308int i ;
22722309Bitmapset * modifiedCols ;
22732310
2311+ /* get a copy of the on-disk tuple we are planning to update */
22742312trigtuple = GetTupleForTrigger (estate ,epqstate ,relinfo ,tupleid ,
22752313& newSlot );
22762314if (trigtuple == NULL )
2277- return NULL ;
2315+ return NULL ;/* cancel the update action */
22782316
22792317/*
2280- * In READ COMMITTED isolation level it's possible thatnewtuple was
2318+ * In READ COMMITTED isolation level it's possible thattarget tuple was
22812319 * changed due to concurrent update. In that case we have a raw subplan
2282- * output tuple and need to run it through the junk filter.
2320+ * output tuple in newSlot, and need to run it through the junk filter to
2321+ * produce an insertable tuple.
2322+ *
2323+ * Caution: more than likely, the passed-in slot is the same as the
2324+ * junkfilter's output slot, so we are clobbering the original value of
2325+ * slottuple by doing the filtering. This is OK since neither we nor our
2326+ * caller have any more interest in the prior contents of that slot.
22832327 */
22842328if (newSlot != NULL )
2285- intuple = newtuple = ExecRemoveJunk (relinfo -> ri_junkFilter ,newSlot );
2329+ {
2330+ slot = ExecFilterJunk (relinfo -> ri_junkFilter ,newSlot );
2331+ slottuple = ExecMaterializeSlot (slot );
2332+ newtuple = slottuple ;
2333+ }
22862334
22872335modifiedCols = GetModifiedColumns (relinfo ,estate );
22882336
@@ -2314,13 +2362,33 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
23142362relinfo -> ri_TrigFunctions ,
23152363relinfo -> ri_TrigInstrument ,
23162364GetPerTupleMemoryContext (estate ));
2317- if (oldtuple != newtuple && oldtuple != intuple )
2365+ if (oldtuple != newtuple && oldtuple != slottuple )
23182366heap_freetuple (oldtuple );
23192367if (newtuple == NULL )
2320- break ;
2368+ {
2369+ heap_freetuple (trigtuple );
2370+ return NULL ;/* "do nothing" */
2371+ }
23212372}
23222373heap_freetuple (trigtuple );
2323- return newtuple ;
2374+
2375+ if (newtuple != slottuple )
2376+ {
2377+ /*
2378+ * Return the modified tuple using the es_trig_tuple_slot. We assume
2379+ * the tuple was allocated in per-tuple memory context, and therefore
2380+ * will go away by itself. The tuple table slot should not try to
2381+ * clear it.
2382+ */
2383+ TupleTableSlot * newslot = estate -> es_trig_tuple_slot ;
2384+ TupleDesc tupdesc = RelationGetDescr (relinfo -> ri_RelationDesc );
2385+
2386+ if (newslot -> tts_tupleDescriptor != tupdesc )
2387+ ExecSetSlotDescriptor (newslot ,tupdesc );
2388+ ExecStoreTuple (newtuple ,newslot ,InvalidBuffer , false);
2389+ slot = newslot ;
2390+ }
2391+ return slot ;
23242392}
23252393
23262394void
@@ -2342,14 +2410,15 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
23422410}
23432411}
23442412
2345- HeapTuple
2413+ TupleTableSlot *
23462414ExecIRUpdateTriggers (EState * estate ,ResultRelInfo * relinfo ,
2347- HeapTuple oldtuple , HeapTuple newtuple )
2415+ HeapTuple trigtuple , TupleTableSlot * slot )
23482416{
23492417TriggerDesc * trigdesc = relinfo -> ri_TrigDesc ;
2418+ HeapTuple slottuple = ExecMaterializeSlot (slot );
2419+ HeapTuple newtuple = slottuple ;
23502420TriggerData LocTriggerData ;
2351- HeapTuple intuple = newtuple ;
2352- HeapTuple rettuple ;
2421+ HeapTuple oldtuple ;
23532422int i ;
23542423
23552424LocTriggerData .type = T_TriggerData ;
@@ -2367,26 +2436,42 @@ ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
23672436TRIGGER_TYPE_UPDATE ))
23682437continue ;
23692438if (!TriggerEnabled (estate ,relinfo ,trigger ,LocTriggerData .tg_event ,
2370- NULL ,oldtuple ,newtuple ))
2439+ NULL ,trigtuple ,newtuple ))
23712440continue ;
23722441
2373- LocTriggerData .tg_trigtuple = oldtuple ;
2374- LocTriggerData .tg_newtuple = newtuple ;
2442+ LocTriggerData .tg_trigtuple = trigtuple ;
2443+ LocTriggerData .tg_newtuple = oldtuple = newtuple ;
23752444LocTriggerData .tg_trigtuplebuf = InvalidBuffer ;
23762445LocTriggerData .tg_newtuplebuf = InvalidBuffer ;
23772446LocTriggerData .tg_trigger = trigger ;
2378- rettuple = ExecCallTriggerFunc (& LocTriggerData ,
2447+ newtuple = ExecCallTriggerFunc (& LocTriggerData ,
23792448i ,
23802449relinfo -> ri_TrigFunctions ,
23812450relinfo -> ri_TrigInstrument ,
23822451GetPerTupleMemoryContext (estate ));
2383- if (newtuple != rettuple && newtuple != intuple )
2384- heap_freetuple (newtuple );
2385- newtuple = rettuple ;
2452+ if (oldtuple != newtuple && oldtuple != slottuple )
2453+ heap_freetuple (oldtuple );
23862454if (newtuple == NULL )
2387- break ;
2455+ return NULL ;/* "do nothing" */
2456+ }
2457+
2458+ if (newtuple != slottuple )
2459+ {
2460+ /*
2461+ * Return the modified tuple using the es_trig_tuple_slot. We assume
2462+ * the tuple was allocated in per-tuple memory context, and therefore
2463+ * will go away by itself. The tuple table slot should not try to
2464+ * clear it.
2465+ */
2466+ TupleTableSlot * newslot = estate -> es_trig_tuple_slot ;
2467+ TupleDesc tupdesc = RelationGetDescr (relinfo -> ri_RelationDesc );
2468+
2469+ if (newslot -> tts_tupleDescriptor != tupdesc )
2470+ ExecSetSlotDescriptor (newslot ,tupdesc );
2471+ ExecStoreTuple (newtuple ,newslot ,InvalidBuffer , false);
2472+ slot = newslot ;
23882473}
2389- return newtuple ;
2474+ return slot ;
23902475}
23912476
23922477void