Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 8f2a289

Browse files
committed
Arrange to copy relcache's trigdesc structure at the start of any
query that uses it. This ensures that triggers will be applied consistently throughout a query even if someone commits changes to the relation's pg_class.reltriggers field meanwhile. Per crash report from Laurette Cisneros. While at it, simplify memory management in relcache.c, which no longer needs the old hack to try to keep trigger info in the same place over a relcache entry rebuild. (Should try to fix rd_att and rewrite-rule access similarly, someday.) And make RelationBuildTriggers simpler and more robust by making it build the trigdesc in working memory and then CopyTriggerDesc() into cache memory.
1 parent 8fc1f41 commit 8f2a289

File tree

5 files changed

+176
-66
lines changed

5 files changed

+176
-66
lines changed

src/backend/commands/copy.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.175 2002/09/20 16:56:02 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.176 2002/10/14 16:51:28 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -780,7 +780,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
780780
resultRelInfo = makeNode(ResultRelInfo);
781781
resultRelInfo->ri_RangeTableIndex = 1; /* dummy */
782782
resultRelInfo->ri_RelationDesc = rel;
783-
resultRelInfo->ri_TrigDesc = rel->trigdesc;
783+
resultRelInfo->ri_TrigDesc = CopyTriggerDesc(rel->trigdesc);
784784

785785
ExecOpenIndices(resultRelInfo);
786786

src/backend/commands/trigger.c

Lines changed: 162 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
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,
4949
static void DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
5050
HeapTuple oldtup, HeapTuple newtup);
5151
static void DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
52-
Relation rel, FmgrInfo *finfo,
52+
Relation rel, TriggerDesc *trigdesc, FmgrInfo *finfo,
5353
MemoryContext 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
*/
687690
void
688691
RelationBuildTriggers(Relation relation)
@@ -695,9 +698,11 @@ RelationBuildTriggers(Relation relation)
695698
ScanKeyData skey;
696699
SysScanDesc tgscan;
697700
HeapTuple 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)
726731
build = &(triggers[found]);
727732

728733
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)));
732736
build->tgfoid = pg_trigger->tgfoid;
733737
build->tgtype = pg_trigger->tgtype;
734738
build->tgenabled = pg_trigger->tgenabled;
@@ -753,13 +757,10 @@ RelationBuildTriggers(Relation relation)
753757
elog(ERROR, "RelationBuildTriggers: tgargs IS NULL for rel %s",
754758
RelationGetRelationName(relation));
755759
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 *));
759761
for (i = 0; i < build->tgnargs; i++)
760762
{
761-
build->tgargs[i] = MemoryContextStrdup(CacheMemoryContext,
762-
p);
763+
build->tgargs[i] = pstrdup(p);
763764
p += strlen(p) + 1;
764765
}
765766
}
@@ -778,18 +779,30 @@ RelationBuildTriggers(Relation relation)
778779
RelationGetRelationName(relation));
779780

780781
/* Build trigdesc */
781-
trigdesc = (TriggerDesc *) MemoryContextAlloc(CacheMemoryContext,
782-
sizeof(TriggerDesc));
782+
trigdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
783783
MemSet(trigdesc, 0, sizeof(TriggerDesc));
784784
trigdesc->triggers = triggers;
785785
trigdesc->numtriggers = ntrigs;
786786
for (found = 0; found < ntrigs; found++)
787787
InsertTrigger(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+
*/
793806
static void
794807
InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx)
795808
{
@@ -830,11 +843,7 @@ InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx)
830843
{
831844
tp = &(t[TRIGGER_EVENT_INSERT]);
832845
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));
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
{
844853
tp = &(t[TRIGGER_EVENT_DELETE]);
845854
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));
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
{
857862
tp = &(t[TRIGGER_EVENT_UPDATE]);
858863
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));
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+
*/
869971
void
870972
FreeTriggerDesc(TriggerDesc *trigdesc)
871973
{
@@ -909,6 +1011,10 @@ FreeTriggerDesc(TriggerDesc *trigdesc)
9091011
pfree(trigdesc);
9101012
}
9111013

