7
7
* Portions Copyright (c) 1994, Regents of the University of California
8
8
*
9
9
* 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 $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
@@ -49,7 +49,7 @@ static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
49
49
static void DeferredTriggerSaveEvent (ResultRelInfo * relinfo , int event ,
50
50
HeapTuple oldtup , HeapTuple newtup );
51
51
static void DeferredTriggerExecute (DeferredTriggerEvent event , int itemno ,
52
- Relation rel , FmgrInfo * finfo ,
52
+ Relation rel , TriggerDesc * trigdesc , FmgrInfo * finfo ,
53
53
MemoryContext per_tuple_context );
54
54
55
55
@@ -680,9 +680,12 @@ renametrig(Oid relid,
680
680
/*
681
681
* Build trigger data to attach to the given relcache entry.
682
682
*
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.
686
689
*/
687
690
void
688
691
RelationBuildTriggers (Relation relation )
@@ -695,9 +698,11 @@ RelationBuildTriggers(Relation relation)
695
698
ScanKeyData skey ;
696
699
SysScanDesc tgscan ;
697
700
HeapTuple htup ;
701
+ MemoryContext oldContext ;
702
+
703
+ Assert (ntrigs > 0 ); /* else I should not have been called */
698
704
699
- triggers = (Trigger * ) MemoryContextAlloc (CacheMemoryContext ,
700
- ntrigs * sizeof (Trigger ));
705
+ triggers = (Trigger * ) palloc (ntrigs * sizeof (Trigger ));
701
706
702
707
/*
703
708
* Note: since we scan the triggers using TriggerRelidNameIndex, we
@@ -726,9 +731,8 @@ RelationBuildTriggers(Relation relation)
726
731
build = & (triggers [found ]);
727
732
728
733
build -> 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 )));
732
736
build -> tgfoid = pg_trigger -> tgfoid ;
733
737
build -> tgtype = pg_trigger -> tgtype ;
734
738
build -> tgenabled = pg_trigger -> tgenabled ;
@@ -753,13 +757,10 @@ RelationBuildTriggers(Relation relation)
753
757
elog (ERROR , "RelationBuildTriggers: tgargs IS NULL for rel %s" ,
754
758
RelationGetRelationName (relation ));
755
759
p = (char * ) VARDATA (val );
756
- build -> tgargs = (char * * )
757
- MemoryContextAlloc (CacheMemoryContext ,
758
- build -> tgnargs * sizeof (char * ));
760
+ build -> tgargs = (char * * ) palloc (build -> tgnargs * sizeof (char * ));
759
761
for (i = 0 ; i < build -> tgnargs ; i ++ )
760
762
{
761
- build -> tgargs [i ] = MemoryContextStrdup (CacheMemoryContext ,
762
- p );
763
+ build -> tgargs [i ] = pstrdup (p );
763
764
p += strlen (p ) + 1 ;
764
765
}
765
766
}
@@ -778,18 +779,30 @@ RelationBuildTriggers(Relation relation)
778
779
RelationGetRelationName (relation ));
779
780
780
781
/* Build trigdesc */
781
- trigdesc = (TriggerDesc * ) MemoryContextAlloc (CacheMemoryContext ,
782
- sizeof (TriggerDesc ));
782
+ trigdesc = (TriggerDesc * ) palloc (sizeof (TriggerDesc ));
783
783
MemSet (trigdesc , 0 , sizeof (TriggerDesc ));
784
784
trigdesc -> triggers = triggers ;
785
785
trigdesc -> numtriggers = ntrigs ;
786
786
for (found = 0 ; found < ntrigs ; found ++ )
787
787
InsertTrigger (trigdesc , & (triggers [found ]), found );
788
788
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 );
790
796
}
791
797
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
+ */
793
806
static void
794
807
InsertTrigger (TriggerDesc * trigdesc , Trigger * trigger , int indx )
795
808
{
@@ -830,11 +843,7 @@ InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx)
830
843
{
831
844
tp = & (t [TRIGGER_EVENT_INSERT ]);
832
845
if (* 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 ));
838
847
(* tp )[n [TRIGGER_EVENT_INSERT ]] = indx ;
839
848
(n [TRIGGER_EVENT_INSERT ])++ ;
840
849
}
@@ -843,11 +852,7 @@ InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx)
843
852
{
844
853
tp = & (t [TRIGGER_EVENT_DELETE ]);
845
854
if (* 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 ));
851
856
(* tp )[n [TRIGGER_EVENT_DELETE ]] = indx ;
852
857
(n [TRIGGER_EVENT_DELETE ])++ ;
853
858
}
@@ -856,16 +861,113 @@ InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx)
856
861
{
857
862
tp = & (t [TRIGGER_EVENT_UPDATE ]);
858
863
if (* 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 ));
864
865
(* tp )[n [TRIGGER_EVENT_UPDATE ]] = indx ;
865
866
(n [TRIGGER_EVENT_UPDATE ])++ ;
866
867
}
867
868
}
868
869
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
+ */
869
971
void
870
972
FreeTriggerDesc (TriggerDesc * trigdesc )
871
973
{
@@ -909,6 +1011,10 @@ FreeTriggerDesc(TriggerDesc *trigdesc)
909
1011
pfree (trigdesc );
910
1012
}
911
1013
1014
+ /*
1015
+ * Compare two TriggerDesc structures for logical equality.
1016
+ */
1017
+ #ifdef NOT_USED
912
1018
bool
913
1019
equalTriggerDescs (TriggerDesc * trigdesc1 , TriggerDesc * trigdesc2 )
914
1020
{
@@ -966,6 +1072,7 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
966
1072
return false;
967
1073
return true;
968
1074
}
1075
+ #endif /* NOT_USED */
969
1076
970
1077
/*
971
1078
* Call a trigger function.
@@ -1455,17 +1562,17 @@ deferredTriggerAddEvent(DeferredTriggerEvent event)
1455
1562
* event: event currently being fired.
1456
1563
* itemno: item within event currently being fired.
1457
1564
* 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).
1459
1567
* per_tuple_context: memory context to call trigger function in.
1460
1568
* ----------
1461
1569
*/
1462
1570
static void
1463
1571
DeferredTriggerExecute (DeferredTriggerEvent event , int itemno ,
1464
- Relation rel , FmgrInfo * finfo ,
1572
+ Relation rel , TriggerDesc * trigdesc , FmgrInfo * finfo ,
1465
1573
MemoryContext per_tuple_context )
1466
1574
{
1467
1575
Oid tgoid = event -> dte_item [itemno ].dti_tgoid ;
1468
- TriggerDesc * trigdesc = rel -> trigdesc ;
1469
1576
TriggerData LocTriggerData ;
1470
1577
HeapTupleData oldtuple ;
1471
1578
HeapTupleData newtuple ;
@@ -1530,7 +1637,7 @@ DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
1530
1637
}
1531
1638
1532
1639
/*
1533
- * Call the trigger and throw away an eventually returned updated
1640
+ * Call the trigger and throw away any eventually returned updated
1534
1641
* tuple.
1535
1642
*/
1536
1643
rettuple = ExecCallTriggerFunc (& LocTriggerData ,
@@ -1569,6 +1676,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
1569
1676
prev_event = NULL ;
1570
1677
MemoryContext per_tuple_context ;
1571
1678
Relation rel = NULL ;
1679
+ TriggerDesc * trigdesc = NULL ;
1572
1680
FmgrInfo * finfo = NULL ;
1573
1681
1574
1682
/*
@@ -1637,6 +1745,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
1637
1745
{
1638
1746
if (rel )
1639
1747
heap_close (rel , NoLock );
1748
+ FreeTriggerDesc (trigdesc );
1640
1749
if (finfo )
1641
1750
pfree (finfo );
1642
1751
@@ -1647,16 +1756,25 @@ deferredTriggerInvokeEvents(bool immediate_only)
1647
1756
rel = heap_open (event -> dte_relid , NoLock );
1648
1757
1649
1758
/*
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.
1652
1770
*/
1653
1771
finfo = (FmgrInfo * )
1654
- palloc (rel -> trigdesc -> numtriggers * sizeof (FmgrInfo ));
1772
+ palloc (trigdesc -> numtriggers * sizeof (FmgrInfo ));
1655
1773
MemSet (finfo , 0 ,
1656
- rel -> trigdesc -> numtriggers * sizeof (FmgrInfo ));
1774
+ trigdesc -> numtriggers * sizeof (FmgrInfo ));
1657
1775
}
1658
1776
1659
- DeferredTriggerExecute (event , i , rel , finfo ,
1777
+ DeferredTriggerExecute (event , i , rel , trigdesc , finfo ,
1660
1778
per_tuple_context );
1661
1779
1662
1780
event -> dte_item [i ].dti_state |= TRIGGER_DEFERRED_DONE ;
@@ -1708,6 +1826,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
1708
1826
/* Release working resources */
1709
1827
if (rel )
1710
1828
heap_close (rel , NoLock );
1829
+ FreeTriggerDesc (trigdesc );
1711
1830
if (finfo )
1712
1831
pfree (finfo );
1713
1832
MemoryContextDelete (per_tuple_context );
0 commit comments