77 * Portions Copyright (c) 1994, Regents of the University of California
88 *
99 * IDENTIFICATION
10- * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.82 2000/12/18 00:44:46 tgl Exp $
10+ * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.83 2001/01/22 00:50:07 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -36,7 +36,8 @@ static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger);
3636static HeapTuple GetTupleForTrigger (EState * estate ,ItemPointer tid ,
3737TupleTableSlot * * newSlot );
3838static HeapTuple ExecCallTriggerFunc (Trigger * trigger ,
39- TriggerData * trigdata );
39+ TriggerData * trigdata ,
40+ MemoryContext per_tuple_context );
4041static void DeferredTriggerSaveEvent (Relation rel ,int event ,
4142HeapTuple oldtup ,HeapTuple newtup );
4243
@@ -831,10 +832,13 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
831832}
832833
833834static HeapTuple
834- ExecCallTriggerFunc (Trigger * trigger ,TriggerData * trigdata )
835+ ExecCallTriggerFunc (Trigger * trigger ,
836+ TriggerData * trigdata ,
837+ MemoryContext per_tuple_context )
835838{
836839FunctionCallInfoData fcinfo ;
837840Datum result ;
841+ MemoryContext oldContext ;
838842
839843/*
840844 * Fmgr lookup info is cached in the Trigger structure,
@@ -843,6 +847,14 @@ ExecCallTriggerFunc(Trigger *trigger, TriggerData *trigdata)
843847if (trigger -> tgfunc .fn_oid == InvalidOid )
844848fmgr_info (trigger -> tgfoid ,& trigger -> tgfunc );
845849
850+ /*
851+ * Do the function evaluation in the per-tuple memory context,
852+ * so that leaked memory will be reclaimed once per tuple.
853+ * Note in particular that any new tuple created by the trigger function
854+ * will live till the end of the tuple cycle.
855+ */
856+ oldContext = MemoryContextSwitchTo (per_tuple_context );
857+
846858/*
847859 * Call the function, passing no arguments but setting a context.
848860 */
@@ -853,6 +865,8 @@ ExecCallTriggerFunc(Trigger *trigger, TriggerData *trigdata)
853865
854866result = FunctionCallInvoke (& fcinfo );
855867
868+ MemoryContextSwitchTo (oldContext );
869+
856870/*
857871 * Trigger protocol allows function to return a null pointer,
858872 * but NOT to set the isnull result flag.
@@ -865,7 +879,7 @@ ExecCallTriggerFunc(Trigger *trigger, TriggerData *trigdata)
865879}
866880
867881HeapTuple
868- ExecBRInsertTriggers (Relation rel ,HeapTuple trigtuple )
882+ ExecBRInsertTriggers (EState * estate , Relation rel ,HeapTuple trigtuple )
869883{
870884int ntrigs = rel -> trigdesc -> n_before_row [TRIGGER_EVENT_INSERT ];
871885Trigger * * trigger = rel -> trigdesc -> tg_before_row [TRIGGER_EVENT_INSERT ];
@@ -884,20 +898,20 @@ ExecBRInsertTriggers(Relation rel, HeapTuple trigtuple)
884898continue ;
885899LocTriggerData .tg_trigtuple = oldtuple = newtuple ;
886900LocTriggerData .tg_trigger = trigger [i ];
887- newtuple = ExecCallTriggerFunc (trigger [i ],& LocTriggerData );
901+ newtuple = ExecCallTriggerFunc (trigger [i ],& LocTriggerData ,
902+ GetPerTupleMemoryContext (estate ));
903+ if (oldtuple != newtuple && oldtuple != trigtuple )
904+ heap_freetuple (oldtuple );
888905if (newtuple == NULL )
889906break ;
890- else if (oldtuple != newtuple && oldtuple != trigtuple )
891- heap_freetuple (oldtuple );
892907}
893908return newtuple ;
894909}
895910
896911void
897- ExecARInsertTriggers (Relation rel ,HeapTuple trigtuple )
912+ ExecARInsertTriggers (EState * estate , Relation rel ,HeapTuple trigtuple )
898913{
899914DeferredTriggerSaveEvent (rel ,TRIGGER_EVENT_INSERT ,NULL ,trigtuple );
900- return ;
901915}
902916
903917bool
@@ -926,7 +940,8 @@ ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
926940continue ;
927941LocTriggerData .tg_trigtuple = trigtuple ;
928942LocTriggerData .tg_trigger = trigger [i ];
929- newtuple = ExecCallTriggerFunc (trigger [i ],& LocTriggerData );
943+ newtuple = ExecCallTriggerFunc (trigger [i ],& LocTriggerData ,
944+ GetPerTupleMemoryContext (estate ));
930945if (newtuple == NULL )
931946break ;
932947if (newtuple != trigtuple )
@@ -944,7 +959,7 @@ ExecARDeleteTriggers(EState *estate, ItemPointer tupleid)
944959HeapTuple trigtuple = GetTupleForTrigger (estate ,tupleid ,NULL );
945960
946961DeferredTriggerSaveEvent (rel ,TRIGGER_EVENT_DELETE ,trigtuple ,NULL );
947- return ;
962+ heap_freetuple ( trigtuple ) ;
948963}
949964
950965HeapTuple
@@ -981,11 +996,12 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
981996LocTriggerData .tg_trigtuple = trigtuple ;
982997LocTriggerData .tg_newtuple = oldtuple = newtuple ;
983998LocTriggerData .tg_trigger = trigger [i ];
984- newtuple = ExecCallTriggerFunc (trigger [i ],& LocTriggerData );
999+ newtuple = ExecCallTriggerFunc (trigger [i ],& LocTriggerData ,
1000+ GetPerTupleMemoryContext (estate ));
1001+ if (oldtuple != newtuple && oldtuple != intuple )
1002+ heap_freetuple (oldtuple );
9851003if (newtuple == NULL )
9861004break ;
987- else if (oldtuple != newtuple && oldtuple != intuple )
988- heap_freetuple (oldtuple );
9891005}
9901006heap_freetuple (trigtuple );
9911007return newtuple ;
@@ -998,7 +1014,7 @@ ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
9981014HeapTuple trigtuple = GetTupleForTrigger (estate ,tupleid ,NULL );
9991015
10001016DeferredTriggerSaveEvent (rel ,TRIGGER_EVENT_UPDATE ,trigtuple ,newtuple );
1001- return ;
1017+ heap_freetuple ( trigtuple ) ;
10021018}
10031019
10041020
@@ -1236,7 +1252,7 @@ deferredTriggerGetPreviousEvent(Oid relid, ItemPointer ctid)
12361252}
12371253
12381254elog (ERROR ,
1239- "deferredTriggerGetPreviousEvent() : event for tuple %s not found" ,
1255+ "deferredTriggerGetPreviousEvent: event for tuple %s not found" ,
12401256DatumGetCString (DirectFunctionCall1 (tidout ,PointerGetDatum (ctid ))));
12411257return NULL ;
12421258}
@@ -1250,7 +1266,8 @@ deferredTriggerGetPreviousEvent(Oid relid, ItemPointer ctid)
12501266 * ----------
12511267 */
12521268static void
1253- deferredTriggerExecute (DeferredTriggerEvent event ,int itemno )
1269+ deferredTriggerExecute (DeferredTriggerEvent event ,int itemno ,
1270+ MemoryContext per_tuple_context )
12541271{
12551272Relation rel ;
12561273TriggerData LocTriggerData ;
@@ -1271,15 +1288,15 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno)
12711288ItemPointerCopy (& (event -> dte_oldctid ),& (oldtuple .t_self ));
12721289heap_fetch (rel ,SnapshotAny ,& oldtuple ,& oldbuffer );
12731290if (!oldtuple .t_data )
1274- elog (ERROR ,"deferredTriggerExecute() : failed to fetch old tuple" );
1291+ elog (ERROR ,"deferredTriggerExecute: failed to fetch old tuple" );
12751292}
12761293
12771294if (ItemPointerIsValid (& (event -> dte_newctid )))
12781295{
12791296ItemPointerCopy (& (event -> dte_newctid ),& (newtuple .t_self ));
12801297heap_fetch (rel ,SnapshotAny ,& newtuple ,& newbuffer );
12811298if (!newtuple .t_data )
1282- elog (ERROR ,"deferredTriggerExecute() : failed to fetch new tuple" );
1299+ elog (ERROR ,"deferredTriggerExecute: failed to fetch new tuple" );
12831300}
12841301
12851302/* ----------
@@ -1320,7 +1337,9 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno)
13201337 * updated tuple.
13211338 * ----------
13221339 */
1323- rettuple = ExecCallTriggerFunc (LocTriggerData .tg_trigger ,& LocTriggerData );
1340+ rettuple = ExecCallTriggerFunc (LocTriggerData .tg_trigger ,
1341+ & LocTriggerData ,
1342+ per_tuple_context );
13241343if (rettuple != NULL && rettuple != & oldtuple && rettuple != & newtuple )
13251344heap_freetuple (rettuple );
13261345
@@ -1359,6 +1378,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
13591378int still_deferred_ones ;
13601379int eventno = -1 ;
13611380int i ;
1381+ MemoryContext per_tuple_context ;
13621382
13631383/* ----------
13641384 * For now we process all events - to speedup transaction blocks
@@ -1369,10 +1389,21 @@ deferredTriggerInvokeEvents(bool immediate_only)
13691389 * SET CONSTRAINTS ... command finishes and calls EndQuery.
13701390 * ----------
13711391 */
1392+
1393+ /* Make a per-tuple memory context for trigger function calls */
1394+ per_tuple_context =
1395+ AllocSetContextCreate (CurrentMemoryContext ,
1396+ "DeferredTriggerTupleContext" ,
1397+ 0 ,
1398+ ALLOCSET_DEFAULT_INITSIZE ,
1399+ ALLOCSET_DEFAULT_MAXSIZE );
1400+
13721401foreach (el ,deftrig_events )
13731402{
13741403eventno ++ ;
13751404
1405+ MemoryContextReset (per_tuple_context );
1406+
13761407/* ----------
13771408 * Get the event and check if it is completely done.
13781409 * ----------
@@ -1409,7 +1440,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
14091440 * So let's fire it...
14101441 * ----------
14111442 */
1412- deferredTriggerExecute (event ,i );
1443+ deferredTriggerExecute (event ,i , per_tuple_context );
14131444event -> dte_item [i ].dti_state |=TRIGGER_DEFERRED_DONE ;
14141445}
14151446
@@ -1421,6 +1452,8 @@ deferredTriggerInvokeEvents(bool immediate_only)
14211452if (!still_deferred_ones )
14221453event -> dte_event |=TRIGGER_DEFERRED_DONE ;
14231454}
1455+
1456+ MemoryContextDelete (per_tuple_context );
14241457}
14251458
14261459
@@ -1866,13 +1899,10 @@ DeferredTriggerSaveEvent(Relation rel, int event,
18661899 * Check if we're interested in this row at all
18671900 * ----------
18681901 */
1869- if (rel -> trigdesc -> n_after_row [TRIGGER_EVENT_INSERT ]== 0 &&
1870- rel -> trigdesc -> n_after_row [TRIGGER_EVENT_UPDATE ]== 0 &&
1871- rel -> trigdesc -> n_after_row [TRIGGER_EVENT_DELETE ]== 0 &&
1872- rel -> trigdesc -> n_before_row [TRIGGER_EVENT_INSERT ]== 0 &&
1873- rel -> trigdesc -> n_before_row [TRIGGER_EVENT_UPDATE ]== 0 &&
1874- rel -> trigdesc -> n_before_row [TRIGGER_EVENT_DELETE ]== 0 )
1902+ ntriggers = rel -> trigdesc -> n_after_row [event ];
1903+ if (ntriggers <=0 )
18751904return ;
1905+ triggers = rel -> trigdesc -> tg_after_row [event ];
18761906
18771907/* ----------
18781908 * Get the CTID's of OLD and NEW
@@ -1893,9 +1923,6 @@ DeferredTriggerSaveEvent(Relation rel, int event,
18931923 */
18941924oldcxt = MemoryContextSwitchTo (deftrig_cxt );
18951925
1896- ntriggers = rel -> trigdesc -> n_after_row [event ];
1897- triggers = rel -> trigdesc -> tg_after_row [event ];
1898-
18991926new_size = sizeof (DeferredTriggerEventData )+
19001927ntriggers * sizeof (DeferredTriggerEventItem );
19011928