aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/trigger.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/trigger.c')
-rw-r--r--src/backend/commands/trigger.c365
1 files changed, 239 insertions, 126 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 70c146530f1..013221860a2 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.91 2001/05/27 09:59:29 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.92 2001/06/01 02:41:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,14 +32,19 @@
#include "utils/syscache.h"
-static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger);
-static HeapTuple GetTupleForTrigger(EState *estate, ItemPointer tid,
- TupleTableSlot **newSlot);
-static HeapTuple ExecCallTriggerFunc(Trigger *trigger,
- TriggerData *trigdata,
- MemoryContext per_tuple_context);
-static void DeferredTriggerSaveEvent(Relation rel, int event,
- HeapTuple oldtup, HeapTuple newtup);
+static void InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx);
+static HeapTuple GetTupleForTrigger(EState *estate,
+ ResultRelInfo *relinfo,
+ ItemPointer tid,
+ TupleTableSlot **newSlot);
+static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
+ FmgrInfo *finfo,
+ MemoryContext per_tuple_context);
+static void DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
+ HeapTuple oldtup, HeapTuple newtup);
+static void DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
+ Relation rel, FmgrInfo *finfo,
+ MemoryContext per_tuple_context);
void
@@ -577,8 +582,6 @@ RelationBuildTriggers(Relation relation)
DatumGetCString(DirectFunctionCall1(nameout,
NameGetDatum(&pg_trigger->tgname))));
build->tgfoid = pg_trigger->tgfoid;
- build->tgfunc.fn_oid = InvalidOid; /* mark FmgrInfo as
- * uninitialized */
build->tgtype = pg_trigger->tgtype;
build->tgenabled = pg_trigger->tgenabled;
build->tgisconstraint = pg_trigger->tgisconstraint;
@@ -641,21 +644,22 @@ RelationBuildTriggers(Relation relation)
trigdesc->triggers = triggers;
trigdesc->numtriggers = ntrigs;
for (found = 0; found < ntrigs; found++)
- DescribeTrigger(trigdesc, &(triggers[found]));
+ InsertTrigger(trigdesc, &(triggers[found]), found);
relation->trigdesc = trigdesc;
}
+/* Insert the given trigger into the appropriate index list(s) for it */
static void
-DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
+InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx)
{
uint16 *n;
- Trigger ***t,
- ***tp;
+ int **t,
+ **tp;
- if (TRIGGER_FOR_ROW(trigger->tgtype)) /* Is ROW/STATEMENT
- * trigger */
+ if (TRIGGER_FOR_ROW(trigger->tgtype))
{
+ /* ROW trigger */
if (TRIGGER_FOR_BEFORE(trigger->tgtype))
{
n = trigdesc->n_before_row;
@@ -668,8 +672,8 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
}
}
else
-/* STATEMENT (NI) */
{
+ /* STATEMENT trigger */
if (TRIGGER_FOR_BEFORE(trigger->tgtype))
{
n = trigdesc->n_before_statement;
@@ -686,12 +690,12 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
{
tp = &(t[TRIGGER_EVENT_INSERT]);
if (*tp == NULL)
- *tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext,
- sizeof(Trigger *));
+ *tp = (int *) MemoryContextAlloc(CacheMemoryContext,
+ sizeof(int));
else
- *tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
- sizeof(Trigger *));
- (*tp)[n[TRIGGER_EVENT_INSERT]] = trigger;
+ *tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
+ sizeof(int));
+ (*tp)[n[TRIGGER_EVENT_INSERT]] = indx;
(n[TRIGGER_EVENT_INSERT])++;
}
@@ -699,12 +703,12 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
{
tp = &(t[TRIGGER_EVENT_DELETE]);
if (*tp == NULL)
- *tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext,
- sizeof(Trigger *));
+ *tp = (int *) MemoryContextAlloc(CacheMemoryContext,
+ sizeof(int));
else
- *tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
- sizeof(Trigger *));
- (*tp)[n[TRIGGER_EVENT_DELETE]] = trigger;
+ *tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
+ sizeof(int));
+ (*tp)[n[TRIGGER_EVENT_DELETE]] = indx;
(n[TRIGGER_EVENT_DELETE])++;
}
@@ -712,21 +716,20 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
{
tp = &(t[TRIGGER_EVENT_UPDATE]);
if (*tp == NULL)
- *tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext,
- sizeof(Trigger *));
+ *tp = (int *) MemoryContextAlloc(CacheMemoryContext,
+ sizeof(int));
else
- *tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
- sizeof(Trigger *));
- (*tp)[n[TRIGGER_EVENT_UPDATE]] = trigger;
+ *tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
+ sizeof(int));
+ (*tp)[n[TRIGGER_EVENT_UPDATE]] = indx;
(n[TRIGGER_EVENT_UPDATE])++;
}
-
}
void
FreeTriggerDesc(TriggerDesc *trigdesc)
{
- Trigger ***t;
+ int **t;
Trigger *trigger;
int i;
@@ -734,19 +737,19 @@ FreeTriggerDesc(TriggerDesc *trigdesc)
return;
t = trigdesc->tg_before_statement;
- for (i = 0; i < 4; i++)
+ for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
if (t[i] != NULL)
pfree(t[i]);
t = trigdesc->tg_before_row;
- for (i = 0; i < 4; i++)
+ for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
if (t[i] != NULL)
pfree(t[i]);
t = trigdesc->tg_after_row;
- for (i = 0; i < 4; i++)
+ for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
if (t[i] != NULL)
pfree(t[i]);
t = trigdesc->tg_after_statement;
- for (i = 0; i < 4; i++)
+ for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
if (t[i] != NULL)
pfree(t[i]);
@@ -806,7 +809,6 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
return false;
if (trig1->tgfoid != trig2->tgfoid)
return false;
- /* need not examine tgfunc, if tgfoid matches */
if (trig1->tgtype != trig2->tgtype)
return false;
if (trig1->tgenabled != trig2->tgenabled)
@@ -832,9 +834,18 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
return true;
}
+/*
+ * Call a trigger function.
+ *
+ * trigdata: trigger descriptor.
+ * finfo: possibly-cached call info for the function.
+ * per_tuple_context: memory context to execute the function in.
+ *
+ * Returns the tuple (or NULL) as returned by the function.
+ */
static HeapTuple
-ExecCallTriggerFunc(Trigger *trigger,
- TriggerData *trigdata,
+ExecCallTriggerFunc(TriggerData *trigdata,
+ FmgrInfo *finfo,
MemoryContext per_tuple_context)
{
FunctionCallInfoData fcinfo;
@@ -842,11 +853,13 @@ ExecCallTriggerFunc(Trigger *trigger,
MemoryContext oldContext;
/*
- * Fmgr lookup info is cached in the Trigger structure, so that we
- * need not repeat the lookup on every call.
+ * We cache fmgr lookup info, to avoid making the lookup
+ * again on each call.
*/
- if (trigger->tgfunc.fn_oid == InvalidOid)
- fmgr_info(trigger->tgfoid, &trigger->tgfunc);
+ if (finfo->fn_oid == InvalidOid)
+ fmgr_info(trigdata->tg_trigger->tgfoid, finfo);
+
+ Assert(finfo->fn_oid == trigdata->tg_trigger->tgfoid);
/*
* Do the function evaluation in the per-tuple memory context, so that
@@ -861,7 +874,7 @@ ExecCallTriggerFunc(Trigger *trigger,
*/
MemSet(&fcinfo, 0, sizeof(fcinfo));
- fcinfo.flinfo = &trigger->tgfunc;
+ fcinfo.flinfo = finfo;
fcinfo.context = (Node *) trigdata;
result = FunctionCallInvoke(&fcinfo);
@@ -880,26 +893,40 @@ ExecCallTriggerFunc(Trigger *trigger,
}
HeapTuple
-ExecBRInsertTriggers(EState *estate, Relation rel, HeapTuple trigtuple)
+ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
+ HeapTuple trigtuple)
{
- int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
- Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
+ TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
+ int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
+ int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
HeapTuple newtuple = trigtuple;
HeapTuple oldtuple;
TriggerData LocTriggerData;
int i;
+ /* Allocate cache space for fmgr lookup info, if not done yet */
+ if (relinfo->ri_TrigFunctions == NULL)
+ {
+ relinfo->ri_TrigFunctions = (FmgrInfo *)
+ palloc(trigdesc->numtriggers * sizeof(FmgrInfo));
+ MemSet(relinfo->ri_TrigFunctions, 0,
+ trigdesc->numtriggers * sizeof(FmgrInfo));
+ }
+
LocTriggerData.type = T_TriggerData;
LocTriggerData.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
- LocTriggerData.tg_relation = rel;
+ LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
LocTriggerData.tg_newtuple = NULL;
for (i = 0; i < ntrigs; i++)
{
- if (!trigger[i]->tgenabled)
+ Trigger *trigger = &trigdesc->triggers[tgindx[i]];
+
+ if (!trigger->tgenabled)
continue;
LocTriggerData.tg_trigtuple = oldtuple = newtuple;
- LocTriggerData.tg_trigger = trigger[i];
- newtuple = ExecCallTriggerFunc(trigger[i], &LocTriggerData,
+ LocTriggerData.tg_trigger = trigger;
+ newtuple = ExecCallTriggerFunc(&LocTriggerData,
+ relinfo->ri_TrigFunctions + tgindx[i],
GetPerTupleMemoryContext(estate));
if (oldtuple != newtuple && oldtuple != trigtuple)
heap_freetuple(oldtuple);
@@ -910,42 +937,59 @@ ExecBRInsertTriggers(EState *estate, Relation rel, HeapTuple trigtuple)
}
void
-ExecARInsertTriggers(EState *estate, Relation rel, HeapTuple trigtuple)
+ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo,
+ HeapTuple trigtuple)
{
+ TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
+
/* Must save info if there are any deferred triggers on this rel */
- if (rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0 ||
- rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 ||
- rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
- DeferredTriggerSaveEvent(rel, TRIGGER_EVENT_INSERT, NULL, trigtuple);
+ if (trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0 ||
+ trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 ||
+ trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
+ DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_INSERT,
+ NULL, trigtuple);
}
bool
-ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
+ExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
+ ItemPointer tupleid)
{
- Relation rel = estate->es_result_relation_info->ri_RelationDesc;
- int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
- Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
+ TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
+ int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
+ int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
TriggerData LocTriggerData;
HeapTuple trigtuple;
HeapTuple newtuple = NULL;
TupleTableSlot *newSlot;
int i;
- trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot);
+ trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
if (trigtuple == NULL)
return false;
+ /* Allocate cache space for fmgr lookup info, if not done yet */
+ if (relinfo->ri_TrigFunctions == NULL)
+ {
+ relinfo->ri_TrigFunctions = (FmgrInfo *)
+ palloc(trigdesc->numtriggers * sizeof(FmgrInfo));
+ MemSet(relinfo->ri_TrigFunctions, 0,
+ trigdesc->numtriggers * sizeof(FmgrInfo));
+ }
+
LocTriggerData.type = T_TriggerData;
LocTriggerData.tg_event = TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
- LocTriggerData.tg_relation = rel;
+ LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
LocTriggerData.tg_newtuple = NULL;
for (i = 0; i < ntrigs; i++)
{
- if (!trigger[i]->tgenabled)
+ Trigger *trigger = &trigdesc->triggers[tgindx[i]];
+
+ if (!trigger->tgenabled)
continue;
LocTriggerData.tg_trigtuple = trigtuple;
- LocTriggerData.tg_trigger = trigger[i];
- newtuple = ExecCallTriggerFunc(trigger[i], &LocTriggerData,
+ LocTriggerData.tg_trigger = trigger;
+ newtuple = ExecCallTriggerFunc(&LocTriggerData,
+ relinfo->ri_TrigFunctions + tgindx[i],
GetPerTupleMemoryContext(estate));
if (newtuple == NULL)
break;
@@ -958,27 +1002,31 @@ ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
}
void
-ExecARDeleteTriggers(EState *estate, ItemPointer tupleid)
+ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
+ ItemPointer tupleid)
{
- Relation rel = estate->es_result_relation_info->ri_RelationDesc;
+ TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
/* Must save info if there are upd/del deferred triggers on this rel */
- if (rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 ||
- rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
+ if (trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 ||
+ trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
{
- HeapTuple trigtuple = GetTupleForTrigger(estate, tupleid, NULL);
+ HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo,
+ tupleid, NULL);
- DeferredTriggerSaveEvent(rel, TRIGGER_EVENT_DELETE, trigtuple, NULL);
+ DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_DELETE,
+ trigtuple, NULL);
heap_freetuple(trigtuple);
}
}
HeapTuple
-ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
+ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
+ ItemPointer tupleid, HeapTuple newtuple)
{
- Relation rel = estate->es_result_relation_info->ri_RelationDesc;
- int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
- Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
+ TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
+ int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
+ int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
TriggerData LocTriggerData;
HeapTuple trigtuple;
HeapTuple oldtuple;
@@ -986,7 +1034,7 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
TupleTableSlot *newSlot;
int i;
- trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot);
+ trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
if (trigtuple == NULL)
return NULL;
@@ -997,17 +1045,29 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
if (newSlot != NULL)
intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot);
+ /* Allocate cache space for fmgr lookup info, if not done yet */
+ if (relinfo->ri_TrigFunctions == NULL)
+ {
+ relinfo->ri_TrigFunctions = (FmgrInfo *)
+ palloc(trigdesc->numtriggers * sizeof(FmgrInfo));
+ MemSet(relinfo->ri_TrigFunctions, 0,
+ trigdesc->numtriggers * sizeof(FmgrInfo));
+ }
+
LocTriggerData.type = T_TriggerData;
LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
- LocTriggerData.tg_relation = rel;
+ LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
for (i = 0; i < ntrigs; i++)
{
- if (!trigger[i]->tgenabled)
+ Trigger *trigger = &trigdesc->triggers[tgindx[i]];
+
+ if (!trigger->tgenabled)
continue;
LocTriggerData.tg_trigtuple = trigtuple;
LocTriggerData.tg_newtuple = oldtuple = newtuple;
- LocTriggerData.tg_trigger = trigger[i];
- newtuple = ExecCallTriggerFunc(trigger[i], &LocTriggerData,
+ LocTriggerData.tg_trigger = trigger;
+ newtuple = ExecCallTriggerFunc(&LocTriggerData,
+ relinfo->ri_TrigFunctions + tgindx[i],
GetPerTupleMemoryContext(estate));
if (oldtuple != newtuple && oldtuple != intuple)
heap_freetuple(oldtuple);
@@ -1019,26 +1079,30 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
}
void
-ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
+ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
+ ItemPointer tupleid, HeapTuple newtuple)
{
- Relation rel = estate->es_result_relation_info->ri_RelationDesc;
+ TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
/* Must save info if there are upd/del deferred triggers on this rel */
- if (rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 ||
- rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
+ if (trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 ||
+ trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
{
- HeapTuple trigtuple = GetTupleForTrigger(estate, tupleid, NULL);
+ HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo,
+ tupleid, NULL);
- DeferredTriggerSaveEvent(rel, TRIGGER_EVENT_UPDATE, trigtuple, newtuple);
+ DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_UPDATE,
+ trigtuple, newtuple);
heap_freetuple(trigtuple);
}
}
static HeapTuple
-GetTupleForTrigger(EState *estate, ItemPointer tid, TupleTableSlot **newSlot)
+GetTupleForTrigger(EState *estate, ResultRelInfo *relinfo,
+ ItemPointer tid, TupleTableSlot **newSlot)
{
- Relation relation = estate->es_result_relation_info->ri_RelationDesc;
+ Relation relation = relinfo->ri_RelationDesc;
HeapTupleData tuple;
HeapTuple result;
Buffer buffer;
@@ -1070,8 +1134,8 @@ ltrmark:;
else if (!(ItemPointerEquals(&(tuple.t_self), tid)))
{
TupleTableSlot *epqslot = EvalPlanQual(estate,
- estate->es_result_relation_info->ri_RangeTableIndex,
- &(tuple.t_self));
+ relinfo->ri_RangeTableIndex,
+ &(tuple.t_self));
if (!(TupIsNull(epqslot)))
{
@@ -1293,35 +1357,46 @@ deferredTriggerGetPreviousEvent(Oid relid, ItemPointer ctid)
/* ----------
- * deferredTriggerExecute()
+ * DeferredTriggerExecute()
*
* Fetch the required tuples back from the heap and fire one
* single trigger function.
+ *
+ * Frequently, this will be fired many times in a row for triggers of
+ * a single relation. Therefore, we cache the open relation and provide
+ * fmgr lookup cache space at the caller level.
+ *
+ * event: event currently being fired.
+ * itemno: item within event currently being fired.
+ * rel: open relation for event.
+ * finfo: array of fmgr lookup cache entries (one per trigger of relation).
+ * per_tuple_context: memory context to call trigger function in.
* ----------
*/
static void
-deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
+DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
+ Relation rel, FmgrInfo *finfo,
MemoryContext per_tuple_context)
{
- Relation rel;
+ Oid tgoid = event->dte_item[itemno].dti_tgoid;
+ TriggerDesc *trigdesc = rel->trigdesc;
TriggerData LocTriggerData;
HeapTupleData oldtuple;
HeapTupleData newtuple;
HeapTuple rettuple;
Buffer oldbuffer;
Buffer newbuffer;
+ int tgindx;
/*
- * Open the heap and fetch the required OLD and NEW tuples.
+ * Fetch the required OLD and NEW tuples.
*/
- rel = heap_open(event->dte_relid, NoLock);
-
if (ItemPointerIsValid(&(event->dte_oldctid)))
{
ItemPointerCopy(&(event->dte_oldctid), &(oldtuple.t_self));
heap_fetch(rel, SnapshotAny, &oldtuple, &oldbuffer);
if (!oldtuple.t_data)
- elog(ERROR, "deferredTriggerExecute: failed to fetch old tuple");
+ elog(ERROR, "DeferredTriggerExecute: failed to fetch old tuple");
}
if (ItemPointerIsValid(&(event->dte_newctid)))
@@ -1329,7 +1404,7 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
ItemPointerCopy(&(event->dte_newctid), &(newtuple.t_self));
heap_fetch(rel, SnapshotAny, &newtuple, &newbuffer);
if (!newtuple.t_data)
- elog(ERROR, "deferredTriggerExecute: failed to fetch new tuple");
+ elog(ERROR, "DeferredTriggerExecute: failed to fetch new tuple");
}
/*
@@ -1340,27 +1415,33 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
TRIGGER_EVENT_ROW;
LocTriggerData.tg_relation = rel;
+ LocTriggerData.tg_trigger = NULL;
+ for (tgindx = 0; tgindx < trigdesc->numtriggers; tgindx++)
+ {
+ if (trigdesc->triggers[tgindx].tgoid == tgoid)
+ {
+ LocTriggerData.tg_trigger = &(trigdesc->triggers[tgindx]);
+ break;
+ }
+ }
+ if (LocTriggerData.tg_trigger == NULL)
+ elog(ERROR, "DeferredTriggerExecute: can't find trigger %u", tgoid);
+
switch (event->dte_event & TRIGGER_EVENT_OPMASK)
{
case TRIGGER_EVENT_INSERT:
LocTriggerData.tg_trigtuple = &newtuple;
LocTriggerData.tg_newtuple = NULL;
- LocTriggerData.tg_trigger =
- rel->trigdesc->tg_after_row[TRIGGER_EVENT_INSERT][itemno];
break;
case TRIGGER_EVENT_UPDATE:
LocTriggerData.tg_trigtuple = &oldtuple;
LocTriggerData.tg_newtuple = &newtuple;
- LocTriggerData.tg_trigger =
- rel->trigdesc->tg_after_row[TRIGGER_EVENT_UPDATE][itemno];
break;
case TRIGGER_EVENT_DELETE:
LocTriggerData.tg_trigtuple = &oldtuple;
LocTriggerData.tg_newtuple = NULL;
- LocTriggerData.tg_trigger =
- rel->trigdesc->tg_after_row[TRIGGER_EVENT_DELETE][itemno];
break;
}
@@ -1368,8 +1449,8 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
* Call the trigger and throw away an eventually returned updated
* tuple.
*/
- rettuple = ExecCallTriggerFunc(LocTriggerData.tg_trigger,
- &LocTriggerData,
+ rettuple = ExecCallTriggerFunc(&LocTriggerData,
+ finfo + tgindx,
per_tuple_context);
if (rettuple != NULL && rettuple != &oldtuple && rettuple != &newtuple)
heap_freetuple(rettuple);
@@ -1381,14 +1462,12 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
ReferentialIntegritySnapshotOverride = false;
/*
- * Release buffers and close the relation
+ * Release buffers
*/
if (ItemPointerIsValid(&(event->dte_oldctid)))
ReleaseBuffer(oldbuffer);
if (ItemPointerIsValid(&(event->dte_newctid)))
ReleaseBuffer(newbuffer);
-
- heap_close(rel, NoLock);
}
@@ -1403,9 +1482,9 @@ static void
deferredTriggerInvokeEvents(bool immediate_only)
{
DeferredTriggerEvent event;
- int still_deferred_ones;
- int i;
MemoryContext per_tuple_context;
+ Relation rel = NULL;
+ FmgrInfo *finfo = NULL;
/*
* For now we process all events - to speedup transaction blocks we
@@ -1426,6 +1505,8 @@ deferredTriggerInvokeEvents(bool immediate_only)
for (event = deftrig_events; event != NULL; event = event->dte_next)
{
+ bool still_deferred_ones;
+ int i;
/*
* Check if event is completely done.
@@ -1458,9 +1539,32 @@ deferredTriggerInvokeEvents(bool immediate_only)
}
/*
- * So let's fire it...
+ * So let's fire it... but first, open the correct relation
+ * if this is not the same relation as before.
*/
- deferredTriggerExecute(event, i, per_tuple_context);
+ if (rel == NULL || rel->rd_id != event->dte_relid)
+ {
+ if (rel)
+ heap_close(rel, NoLock);
+ if (finfo)
+ pfree(finfo);
+ /*
+ * We assume that an appropriate lock is still held by the
+ * executor, so grab no new lock here.
+ */
+ rel = heap_open(event->dte_relid, NoLock);
+ /*
+ * Allocate space to cache fmgr lookup info for triggers
+ * of this relation.
+ */
+ finfo = (FmgrInfo *)
+ palloc(rel->trigdesc->numtriggers * sizeof(FmgrInfo));
+ MemSet(finfo, 0,
+ rel->trigdesc->numtriggers * sizeof(FmgrInfo));
+ }
+
+ DeferredTriggerExecute(event, i, rel, finfo, per_tuple_context);
+
event->dte_item[i].dti_state |= TRIGGER_DEFERRED_DONE;
}
@@ -1471,6 +1575,10 @@ deferredTriggerInvokeEvents(bool immediate_only)
event->dte_event |= TRIGGER_DEFERRED_DONE;
}
+ if (rel)
+ heap_close(rel, NoLock);
+ if (finfo)
+ pfree(finfo);
MemoryContextDelete(per_tuple_context);
}
@@ -1892,16 +2000,18 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
* ----------
*/
static void
-DeferredTriggerSaveEvent(Relation rel, int event,
+DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
HeapTuple oldtup, HeapTuple newtup)
{
+ Relation rel = relinfo->ri_RelationDesc;
+ TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
MemoryContext oldcxt;
DeferredTriggerEvent new_event;
DeferredTriggerEvent prev_event;
int new_size;
int i;
int ntriggers;
- Trigger **triggers;
+ int *tgindx;
ItemPointerData oldctid;
ItemPointerData newctid;
TriggerData LocTriggerData;
@@ -1927,8 +2037,8 @@ DeferredTriggerSaveEvent(Relation rel, int event,
*/
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
- ntriggers = rel->trigdesc->n_after_row[event];
- triggers = rel->trigdesc->tg_after_row[event];
+ ntriggers = trigdesc->n_after_row[event];
+ tgindx = trigdesc->tg_after_row[event];
new_size = offsetof(DeferredTriggerEventData, dte_item[0]) +
ntriggers * sizeof(DeferredTriggerEventItem);
@@ -1941,13 +2051,15 @@ DeferredTriggerSaveEvent(Relation rel, int event,
new_event->dte_n_items = ntriggers;
for (i = 0; i < ntriggers; i++)
{
- new_event->dte_item[i].dti_tgoid = triggers[i]->tgoid;
+ Trigger *trigger = &trigdesc->triggers[tgindx[i]];
+
+ new_event->dte_item[i].dti_tgoid = trigger->tgoid;
new_event->dte_item[i].dti_state =
- ((triggers[i]->tgdeferrable) ?
+ ((trigger->tgdeferrable) ?
TRIGGER_DEFERRED_DEFERRABLE : 0) |
- ((triggers[i]->tginitdeferred) ?
+ ((trigger->tginitdeferred) ?
TRIGGER_DEFERRED_INITDEFERRED : 0) |
- ((rel->trigdesc->n_before_row[event] > 0) ?
+ ((trigdesc->n_before_row[event] > 0) ?
TRIGGER_DEFERRED_HAS_BEFORE : 0);
}
@@ -1978,13 +2090,14 @@ DeferredTriggerSaveEvent(Relation rel, int event,
*/
for (i = 0; i < ntriggers; i++)
{
+ Trigger *trigger = &trigdesc->triggers[tgindx[i]];
bool is_ri_trigger;
bool key_unchanged;
/*
* We are interested in RI_FKEY triggers only.
*/
- switch (triggers[i]->tgfoid)
+ switch (trigger->tgfoid)
{
case F_RI_FKEY_NOACTION_UPD:
case F_RI_FKEY_CASCADE_UPD:
@@ -2006,7 +2119,7 @@ DeferredTriggerSaveEvent(Relation rel, int event,
LocTriggerData.tg_relation = rel;
LocTriggerData.tg_trigtuple = oldtup;
LocTriggerData.tg_newtuple = newtup;
- LocTriggerData.tg_trigger = triggers[i];
+ LocTriggerData.tg_trigger = trigger;
key_unchanged = RI_FKey_keyequal_upd(&LocTriggerData);