@@ -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{
19161916 TriggerDesc * trigdesc = relinfo -> ri_TrigDesc ;
1917- HeapTuple newtuple = trigtuple ;
1917+ HeapTuple slottuple = ExecMaterializeSlot (slot );
1918+ HeapTuple newtuple = slottuple ;
19181919 HeapTuple oldtuple ;
19191920 TriggerData LocTriggerData ;
19201921 int i ;
@@ -1947,12 +1948,29 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
19471948 relinfo -> ri_TrigFunctions ,
19481949 relinfo -> ri_TrigInstrument ,
19491950 GetPerTupleMemoryContext (estate ));
1950- if (oldtuple != newtuple && oldtuple != trigtuple )
1951+ if (oldtuple != newtuple && oldtuple != slottuple )
19511952 heap_freetuple (oldtuple );
19521953 if (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{
19731991 TriggerDesc * trigdesc = relinfo -> ri_TrigDesc ;
1974- HeapTuple newtuple = trigtuple ;
1992+ HeapTuple slottuple = ExecMaterializeSlot (slot );
1993+ HeapTuple newtuple = slottuple ;
19751994 HeapTuple oldtuple ;
19761995 TriggerData LocTriggerData ;
19771996 int i ;
@@ -2004,12 +2023,29 @@ ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
20042023 relinfo -> ri_TrigFunctions ,
20052024 relinfo -> ri_TrigInstrument ,
20062025 GetPerTupleMemoryContext (estate ));
2007- if (oldtuple != newtuple && oldtuple != trigtuple )
2026+ if (oldtuple != newtuple && oldtuple != slottuple )
20082027 heap_freetuple (oldtuple );
20092028 if (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)
22572293 GetModifiedColumns (relinfo , estate ));
22582294}
22592295
2260- HeapTuple
2296+ TupleTableSlot *
22612297ExecBRUpdateTriggers (EState * estate , EPQState * epqstate ,
22622298 ResultRelInfo * relinfo ,
2263- ItemPointer tupleid , HeapTuple newtuple )
2299+ ItemPointer tupleid , TupleTableSlot * slot )
22642300{
22652301 TriggerDesc * trigdesc = relinfo -> ri_TrigDesc ;
2302+ HeapTuple slottuple = ExecMaterializeSlot (slot );
2303+ HeapTuple newtuple = slottuple ;
22662304 TriggerData LocTriggerData ;
22672305 HeapTuple trigtuple ;
22682306 HeapTuple oldtuple ;
2269- HeapTuple intuple = newtuple ;
22702307 TupleTableSlot * newSlot ;
22712308 int i ;
22722309 Bitmapset * modifiedCols ;
22732310
2311+ /* get a copy of the on-disk tuple we are planning to update */
22742312 trigtuple = GetTupleForTrigger (estate , epqstate , relinfo , tupleid ,
22752313 & newSlot );
22762314 if (trigtuple == NULL )
2277- return NULL ;
2315+ return NULL ; /* cancel the update action */
22782316
22792317 /*
2280- * In READ COMMITTED isolation level it's possible that newtuple was
2318+ * In READ COMMITTED isolation level it's possible that target 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 */
22842328 if (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
22872335 modifiedCols = GetModifiedColumns (relinfo , estate );
22882336
@@ -2314,13 +2362,33 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
23142362 relinfo -> ri_TrigFunctions ,
23152363 relinfo -> ri_TrigInstrument ,
23162364 GetPerTupleMemoryContext (estate ));
2317- if (oldtuple != newtuple && oldtuple != intuple )
2365+ if (oldtuple != newtuple && oldtuple != slottuple )
23182366 heap_freetuple (oldtuple );
23192367 if (newtuple == NULL )
2320- break ;
2368+ {
2369+ heap_freetuple (trigtuple );
2370+ return NULL ; /* "do nothing" */
2371+ }
23212372 }
23222373 heap_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{
23492417 TriggerDesc * trigdesc = relinfo -> ri_TrigDesc ;
2418+ HeapTuple slottuple = ExecMaterializeSlot (slot );
2419+ HeapTuple newtuple = slottuple ;
23502420 TriggerData LocTriggerData ;
2351- HeapTuple intuple = newtuple ;
2352- HeapTuple rettuple ;
2421+ HeapTuple oldtuple ;
23532422 int i ;
23542423
23552424 LocTriggerData .type = T_TriggerData ;
@@ -2367,26 +2436,42 @@ ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
23672436 TRIGGER_TYPE_UPDATE ))
23682437 continue ;
23692438 if (!TriggerEnabled (estate , relinfo , trigger , LocTriggerData .tg_event ,
2370- NULL , oldtuple , newtuple ))
2439+ NULL , trigtuple , newtuple ))
23712440 continue ;
23722441
2373- LocTriggerData .tg_trigtuple = oldtuple ;
2374- LocTriggerData .tg_newtuple = newtuple ;
2442+ LocTriggerData .tg_trigtuple = trigtuple ;
2443+ LocTriggerData .tg_newtuple = oldtuple = newtuple ;
23752444 LocTriggerData .tg_trigtuplebuf = InvalidBuffer ;
23762445 LocTriggerData .tg_newtuplebuf = InvalidBuffer ;
23772446 LocTriggerData .tg_trigger = trigger ;
2378- rettuple = ExecCallTriggerFunc (& LocTriggerData ,
2447+ newtuple = ExecCallTriggerFunc (& LocTriggerData ,
23792448 i ,
23802449 relinfo -> ri_TrigFunctions ,
23812450 relinfo -> ri_TrigInstrument ,
23822451 GetPerTupleMemoryContext (estate ));
2383- if (newtuple != rettuple && newtuple != intuple )
2384- heap_freetuple (newtuple );
2385- newtuple = rettuple ;
2452+ if (oldtuple != newtuple && oldtuple != slottuple )
2453+ heap_freetuple (oldtuple );
23862454 if (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
0 commit comments