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.134 2002/10/03 21:06:23 tgl Exp $
10+ * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.135 2002/10/14 16:51:29 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -49,7 +49,7 @@ static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
4949static void DeferredTriggerSaveEvent (ResultRelInfo * relinfo ,int event ,
5050HeapTuple oldtup ,HeapTuple newtup );
5151static void DeferredTriggerExecute (DeferredTriggerEvent event ,int itemno ,
52- Relation rel ,FmgrInfo * finfo ,
52+ Relation rel ,TriggerDesc * trigdesc , FmgrInfo * finfo ,
5353MemoryContext per_tuple_context );
5454
5555
@@ -680,9 +680,12 @@ renametrig(Oid relid,
680680/*
681681 * Build trigger data to attach to the given relcache entry.
682682 *
683- * Note that trigger data must be allocated in CacheMemoryContext
684- * to ensure it survives as long as the relcache entry. But we
685- * are probably running in a less long-lived working context.
683+ * Note that trigger data attached to a relcache entry must be stored in
684+ * CacheMemoryContext to ensure it survives as long as the relcache entry.
685+ * But we should be running in a less long-lived working context. To avoid
686+ * leaking cache memory if this routine fails partway through, we build a
687+ * temporary TriggerDesc in working memory and then copy the completed
688+ * structure into cache memory.
686689 */
687690void
688691RelationBuildTriggers (Relation relation )
@@ -695,9 +698,11 @@ RelationBuildTriggers(Relation relation)
695698ScanKeyData skey ;
696699SysScanDesc tgscan ;
697700HeapTuple htup ;
701+ MemoryContext oldContext ;
702+
703+ Assert (ntrigs > 0 );/* else I should not have been called */
698704
699- triggers = (Trigger * )MemoryContextAlloc (CacheMemoryContext ,
700- ntrigs * sizeof (Trigger ));
705+ triggers = (Trigger * )palloc (ntrigs * sizeof (Trigger ));
701706
702707/*
703708 * Note: since we scan the triggers using TriggerRelidNameIndex, we
@@ -726,9 +731,8 @@ RelationBuildTriggers(Relation relation)
726731build = & (triggers [found ]);
727732
728733build -> tgoid = HeapTupleGetOid (htup );
729- build -> tgname = MemoryContextStrdup (CacheMemoryContext ,
730- DatumGetCString (DirectFunctionCall1 (nameout ,
731- NameGetDatum (& pg_trigger -> tgname ))));
734+ build -> tgname = DatumGetCString (DirectFunctionCall1 (nameout ,
735+ NameGetDatum (& pg_trigger -> tgname )));
732736build -> tgfoid = pg_trigger -> tgfoid ;
733737build -> tgtype = pg_trigger -> tgtype ;
734738build -> tgenabled = pg_trigger -> tgenabled ;
@@ -753,13 +757,10 @@ RelationBuildTriggers(Relation relation)
753757elog (ERROR ,"RelationBuildTriggers: tgargs IS NULL for rel %s" ,
754758RelationGetRelationName (relation ));
755759p = (char * )VARDATA (val );
756- build -> tgargs = (char * * )
757- MemoryContextAlloc (CacheMemoryContext ,
758- build -> tgnargs * sizeof (char * ));
760+ build -> tgargs = (char * * )palloc (build -> tgnargs * sizeof (char * ));
759761for (i = 0 ;i < build -> tgnargs ;i ++ )
760762{
761- build -> tgargs [i ]= MemoryContextStrdup (CacheMemoryContext ,
762- p );
763+ build -> tgargs [i ]= pstrdup (p );
763764p += strlen (p )+ 1 ;
764765}
765766}
@@ -778,18 +779,30 @@ RelationBuildTriggers(Relation relation)
778779RelationGetRelationName (relation ));
779780
780781/* Build trigdesc */
781- trigdesc = (TriggerDesc * )MemoryContextAlloc (CacheMemoryContext ,
782- sizeof (TriggerDesc ));
782+ trigdesc = (TriggerDesc * )palloc (sizeof (TriggerDesc ));
783783MemSet (trigdesc ,0 ,sizeof (TriggerDesc ));
784784trigdesc -> triggers = triggers ;
785785trigdesc -> numtriggers = ntrigs ;
786786for (found = 0 ;found < ntrigs ;found ++ )
787787InsertTrigger (trigdesc ,& (triggers [found ]),found );
788788
789- relation -> trigdesc = trigdesc ;
789+ /* Copy completed trigdesc into cache storage */
790+ oldContext = MemoryContextSwitchTo (CacheMemoryContext );
791+ relation -> trigdesc = CopyTriggerDesc (trigdesc );
792+ MemoryContextSwitchTo (oldContext );
793+
794+ /* Release working memory */
795+ FreeTriggerDesc (trigdesc );
790796}
791797
792- /* Insert the given trigger into the appropriate index list(s) for it */
798+ /*
799+ * Insert the given trigger into the appropriate index list(s) for it
800+ *
801+ * To simplify storage management, we allocate each index list at the max
802+ * possible size (trigdesc->numtriggers) if it's used at all. This does
803+ * not waste space permanently since we're only building a temporary
804+ * trigdesc at this point.
805+ */
793806static void
794807InsertTrigger (TriggerDesc * trigdesc ,Trigger * trigger ,int indx )
795808{
@@ -830,11 +843,7 @@ InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx)
830843{
831844tp = & (t [TRIGGER_EVENT_INSERT ]);
832845if (* tp == NULL )
833- * tp = (int * )MemoryContextAlloc (CacheMemoryContext ,
834- sizeof (int ));
835- else
836- * tp = (int * )repalloc (* tp , (n [TRIGGER_EVENT_INSERT ]+ 1 )*
837- sizeof (int ));
846+ * tp = (int * )palloc (trigdesc -> numtriggers * sizeof (int ));
838847(* tp )[n [TRIGGER_EVENT_INSERT ]]= indx ;
839848(n [TRIGGER_EVENT_INSERT ])++ ;
840849}
@@ -843,11 +852,7 @@ InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx)
843852{
844853tp = & (t [TRIGGER_EVENT_DELETE ]);
845854if (* tp == NULL )
846- * tp = (int * )MemoryContextAlloc (CacheMemoryContext ,
847- sizeof (int ));
848- else
849- * tp = (int * )repalloc (* tp , (n [TRIGGER_EVENT_DELETE ]+ 1 )*
850- sizeof (int ));
855+ * tp = (int * )palloc (trigdesc -> numtriggers * sizeof (int ));
851856(* tp )[n [TRIGGER_EVENT_DELETE ]]= indx ;
852857(n [TRIGGER_EVENT_DELETE ])++ ;
853858}
@@ -856,16 +861,113 @@ InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx)
856861{
857862tp = & (t [TRIGGER_EVENT_UPDATE ]);
858863if (* tp == NULL )
859- * tp = (int * )MemoryContextAlloc (CacheMemoryContext ,
860- sizeof (int ));
861- else
862- * tp = (int * )repalloc (* tp , (n [TRIGGER_EVENT_UPDATE ]+ 1 )*
863- sizeof (int ));
864+ * tp = (int * )palloc (trigdesc -> numtriggers * sizeof (int ));
864865(* tp )[n [TRIGGER_EVENT_UPDATE ]]= indx ;
865866(n [TRIGGER_EVENT_UPDATE ])++ ;
866867}
867868}
868869
870+ /*
871+ * Copy a TriggerDesc data structure.
872+ *
873+ * The copy is allocated in the current memory context.
874+ */
875+ TriggerDesc *
876+ CopyTriggerDesc (TriggerDesc * trigdesc )
877+ {
878+ TriggerDesc * newdesc ;
879+ uint16 * n ;
880+ int * * t ,
881+ * tnew ;
882+ Trigger * trigger ;
883+ int i ;
884+
885+ if (trigdesc == NULL || trigdesc -> numtriggers <=0 )
886+ return NULL ;
887+
888+ newdesc = (TriggerDesc * )palloc (sizeof (TriggerDesc ));
889+ memcpy (newdesc ,trigdesc ,sizeof (TriggerDesc ));
890+
891+ trigger = (Trigger * )palloc (trigdesc -> numtriggers * sizeof (Trigger ));
892+ memcpy (trigger ,trigdesc -> triggers ,
893+ trigdesc -> numtriggers * sizeof (Trigger ));
894+ newdesc -> triggers = trigger ;
895+
896+ for (i = 0 ;i < trigdesc -> numtriggers ;i ++ )
897+ {
898+ trigger -> tgname = pstrdup (trigger -> tgname );
899+ if (trigger -> tgnargs > 0 )
900+ {
901+ char * * newargs ;
902+ int16 j ;
903+
904+ newargs = (char * * )palloc (trigger -> tgnargs * sizeof (char * ));
905+ for (j = 0 ;j < trigger -> tgnargs ;j ++ )
906+ newargs [j ]= pstrdup (trigger -> tgargs [j ]);
907+ trigger -> tgargs = newargs ;
908+ }
909+ trigger ++ ;
910+ }
911+
912+ n = newdesc -> n_before_statement ;
913+ t = newdesc -> tg_before_statement ;
914+ for (i = 0 ;i < TRIGGER_NUM_EVENT_CLASSES ;i ++ )
915+ {
916+ if (n [i ]> 0 )
917+ {
918+ tnew = (int * )palloc (n [i ]* sizeof (int ));
919+ memcpy (tnew ,t [i ],n [i ]* sizeof (int ));
920+ t [i ]= tnew ;
921+ }
922+ else
923+ t [i ]= NULL ;
924+ }
925+ n = newdesc -> n_before_row ;
926+ t = newdesc -> tg_before_row ;
927+ for (i = 0 ;i < TRIGGER_NUM_EVENT_CLASSES ;i ++ )
928+ {
929+ if (n [i ]> 0 )
930+ {
931+ tnew = (int * )palloc (n [i ]* sizeof (int ));
932+ memcpy (tnew ,t [i ],n [i ]* sizeof (int ));
933+ t [i ]= tnew ;
934+ }
935+ else
936+ t [i ]= NULL ;
937+ }
938+ n = newdesc -> n_after_row ;
939+ t = newdesc -> tg_after_row ;
940+ for (i = 0 ;i < TRIGGER_NUM_EVENT_CLASSES ;i ++ )
941+ {
942+ if (n [i ]> 0 )
943+ {
944+ tnew = (int * )palloc (n [i ]* sizeof (int ));
945+ memcpy (tnew ,t [i ],n [i ]* sizeof (int ));
946+ t [i ]= tnew ;
947+ }
948+ else
949+ t [i ]= NULL ;
950+ }
951+ n = newdesc -> n_after_statement ;
952+ t = newdesc -> tg_after_statement ;
953+ for (i = 0 ;i < TRIGGER_NUM_EVENT_CLASSES ;i ++ )
954+ {
955+ if (n [i ]> 0 )
956+ {
957+ tnew = (int * )palloc (n [i ]* sizeof (int ));
958+ memcpy (tnew ,t [i ],n [i ]* sizeof (int ));
959+ t [i ]= tnew ;
960+ }
961+ else
962+ t [i ]= NULL ;
963+ }
964+
965+ return newdesc ;
966+ }
967+
968+ /*
969+ * Free a TriggerDesc data structure.
970+ */
869971void
870972FreeTriggerDesc (TriggerDesc * trigdesc )
871973{
@@ -909,6 +1011,10 @@ FreeTriggerDesc(TriggerDesc *trigdesc)
9091011pfree (trigdesc );
9101012}
9111013
1014+ /*
1015+ * Compare two TriggerDesc structures for logical equality.
1016+ */
1017+ #ifdef NOT_USED
9121018bool
9131019equalTriggerDescs (TriggerDesc * trigdesc1 ,TriggerDesc * trigdesc2 )
9141020{
@@ -966,6 +1072,7 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
9661072return false;
9671073return true;
9681074}
1075+ #endif /* NOT_USED */
9691076
9701077/*
9711078 * Call a trigger function.
@@ -1455,17 +1562,17 @@ deferredTriggerAddEvent(DeferredTriggerEvent event)
14551562 *event: event currently being fired.
14561563 *itemno: item within event currently being fired.
14571564 *rel: open relation for event.
1458- *finfo: array of fmgr lookup cache entries (one per trigger of relation).
1565+ *trigdesc: working copy of rel's trigger info.
1566+ *finfo: array of fmgr lookup cache entries (one per trigger in trigdesc).
14591567 *per_tuple_context: memory context to call trigger function in.
14601568 * ----------
14611569 */
14621570static void
14631571DeferredTriggerExecute (DeferredTriggerEvent event ,int itemno ,
1464- Relation rel ,FmgrInfo * finfo ,
1572+ Relation rel ,TriggerDesc * trigdesc , FmgrInfo * finfo ,
14651573MemoryContext per_tuple_context )
14661574{
14671575Oid tgoid = event -> dte_item [itemno ].dti_tgoid ;
1468- TriggerDesc * trigdesc = rel -> trigdesc ;
14691576TriggerData LocTriggerData ;
14701577HeapTupleData oldtuple ;
14711578HeapTupleData newtuple ;
@@ -1530,7 +1637,7 @@ DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
15301637}
15311638
15321639/*
1533- * Call the trigger and throw awayan eventually returned updated
1640+ * Call the trigger and throw awayany eventually returned updated
15341641 * tuple.
15351642 */
15361643rettuple = ExecCallTriggerFunc (& LocTriggerData ,
@@ -1569,6 +1676,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
15691676prev_event = NULL ;
15701677MemoryContext per_tuple_context ;
15711678Relation rel = NULL ;
1679+ TriggerDesc * trigdesc = NULL ;
15721680FmgrInfo * finfo = NULL ;
15731681
15741682/*
@@ -1637,6 +1745,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
16371745{
16381746if (rel )
16391747heap_close (rel ,NoLock );
1748+ FreeTriggerDesc (trigdesc );
16401749if (finfo )
16411750pfree (finfo );
16421751
@@ -1647,16 +1756,25 @@ deferredTriggerInvokeEvents(bool immediate_only)
16471756rel = heap_open (event -> dte_relid ,NoLock );
16481757
16491758/*
1650- * Allocate space to cache fmgr lookup info for
1651- * triggers of this relation.
1759+ * Copy relation's trigger info so that we have a stable
1760+ * copy no matter what the called triggers do.
1761+ */
1762+ trigdesc = CopyTriggerDesc (rel -> trigdesc );
1763+
1764+ if (trigdesc == NULL )
1765+ elog (ERROR ,"deferredTriggerInvokeEvents: relation %u has no triggers" ,
1766+ event -> dte_relid );
1767+
1768+ /*
1769+ * Allocate space to cache fmgr lookup info for triggers.
16521770 */
16531771finfo = (FmgrInfo * )
1654- palloc (rel -> trigdesc -> numtriggers * sizeof (FmgrInfo ));
1772+ palloc (trigdesc -> numtriggers * sizeof (FmgrInfo ));
16551773MemSet (finfo ,0 ,
1656- rel -> trigdesc -> numtriggers * sizeof (FmgrInfo ));
1774+ trigdesc -> numtriggers * sizeof (FmgrInfo ));
16571775}
16581776
1659- DeferredTriggerExecute (event ,i ,rel ,finfo ,
1777+ DeferredTriggerExecute (event ,i ,rel ,trigdesc , finfo ,
16601778per_tuple_context );
16611779
16621780event -> dte_item [i ].dti_state |=TRIGGER_DEFERRED_DONE ;
@@ -1708,6 +1826,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
17081826/* Release working resources */
17091827if (rel )
17101828heap_close (rel ,NoLock );
1829+ FreeTriggerDesc (trigdesc );
17111830if (finfo )
17121831pfree (finfo );
17131832MemoryContextDelete (per_tuple_context );