1014+
/*
1015+
* Compare two TriggerDesc structures for logical equality.
1016+
*/
1017+
#ifdef NOT_USED
9121018
bool
9131019
equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
9141020
{
@@ -966,6 +1072,7 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
9661072
return false;
9671073
return 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
*/
14621570
static void
14631571
DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
1464-
Relation rel, FmgrInfo *finfo,
1572+
Relation rel, TriggerDesc *trigdesc, FmgrInfo *finfo,
14651573
MemoryContext per_tuple_context)
14661574
{
14671575
Oid tgoid = event->dte_item[itemno].dti_tgoid;
1468-
TriggerDesc *trigdesc = rel->trigdesc;
14691576
TriggerData LocTriggerData;
14701577
HeapTupleData oldtuple;
14711578
HeapTupleData newtuple;
@@ -1530,7 +1637,7 @@ DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
15301637
}
15311638

15321639
/*
1533-
* Call the trigger and throw away an eventually returned updated
1640+
* Call the trigger and throw away any eventually returned updated
15341641
* tuple.
15351642
*/
15361643
rettuple = ExecCallTriggerFunc(&LocTriggerData,
@@ -1569,6 +1676,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
15691676
prev_event = NULL;
15701677
MemoryContext per_tuple_context;
15711678
Relation rel = NULL;
1679+
TriggerDesc *trigdesc = NULL;
15721680
FmgrInfo *finfo = NULL;
15731681

15741682
/*
@@ -1637,6 +1745,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
16371745
{
16381746
if (rel)
16391747
heap_close(rel, NoLock);
1748+
FreeTriggerDesc(trigdesc);
16401749
if (finfo)
16411750
pfree(finfo);
16421751

@@ -1647,16 +1756,25 @@ deferredTriggerInvokeEvents(bool immediate_only)
16471756
rel = 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
*/
16531771
finfo = (FmgrInfo *)
1654-
palloc(rel->trigdesc->numtriggers * sizeof(FmgrInfo));
1772+
palloc(trigdesc->numtriggers * sizeof(FmgrInfo));
16551773
MemSet(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,
16601778
per_tuple_context);
16611779

16621780
event->dte_item[i].dti_state |= TRIGGER_DEFERRED_DONE;
@@ -1708,6 +1826,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
17081826
/* Release working resources */
17091827
if (rel)
17101828
heap_close(rel, NoLock);
1829+
FreeTriggerDesc(trigdesc);
17111830
if (finfo)
17121831
pfree(finfo);
17131832
MemoryContextDelete(per_tuple_context);

src/backend/executor/execMain.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
*
2828
*
2929
* IDENTIFICATION
30-
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.179 2002/09/23 22:57:44 tgl Exp $
30+
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.180 2002/10/14 16:51:30 tgl Exp $
3131
*
3232
*-------------------------------------------------------------------------
3333
*/
@@ -799,7 +799,8 @@ initResultRelInfo(ResultRelInfo *resultRelInfo,
799799
resultRelInfo->ri_NumIndices = 0;
800800
resultRelInfo->ri_IndexRelationDescs = NULL;
801801
resultRelInfo->ri_IndexRelationInfo = NULL;
802-
resultRelInfo->ri_TrigDesc = resultRelationDesc->trigdesc;
802+
/* make a copy so as not to depend on relcache info not changing... */
803+
resultRelInfo->ri_TrigDesc = CopyTriggerDesc(resultRelationDesc->trigdesc);
803804
resultRelInfo->ri_TrigFunctions = NULL;
804805
resultRelInfo->ri_ConstraintExprs = NULL;
805806
resultRelInfo->ri_junkFilter = NULL;

0 commit comments

Comments
 (0)