1 /*-------------------------------------------------------------------------
4 * PostgreSQL TRIGGERs support code.
6 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.105 2002/03/08 04:37:14 tgl Exp $
12 *-------------------------------------------------------------------------
16 #include "access/genam.h"
17 #include "access/heapam.h"
18 #include "catalog/catalog.h"
19 #include "catalog/catname.h"
20 #include "catalog/indexing.h"
21 #include "catalog/pg_language.h"
22 #include "catalog/pg_proc.h"
23 #include "catalog/pg_trigger.h"
24 #include "commands/comment.h"
25 #include "commands/trigger.h"
26 #include "executor/executor.h"
27 #include "miscadmin.h"
28 #include "utils/acl.h"
29 #include "utils/builtins.h"
30 #include "utils/fmgroids.h"
31 #include "utils/inval.h"
32 #include "utils/syscache.h"
35 static void InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx);
36 static HeapTuple GetTupleForTrigger(EState *estate,
37 ResultRelInfo *relinfo,
39 TupleTableSlot **newSlot);
40 static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
42 MemoryContext per_tuple_context);
43 static void DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
44 HeapTuple oldtup, HeapTuple newtup);
45 static void DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
46 Relation rel, FmgrInfo *finfo,
47 MemoryContext per_tuple_context);
51 CreateTrigger(CreateTrigStmt *stmt)
54 int16 tgattr[FUNC_MAX_ARGS];
55 Datum values[Natts_pg_trigger];
56 char nulls[Natts_pg_trigger];
63 Relation idescs[Num_pg_trigger_indices];
64 Relation ridescs[Num_pg_class_indices];
65 Oid fargtypes[FUNC_MAX_ARGS];
70 char constrtrigname[NAMEDATALEN];
71 char *constrname = "";
72 Oid constrrelid = InvalidOid;
74 if (!allowSystemTableMods && IsSystemRelationName(stmt->relname))
75 elog(ERROR, "CreateTrigger: can't create trigger for system relation %s", stmt->relname);
77 if (pg_aclcheck(stmt->relname, GetUserId(),
78 stmt->isconstraint ? ACL_REFERENCES : ACL_TRIGGER)
80 elog(ERROR, "permission denied");
83 * If trigger is a constraint, user trigger name as constraint name
84 * and build a unique trigger name instead.
86 if (stmt->isconstraint)
88 constrname = stmt->trigname;
89 stmt->trigname = constrtrigname;
90 sprintf(constrtrigname, "RI_ConstraintTrigger_%u", newoid());
92 if (strcmp(stmt->constrrelname, "") == 0)
93 constrrelid = InvalidOid;
97 * NoLock is probably sufficient here, since we're only
98 * interested in getting the relation's OID...
100 rel = heap_openr(stmt->constrrelname, NoLock);
101 constrrelid = rel->rd_id;
102 heap_close(rel, NoLock);
106 rel = heap_openr(stmt->relname, AccessExclusiveLock);
108 if (rel->rd_rel->relkind != RELKIND_RELATION)
109 elog(ERROR, "CreateTrigger: relation \"%s\" is not a table",
112 TRIGGER_CLEAR_TYPE(tgtype);
114 TRIGGER_SETT_BEFORE(tgtype);
116 TRIGGER_SETT_ROW(tgtype);
118 elog(ERROR, "CreateTrigger: STATEMENT triggers are unimplemented, yet");
120 for (i = 0; i < 3 && stmt->actions[i]; i++)
122 switch (stmt->actions[i])
125 if (TRIGGER_FOR_INSERT(tgtype))
126 elog(ERROR, "CreateTrigger: double INSERT event specified");
127 TRIGGER_SETT_INSERT(tgtype);
130 if (TRIGGER_FOR_DELETE(tgtype))
131 elog(ERROR, "CreateTrigger: double DELETE event specified");
132 TRIGGER_SETT_DELETE(tgtype);
135 if (TRIGGER_FOR_UPDATE(tgtype))
136 elog(ERROR, "CreateTrigger: double UPDATE event specified");
137 TRIGGER_SETT_UPDATE(tgtype);
140 elog(ERROR, "CreateTrigger: unknown event specified");
146 * Scan pg_trigger for existing triggers on relation. NOTE that this
147 * is cool only because we have AccessExclusiveLock on the relation,
148 * so the trigger set won't be changing underneath us.
150 tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
151 ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
153 ObjectIdGetDatum(RelationGetRelid(rel)));
154 tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true,
155 SnapshotNow, 1, &key);
156 while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
158 Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
160 if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
161 elog(ERROR, "CreateTrigger: trigger %s already defined on relation %s",
162 stmt->trigname, stmt->relname);
165 systable_endscan(tgscan);
168 * Find and validate the trigger function.
170 MemSet(fargtypes, 0, FUNC_MAX_ARGS * sizeof(Oid));
171 tuple = SearchSysCache(PROCNAME,
172 PointerGetDatum(stmt->funcname),
174 PointerGetDatum(fargtypes),
176 if (!HeapTupleIsValid(tuple))
177 elog(ERROR, "CreateTrigger: function %s() does not exist",
179 if (((Form_pg_proc) GETSTRUCT(tuple))->prorettype != 0)
180 elog(ERROR, "CreateTrigger: function %s() must return OPAQUE",
182 funcoid = tuple->t_data->t_oid;
183 funclang = ((Form_pg_proc) GETSTRUCT(tuple))->prolang;
184 ReleaseSysCache(tuple);
186 if (funclang != ClanguageId && funclang != INTERNALlanguageId)
190 langTup = SearchSysCache(LANGOID,
191 ObjectIdGetDatum(funclang),
193 if (!HeapTupleIsValid(langTup))
194 elog(ERROR, "CreateTrigger: cache lookup for language %u failed",
196 if (((Form_pg_language) GETSTRUCT(langTup))->lanispl == false)
197 elog(ERROR, "CreateTrigger: only internal, C and PL functions are supported");
198 ReleaseSysCache(langTup);
202 * Build the new pg_trigger tuple.
204 MemSet(nulls, ' ', Natts_pg_trigger * sizeof(char));
206 values[Anum_pg_trigger_tgrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
207 values[Anum_pg_trigger_tgname - 1] = DirectFunctionCall1(namein,
208 CStringGetDatum(stmt->trigname));
209 values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
210 values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
211 values[Anum_pg_trigger_tgenabled - 1] = BoolGetDatum(true);
212 values[Anum_pg_trigger_tgisconstraint - 1] = BoolGetDatum(stmt->isconstraint);
213 values[Anum_pg_trigger_tgconstrname - 1] = PointerGetDatum(constrname);
214 values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
215 values[Anum_pg_trigger_tgdeferrable - 1] = BoolGetDatum(stmt->deferrable);
216 values[Anum_pg_trigger_tginitdeferred - 1] = BoolGetDatum(stmt->initdeferred);
222 int16 nargs = length(stmt->args);
225 foreach(le, stmt->args)
227 char *ar = ((Value *) lfirst(le))->val.str;
229 len += strlen(ar) + 4;
236 args = (char *) palloc(len + 1);
238 foreach(le, stmt->args)
240 char *s = ((Value *) lfirst(le))->val.str;
241 char *d = args + strlen(args);
251 values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
252 values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain,
253 CStringGetDatum(args));
257 values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
258 values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain,
259 CStringGetDatum(""));
261 MemSet(tgattr, 0, FUNC_MAX_ARGS * sizeof(int16));
262 values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
264 tuple = heap_formtuple(tgrel->rd_att, values, nulls);
267 * Insert tuple into pg_trigger.
269 heap_insert(tgrel, tuple);
270 CatalogOpenIndices(Num_pg_trigger_indices, Name_pg_trigger_indices, idescs);
271 CatalogIndexInsert(idescs, Num_pg_trigger_indices, tgrel, tuple);
272 CatalogCloseIndices(Num_pg_trigger_indices, idescs);
273 heap_freetuple(tuple);
274 heap_close(tgrel, RowExclusiveLock);
276 pfree(DatumGetPointer(values[Anum_pg_trigger_tgname - 1]));
277 pfree(DatumGetPointer(values[Anum_pg_trigger_tgargs - 1]));
280 * Update relation's pg_class entry. Crucial side-effect: other
281 * backends (and this one too!) are sent SI message to make them
282 * rebuild relcache entries.
284 pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
285 tuple = SearchSysCacheCopy(RELNAME,
286 PointerGetDatum(stmt->relname),
288 if (!HeapTupleIsValid(tuple))
289 elog(ERROR, "CreateTrigger: relation %s not found in pg_class",
292 ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found + 1;
293 simple_heap_update(pgrel, &tuple->t_self, tuple);
294 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
295 CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
296 CatalogCloseIndices(Num_pg_class_indices, ridescs);
297 heap_freetuple(tuple);
298 heap_close(pgrel, RowExclusiveLock);
301 * We used to try to update the rel's relcache entry here, but that's
302 * fairly pointless since it will happen as a byproduct of the
303 * upcoming CommandCounterIncrement...
306 /* Keep lock on target rel until end of xact */
307 heap_close(rel, NoLock);
311 DropTrigger(DropTrigStmt *stmt)
319 Relation ridescs[Num_pg_class_indices];
323 if (!allowSystemTableMods && IsSystemRelationName(stmt->relname))
324 elog(ERROR, "DropTrigger: can't drop trigger for system relation %s",
327 if (!pg_ownercheck(GetUserId(), stmt->relname, RELNAME))
328 elog(ERROR, "%s: %s", stmt->relname,
329 aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
331 rel = heap_openr(stmt->relname, AccessExclusiveLock);
333 if (rel->rd_rel->relkind != RELKIND_RELATION)
334 elog(ERROR, "DropTrigger: relation \"%s\" is not a table",
338 * Search pg_trigger, delete target trigger, count remaining triggers
339 * for relation. Note this is OK only because we have
340 * AccessExclusiveLock on the rel, so no one else is creating/deleting
341 * triggers on this rel at the same time.
343 tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
344 ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
346 ObjectIdGetDatum(RelationGetRelid(rel)));
347 tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true,
348 SnapshotNow, 1, &key);
349 while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
351 Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
353 if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
355 /* Delete any comments associated with this trigger */
356 DeleteComments(tuple->t_data->t_oid, RelationGetRelid(tgrel));
358 simple_heap_delete(tgrel, &tuple->t_self);
364 systable_endscan(tgscan);
365 heap_close(tgrel, RowExclusiveLock);
368 elog(ERROR, "DropTrigger: there is no trigger %s on relation %s",
369 stmt->trigname, stmt->relname);
371 elog(NOTICE, "DropTrigger: found (and deleted) %d triggers %s on relation %s",
372 tgfound, stmt->trigname, stmt->relname);
375 * Update relation's pg_class entry. Crucial side-effect: other
376 * backends (and this one too!) are sent SI message to make them
377 * rebuild relcache entries.
379 pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
380 tuple = SearchSysCacheCopy(RELNAME,
381 PointerGetDatum(stmt->relname),
383 if (!HeapTupleIsValid(tuple))
384 elog(ERROR, "DropTrigger: relation %s not found in pg_class",
387 ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found;
388 simple_heap_update(pgrel, &tuple->t_self, tuple);
389 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
390 CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
391 CatalogCloseIndices(Num_pg_class_indices, ridescs);
392 heap_freetuple(tuple);
393 heap_close(pgrel, RowExclusiveLock);
396 * We used to try to update the rel's relcache entry here, but that's
397 * fairly pointless since it will happen as a byproduct of the
398 * upcoming CommandCounterIncrement...
401 /* Keep lock on target rel until end of xact */
402 heap_close(rel, NoLock);
406 * Remove all triggers for a relation that's being deleted.
409 RelationRemoveTriggers(Relation rel)
417 tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
418 ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
420 ObjectIdGetDatum(RelationGetRelid(rel)));
421 tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true,
422 SnapshotNow, 1, &key);
424 while (HeapTupleIsValid(tup = systable_getnext(tgscan)))
426 /* Delete any comments associated with this trigger */
427 DeleteComments(tup->t_data->t_oid, RelationGetRelid(tgrel));
429 simple_heap_delete(tgrel, &tup->t_self);
434 systable_endscan(tgscan);
437 * If we deleted any triggers, must update pg_class entry and advance
438 * command counter to make the updated entry visible. This is fairly
439 * annoying, since we'e just going to drop the durn thing later, but
440 * it's necessary to have a consistent state in case we do
441 * CommandCounterIncrement() below --- if RelationBuildTriggers()
442 * runs, it will complain otherwise. Perhaps RelationBuildTriggers()
443 * shouldn't be so picky...
448 Relation ridescs[Num_pg_class_indices];
450 pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
451 tup = SearchSysCacheCopy(RELOID,
452 RelationGetRelid(rel),
454 if (!HeapTupleIsValid(tup))
455 elog(ERROR, "RelationRemoveTriggers: relation %u not found in pg_class",
456 RelationGetRelid(rel));
458 ((Form_pg_class) GETSTRUCT(tup))->reltriggers = 0;
459 simple_heap_update(pgrel, &tup->t_self, tup);
460 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
461 CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tup);
462 CatalogCloseIndices(Num_pg_class_indices, ridescs);
464 heap_close(pgrel, RowExclusiveLock);
465 CommandCounterIncrement();
469 * Also drop all constraint triggers referencing this relation
471 ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgconstrrelid,
473 ObjectIdGetDatum(RelationGetRelid(rel)));
474 tgscan = systable_beginscan(tgrel, TriggerConstrRelidIndex, true,
475 SnapshotNow, 1, &key);
477 while (HeapTupleIsValid(tup = systable_getnext(tgscan)))
479 Form_pg_trigger pg_trigger;
483 pg_trigger = (Form_pg_trigger) GETSTRUCT(tup);
485 stmt.trigname = pstrdup(NameStr(pg_trigger->tgname));
487 /* May as well grab AccessExclusiveLock, since DropTrigger will. */
488 refrel = heap_open(pg_trigger->tgrelid, AccessExclusiveLock);
489 stmt.relname = pstrdup(RelationGetRelationName(refrel));
490 heap_close(refrel, NoLock);
492 elog(NOTICE, "DROP TABLE implicitly drops referential integrity trigger from table \"%s\"", stmt.relname);
497 * Need to do a command counter increment here to show up new
498 * pg_class.reltriggers in the next loop iteration (in case there
499 * are multiple referential integrity action triggers for the same
500 * FK table defined on the PK table).
502 CommandCounterIncrement();
505 pfree(stmt.trigname);
507 systable_endscan(tgscan);
509 heap_close(tgrel, RowExclusiveLock);
513 * Build trigger data to attach to the given relcache entry.
515 * Note that trigger data must be allocated in CacheMemoryContext
516 * to ensure it survives as long as the relcache entry. But we
517 * are probably running in a less long-lived working context.
520 RelationBuildTriggers(Relation relation)
522 TriggerDesc *trigdesc;
523 int ntrigs = relation->rd_rel->reltriggers;
524 Trigger *triggers = NULL;
533 ScanKeyEntryInitialize(&skey,
535 (AttrNumber) Anum_pg_trigger_tgrelid,
536 (RegProcedure) F_OIDEQ,
537 ObjectIdGetDatum(RelationGetRelid(relation)));
539 tgrel = heap_openr(TriggerRelationName, AccessShareLock);
540 tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true,
541 SnapshotNow, 1, &skey);
543 while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
545 Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
549 elog(ERROR, "RelationBuildTriggers: unexpected record found for rel %s",
550 RelationGetRelationName(relation));
552 if (triggers == NULL)
553 triggers = (Trigger *) MemoryContextAlloc(CacheMemoryContext,
556 triggers = (Trigger *) repalloc(triggers,
557 (found + 1) * sizeof(Trigger));
558 build = &(triggers[found]);
560 build->tgoid = htup->t_data->t_oid;
561 build->tgname = MemoryContextStrdup(CacheMemoryContext,
562 DatumGetCString(DirectFunctionCall1(nameout,
563 NameGetDatum(&pg_trigger->tgname))));
564 build->tgfoid = pg_trigger->tgfoid;
565 build->tgtype = pg_trigger->tgtype;
566 build->tgenabled = pg_trigger->tgenabled;
567 build->tgisconstraint = pg_trigger->tgisconstraint;
568 build->tgdeferrable = pg_trigger->tgdeferrable;
569 build->tginitdeferred = pg_trigger->tginitdeferred;
570 build->tgnargs = pg_trigger->tgnargs;
571 memcpy(build->tgattr, &(pg_trigger->tgattr),
572 FUNC_MAX_ARGS * sizeof(int16));
573 if (build->tgnargs > 0)
578 val = (struct varlena *) fastgetattr(htup,
579 Anum_pg_trigger_tgargs,
580 tgrel->rd_att, &isnull);
582 elog(ERROR, "RelationBuildTriggers: tgargs IS NULL for rel %s",
583 RelationGetRelationName(relation));
584 p = (char *) VARDATA(val);
585 build->tgargs = (char **)
586 MemoryContextAlloc(CacheMemoryContext,
587 build->tgnargs * sizeof(char *));
588 for (i = 0; i < build->tgnargs; i++)
590 build->tgargs[i] = MemoryContextStrdup(CacheMemoryContext,
596 build->tgargs = NULL;
601 systable_endscan(tgscan);
602 heap_close(tgrel, AccessShareLock);
605 elog(ERROR, "RelationBuildTriggers: %d record(s) not found for rel %s",
607 RelationGetRelationName(relation));
610 trigdesc = (TriggerDesc *) MemoryContextAlloc(CacheMemoryContext,
611 sizeof(TriggerDesc));
612 MemSet(trigdesc, 0, sizeof(TriggerDesc));
613 trigdesc->triggers = triggers;
614 trigdesc->numtriggers = ntrigs;
615 for (found = 0; found < ntrigs; found++)
616 InsertTrigger(trigdesc, &(triggers[found]), found);
618 relation->trigdesc = trigdesc;
621 /* Insert the given trigger into the appropriate index list(s) for it */
623 InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx)
629 if (TRIGGER_FOR_ROW(trigger->tgtype))
632 if (TRIGGER_FOR_BEFORE(trigger->tgtype))
634 n = trigdesc->n_before_row;
635 t = trigdesc->tg_before_row;
639 n = trigdesc->n_after_row;
640 t = trigdesc->tg_after_row;
645 /* STATEMENT trigger */
646 if (TRIGGER_FOR_BEFORE(trigger->tgtype))
648 n = trigdesc->n_before_statement;
649 t = trigdesc->tg_before_statement;
653 n = trigdesc->n_after_statement;
654 t = trigdesc->tg_after_statement;
658 if (TRIGGER_FOR_INSERT(trigger->tgtype))
660 tp = &(t[TRIGGER_EVENT_INSERT]);
662 *tp = (int *) MemoryContextAlloc(CacheMemoryContext,
665 *tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
667 (*tp)[n[TRIGGER_EVENT_INSERT]] = indx;
668 (n[TRIGGER_EVENT_INSERT])++;
671 if (TRIGGER_FOR_DELETE(trigger->tgtype))
673 tp = &(t[TRIGGER_EVENT_DELETE]);
675 *tp = (int *) MemoryContextAlloc(CacheMemoryContext,
678 *tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
680 (*tp)[n[TRIGGER_EVENT_DELETE]] = indx;
681 (n[TRIGGER_EVENT_DELETE])++;
684 if (TRIGGER_FOR_UPDATE(trigger->tgtype))
686 tp = &(t[TRIGGER_EVENT_UPDATE]);
688 *tp = (int *) MemoryContextAlloc(CacheMemoryContext,
691 *tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
693 (*tp)[n[TRIGGER_EVENT_UPDATE]] = indx;
694 (n[TRIGGER_EVENT_UPDATE])++;
699 FreeTriggerDesc(TriggerDesc *trigdesc)
705 if (trigdesc == NULL)
708 t = trigdesc->tg_before_statement;
709 for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
712 t = trigdesc->tg_before_row;
713 for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
716 t = trigdesc->tg_after_row;
717 for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
720 t = trigdesc->tg_after_statement;
721 for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
725 trigger = trigdesc->triggers;
726 for (i = 0; i < trigdesc->numtriggers; i++)
728 pfree(trigger->tgname);
729 if (trigger->tgnargs > 0)
731 while (--(trigger->tgnargs) >= 0)
732 pfree(trigger->tgargs[trigger->tgnargs]);
733 pfree(trigger->tgargs);
737 pfree(trigdesc->triggers);
742 equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
748 * We need not examine the "index" data, just the trigger array
749 * itself; if we have the same triggers with the same types, the
750 * derived index data should match.
752 if (trigdesc1 != NULL)
754 if (trigdesc2 == NULL)
756 if (trigdesc1->numtriggers != trigdesc2->numtriggers)
758 for (i = 0; i < trigdesc1->numtriggers; i++)
760 Trigger *trig1 = trigdesc1->triggers + i;
761 Trigger *trig2 = NULL;
764 * We can't assume that the triggers are always read from
765 * pg_trigger in the same order; so use the trigger OIDs to
766 * identify the triggers to compare. (We assume here that the
767 * same OID won't appear twice in either trigger set.)
769 for (j = 0; j < trigdesc2->numtriggers; j++)
771 trig2 = trigdesc2->triggers + j;
772 if (trig1->tgoid == trig2->tgoid)
775 if (j >= trigdesc2->numtriggers)
777 if (strcmp(trig1->tgname, trig2->tgname) != 0)
779 if (trig1->tgfoid != trig2->tgfoid)
781 if (trig1->tgtype != trig2->tgtype)
783 if (trig1->tgenabled != trig2->tgenabled)
785 if (trig1->tgisconstraint != trig2->tgisconstraint)
787 if (trig1->tgdeferrable != trig2->tgdeferrable)
789 if (trig1->tginitdeferred != trig2->tginitdeferred)
791 if (trig1->tgnargs != trig2->tgnargs)
793 if (memcmp(trig1->tgattr, trig2->tgattr,
794 sizeof(trig1->tgattr)) != 0)
796 for (j = 0; j < trig1->tgnargs; j++)
797 if (strcmp(trig1->tgargs[j], trig2->tgargs[j]) != 0)
801 else if (trigdesc2 != NULL)
807 * Call a trigger function.
809 * trigdata: trigger descriptor.
810 * finfo: possibly-cached call info for the function.
811 * per_tuple_context: memory context to execute the function in.
813 * Returns the tuple (or NULL) as returned by the function.
816 ExecCallTriggerFunc(TriggerData *trigdata,
818 MemoryContext per_tuple_context)
820 FunctionCallInfoData fcinfo;
822 MemoryContext oldContext;
825 * We cache fmgr lookup info, to avoid making the lookup again on each
828 if (finfo->fn_oid == InvalidOid)
829 fmgr_info(trigdata->tg_trigger->tgfoid, finfo);
831 Assert(finfo->fn_oid == trigdata->tg_trigger->tgfoid);
834 * Do the function evaluation in the per-tuple memory context, so that
835 * leaked memory will be reclaimed once per tuple. Note in particular
836 * that any new tuple created by the trigger function will live till
837 * the end of the tuple cycle.
839 oldContext = MemoryContextSwitchTo(per_tuple_context);
842 * Call the function, passing no arguments but setting a context.
844 MemSet(&fcinfo, 0, sizeof(fcinfo));
846 fcinfo.flinfo = finfo;
847 fcinfo.context = (Node *) trigdata;
849 result = FunctionCallInvoke(&fcinfo);
851 MemoryContextSwitchTo(oldContext);
854 * Trigger protocol allows function to return a null pointer, but NOT
855 * to set the isnull result flag.
858 elog(ERROR, "ExecCallTriggerFunc: function %u returned NULL",
859 fcinfo.flinfo->fn_oid);
861 return (HeapTuple) DatumGetPointer(result);
865 ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
868 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
869 int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
870 int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
871 HeapTuple newtuple = trigtuple;
873 TriggerData LocTriggerData;
876 /* Allocate cache space for fmgr lookup info, if not done yet */
877 if (relinfo->ri_TrigFunctions == NULL)
879 relinfo->ri_TrigFunctions = (FmgrInfo *)
880 palloc(trigdesc->numtriggers * sizeof(FmgrInfo));
881 MemSet(relinfo->ri_TrigFunctions, 0,
882 trigdesc->numtriggers * sizeof(FmgrInfo));
885 LocTriggerData.type = T_TriggerData;
886 LocTriggerData.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
887 LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
888 LocTriggerData.tg_newtuple = NULL;
889 for (i = 0; i < ntrigs; i++)
891 Trigger *trigger = &trigdesc->triggers[tgindx[i]];
893 if (!trigger->tgenabled)
895 LocTriggerData.tg_trigtuple = oldtuple = newtuple;
896 LocTriggerData.tg_trigger = trigger;
897 newtuple = ExecCallTriggerFunc(&LocTriggerData,
898 relinfo->ri_TrigFunctions + tgindx[i],
899 GetPerTupleMemoryContext(estate));
900 if (oldtuple != newtuple && oldtuple != trigtuple)
901 heap_freetuple(oldtuple);
902 if (newtuple == NULL)
909 ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo,
912 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
914 if (trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0)
915 DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_INSERT,
920 ExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
923 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
924 int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
925 int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
926 TriggerData LocTriggerData;
928 HeapTuple newtuple = NULL;
929 TupleTableSlot *newSlot;
932 trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
933 if (trigtuple == NULL)
936 /* Allocate cache space for fmgr lookup info, if not done yet */
937 if (relinfo->ri_TrigFunctions == NULL)
939 relinfo->ri_TrigFunctions = (FmgrInfo *)
940 palloc(trigdesc->numtriggers * sizeof(FmgrInfo));
941 MemSet(relinfo->ri_TrigFunctions, 0,
942 trigdesc->numtriggers * sizeof(FmgrInfo));
945 LocTriggerData.type = T_TriggerData;
946 LocTriggerData.tg_event = TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
947 LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
948 LocTriggerData.tg_newtuple = NULL;
949 for (i = 0; i < ntrigs; i++)
951 Trigger *trigger = &trigdesc->triggers[tgindx[i]];
953 if (!trigger->tgenabled)
955 LocTriggerData.tg_trigtuple = trigtuple;
956 LocTriggerData.tg_trigger = trigger;
957 newtuple = ExecCallTriggerFunc(&LocTriggerData,
958 relinfo->ri_TrigFunctions + tgindx[i],
959 GetPerTupleMemoryContext(estate));
960 if (newtuple == NULL)
962 if (newtuple != trigtuple)
963 heap_freetuple(newtuple);
965 heap_freetuple(trigtuple);
967 return (newtuple == NULL) ? false : true;
971 ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
974 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
976 if (trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
978 HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo,
981 DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_DELETE,
983 heap_freetuple(trigtuple);
988 ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
989 ItemPointer tupleid, HeapTuple newtuple)
991 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
992 int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
993 int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
994 TriggerData LocTriggerData;
997 HeapTuple intuple = newtuple;
998 TupleTableSlot *newSlot;
1001 trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
1002 if (trigtuple == NULL)
1006 * In READ COMMITTED isolevel it's possible that newtuple was changed
1007 * due to concurrent update.
1009 if (newSlot != NULL)
1010 intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot);
1012 /* Allocate cache space for fmgr lookup info, if not done yet */
1013 if (relinfo->ri_TrigFunctions == NULL)
1015 relinfo->ri_TrigFunctions = (FmgrInfo *)
1016 palloc(trigdesc->numtriggers * sizeof(FmgrInfo));
1017 MemSet(relinfo->ri_TrigFunctions, 0,
1018 trigdesc->numtriggers * sizeof(FmgrInfo));
1021 LocTriggerData.type = T_TriggerData;
1022 LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
1023 LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
1024 for (i = 0; i < ntrigs; i++)
1026 Trigger *trigger = &trigdesc->triggers[tgindx[i]];
1028 if (!trigger->tgenabled)
1030 LocTriggerData.tg_trigtuple = trigtuple;
1031 LocTriggerData.tg_newtuple = oldtuple = newtuple;
1032 LocTriggerData.tg_trigger = trigger;
1033 newtuple = ExecCallTriggerFunc(&LocTriggerData,
1034 relinfo->ri_TrigFunctions + tgindx[i],
1035 GetPerTupleMemoryContext(estate));
1036 if (oldtuple != newtuple && oldtuple != intuple)
1037 heap_freetuple(oldtuple);
1038 if (newtuple == NULL)
1041 heap_freetuple(trigtuple);
1046 ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
1047 ItemPointer tupleid, HeapTuple newtuple)
1049 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
1051 if (trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0)
1053 HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo,
1056 DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_UPDATE,
1057 trigtuple, newtuple);
1058 heap_freetuple(trigtuple);
1064 GetTupleForTrigger(EState *estate, ResultRelInfo *relinfo,
1065 ItemPointer tid, TupleTableSlot **newSlot)
1067 Relation relation = relinfo->ri_RelationDesc;
1068 HeapTupleData tuple;
1072 if (newSlot != NULL)
1077 * mark tuple for update
1080 tuple.t_self = *tid;
1082 test = heap_mark4update(relation, &tuple, &buffer);
1085 case HeapTupleSelfUpdated:
1086 ReleaseBuffer(buffer);
1089 case HeapTupleMayBeUpdated:
1092 case HeapTupleUpdated:
1093 ReleaseBuffer(buffer);
1094 if (XactIsoLevel == XACT_SERIALIZABLE)
1095 elog(ERROR, "Can't serialize access due to concurrent update");
1096 else if (!(ItemPointerEquals(&(tuple.t_self), tid)))
1098 TupleTableSlot *epqslot = EvalPlanQual(estate,
1099 relinfo->ri_RangeTableIndex,
1102 if (!(TupIsNull(epqslot)))
1104 *tid = tuple.t_self;
1111 * if tuple was deleted or PlanQual failed for updated
1112 * tuple - we have not process this tuple!
1117 ReleaseBuffer(buffer);
1118 elog(ERROR, "Unknown status %u from heap_mark4update", test);
1127 buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
1129 if (!BufferIsValid(buffer))
1130 elog(ERROR, "GetTupleForTrigger: failed ReadBuffer");
1132 dp = (PageHeader) BufferGetPage(buffer);
1133 lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
1135 Assert(ItemIdIsUsed(lp));
1137 tuple.t_datamcxt = NULL;
1138 tuple.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
1139 tuple.t_len = ItemIdGetLength(lp);
1140 tuple.t_self = *tid;
1143 result = heap_copytuple(&tuple);
1144 ReleaseBuffer(buffer);
1151 * Deferred trigger stuff
1157 * Internal data to the deferred trigger mechanism is held
1158 * during entire session in a global context created at startup and
1159 * over statements/commands in a separate context which
1160 * is created at transaction start and destroyed at transaction end.
1163 static MemoryContext deftrig_gcxt = NULL;
1164 static MemoryContext deftrig_cxt = NULL;
1167 * Global data that tells which triggers are actually in
1168 * state IMMEDIATE or DEFERRED.
1171 static bool deftrig_dfl_all_isset = false;
1172 static bool deftrig_dfl_all_isdeferred = false;
1173 static List *deftrig_dfl_trigstates = NIL;
1175 static bool deftrig_all_isset;
1176 static bool deftrig_all_isdeferred;
1177 static List *deftrig_trigstates;
1180 * The list of pending deferred trigger events during the current transaction.
1182 * deftrig_events is the head, deftrig_event_tail is the last entry.
1183 * Because this can grow pretty large, we don't use separate List nodes,
1184 * but instead thread the list through the dte_next fields of the member
1185 * nodes. Saves just a few bytes per entry, but that adds up.
1187 * XXX Need to be able to shove this data out to a file if it grows too
1191 static DeferredTriggerEvent deftrig_events;
1192 static DeferredTriggerEvent deftrig_event_tail;
1196 * deferredTriggerCheckState()
1198 * Returns true if the trigger identified by tgoid is actually
1199 * in state DEFERRED.
1203 deferredTriggerCheckState(Oid tgoid, int32 itemstate)
1205 MemoryContext oldcxt;
1207 DeferredTriggerStatus trigstate;
1210 * Not deferrable triggers (i.e. normal AFTER ROW triggers and
1211 * constraints declared NOT DEFERRABLE, the state is allways false.
1213 if ((itemstate & TRIGGER_DEFERRED_DEFERRABLE) == 0)
1217 * Lookup if we know an individual state for this trigger
1219 foreach(sl, deftrig_trigstates)
1221 trigstate = (DeferredTriggerStatus) lfirst(sl);
1222 if (trigstate->dts_tgoid == tgoid)
1223 return trigstate->dts_tgisdeferred;
1227 * No individual state known - so if the user issued a SET CONSTRAINT
1228 * ALL ..., we return that instead of the triggers default state.
1230 if (deftrig_all_isset)
1231 return deftrig_all_isdeferred;
1234 * No ALL state known either, remember the default state as the
1235 * current and return that.
1237 oldcxt = MemoryContextSwitchTo(deftrig_cxt);
1239 trigstate = (DeferredTriggerStatus)
1240 palloc(sizeof(DeferredTriggerStatusData));
1241 trigstate->dts_tgoid = tgoid;
1242 trigstate->dts_tgisdeferred =
1243 ((itemstate & TRIGGER_DEFERRED_INITDEFERRED) != 0);
1244 deftrig_trigstates = lappend(deftrig_trigstates, trigstate);
1246 MemoryContextSwitchTo(oldcxt);
1248 return trigstate->dts_tgisdeferred;
1253 * deferredTriggerAddEvent()
1255 * Add a new trigger event to the queue.
1259 deferredTriggerAddEvent(DeferredTriggerEvent event)
1262 * Since the event list could grow quite long, we keep track of the
1263 * list tail and append there, rather than just doing a stupid
1264 * "lappend". This avoids O(N^2) behavior for large numbers of events.
1266 event->dte_next = NULL;
1267 if (deftrig_event_tail == NULL)
1269 /* first list entry */
1270 deftrig_events = event;
1271 deftrig_event_tail = event;
1275 deftrig_event_tail->dte_next = event;
1276 deftrig_event_tail = event;
1282 * DeferredTriggerExecute()
1284 * Fetch the required tuples back from the heap and fire one
1285 * single trigger function.
1287 * Frequently, this will be fired many times in a row for triggers of
1288 * a single relation. Therefore, we cache the open relation and provide
1289 * fmgr lookup cache space at the caller level.
1291 * event: event currently being fired.
1292 * itemno: item within event currently being fired.
1293 * rel: open relation for event.
1294 * finfo: array of fmgr lookup cache entries (one per trigger of relation).
1295 * per_tuple_context: memory context to call trigger function in.
1299 DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
1300 Relation rel, FmgrInfo *finfo,
1301 MemoryContext per_tuple_context)
1303 Oid tgoid = event->dte_item[itemno].dti_tgoid;
1304 TriggerDesc *trigdesc = rel->trigdesc;
1305 TriggerData LocTriggerData;
1306 HeapTupleData oldtuple;
1307 HeapTupleData newtuple;
1314 * Fetch the required OLD and NEW tuples.
1316 if (ItemPointerIsValid(&(event->dte_oldctid)))
1318 ItemPointerCopy(&(event->dte_oldctid), &(oldtuple.t_self));
1319 heap_fetch(rel, SnapshotAny, &oldtuple, &oldbuffer, NULL);
1320 if (!oldtuple.t_data)
1321 elog(ERROR, "DeferredTriggerExecute: failed to fetch old tuple");
1324 if (ItemPointerIsValid(&(event->dte_newctid)))
1326 ItemPointerCopy(&(event->dte_newctid), &(newtuple.t_self));
1327 heap_fetch(rel, SnapshotAny, &newtuple, &newbuffer, NULL);
1328 if (!newtuple.t_data)
1329 elog(ERROR, "DeferredTriggerExecute: failed to fetch new tuple");
1333 * Setup the trigger information
1335 LocTriggerData.type = T_TriggerData;
1336 LocTriggerData.tg_event = (event->dte_event & TRIGGER_EVENT_OPMASK) |
1338 LocTriggerData.tg_relation = rel;
1340 LocTriggerData.tg_trigger = NULL;
1341 for (tgindx = 0; tgindx < trigdesc->numtriggers; tgindx++)
1343 if (trigdesc->triggers[tgindx].tgoid == tgoid)
1345 LocTriggerData.tg_trigger = &(trigdesc->triggers[tgindx]);
1349 if (LocTriggerData.tg_trigger == NULL)
1350 elog(ERROR, "DeferredTriggerExecute: can't find trigger %u", tgoid);
1352 switch (event->dte_event & TRIGGER_EVENT_OPMASK)
1354 case TRIGGER_EVENT_INSERT:
1355 LocTriggerData.tg_trigtuple = &newtuple;
1356 LocTriggerData.tg_newtuple = NULL;
1359 case TRIGGER_EVENT_UPDATE:
1360 LocTriggerData.tg_trigtuple = &oldtuple;
1361 LocTriggerData.tg_newtuple = &newtuple;
1364 case TRIGGER_EVENT_DELETE:
1365 LocTriggerData.tg_trigtuple = &oldtuple;
1366 LocTriggerData.tg_newtuple = NULL;
1371 * Call the trigger and throw away an eventually returned updated
1374 rettuple = ExecCallTriggerFunc(&LocTriggerData,
1377 if (rettuple != NULL && rettuple != &oldtuple && rettuple != &newtuple)
1378 heap_freetuple(rettuple);
1381 * Might have been a referential integrity constraint trigger. Reset
1382 * the snapshot overriding flag.
1384 ReferentialIntegritySnapshotOverride = false;
1389 if (ItemPointerIsValid(&(event->dte_oldctid)))
1390 ReleaseBuffer(oldbuffer);
1391 if (ItemPointerIsValid(&(event->dte_newctid)))
1392 ReleaseBuffer(newbuffer);
1397 * deferredTriggerInvokeEvents()
1399 * Scan the event queue for not yet invoked triggers. Check if they
1400 * should be invoked now and do so.
1404 deferredTriggerInvokeEvents(bool immediate_only)
1406 DeferredTriggerEvent event,
1408 MemoryContext per_tuple_context;
1409 Relation rel = NULL;
1410 FmgrInfo *finfo = NULL;
1413 * If immediate_only is true, we remove fully-processed events from
1414 * the event queue to recycle space. If immediate_only is false,
1415 * we are going to discard the whole event queue on return anyway,
1416 * so no need to bother with "retail" pfree's.
1418 * In a scenario with many commands in a transaction and many
1419 * deferred-to-end-of-transaction triggers, it could get annoying
1420 * to rescan all the deferred triggers at each command end.
1421 * To speed this up, we could remember the actual end of the queue at
1422 * EndQuery and examine only events that are newer. On state changes
1423 * we simply reset the saved position to the beginning of the queue
1424 * and process all events once with the new states.
1427 /* Make a per-tuple memory context for trigger function calls */
1429 AllocSetContextCreate(CurrentMemoryContext,
1430 "DeferredTriggerTupleContext",
1431 ALLOCSET_DEFAULT_MINSIZE,
1432 ALLOCSET_DEFAULT_INITSIZE,
1433 ALLOCSET_DEFAULT_MAXSIZE);
1435 event = deftrig_events;
1436 while (event != NULL)
1438 bool still_deferred_ones = false;
1439 DeferredTriggerEvent next_event;
1443 * Check if event is already completely done.
1445 if (! (event->dte_event & (TRIGGER_DEFERRED_DONE |
1446 TRIGGER_DEFERRED_CANCELED)))
1448 MemoryContextReset(per_tuple_context);
1451 * Check each trigger item in the event.
1453 for (i = 0; i < event->dte_n_items; i++)
1455 if (event->dte_item[i].dti_state & TRIGGER_DEFERRED_DONE)
1459 * This trigger item hasn't been called yet. Check if we
1460 * should call it now.
1462 if (immediate_only &&
1463 deferredTriggerCheckState(event->dte_item[i].dti_tgoid,
1464 event->dte_item[i].dti_state))
1466 still_deferred_ones = true;
1471 * So let's fire it... but first, open the correct relation
1472 * if this is not the same relation as before.
1474 if (rel == NULL || rel->rd_id != event->dte_relid)
1477 heap_close(rel, NoLock);
1482 * We assume that an appropriate lock is still held by the
1483 * executor, so grab no new lock here.
1485 rel = heap_open(event->dte_relid, NoLock);
1488 * Allocate space to cache fmgr lookup info for triggers
1491 finfo = (FmgrInfo *)
1492 palloc(rel->trigdesc->numtriggers * sizeof(FmgrInfo));
1494 rel->trigdesc->numtriggers * sizeof(FmgrInfo));
1497 DeferredTriggerExecute(event, i, rel, finfo,
1500 event->dte_item[i].dti_state |= TRIGGER_DEFERRED_DONE;
1501 } /* end loop over items within event */
1505 * If it's now completely done, throw it away.
1507 * NB: it's possible the trigger calls above added more events to the
1508 * queue, or that calls we will do later will want to add more,
1509 * so we have to be careful about maintaining list validity here.
1511 next_event = event->dte_next;
1513 if (still_deferred_ones)
1515 /* Not done, keep in list */
1523 /* delink it from list and free it */
1525 prev_event->dte_next = next_event;
1527 deftrig_events = next_event;
1533 * We will clean up later, but just for paranoia's sake,
1534 * mark the event done.
1536 event->dte_event |= TRIGGER_DEFERRED_DONE;
1543 /* Update list tail pointer in case we just deleted tail event */
1544 deftrig_event_tail = prev_event;
1546 /* Release working resources */
1548 heap_close(rel, NoLock);
1551 MemoryContextDelete(per_tuple_context);
1556 * DeferredTriggerInit()
1558 * Initialize the deferred trigger mechanism. This is called during
1559 * backend startup and is guaranteed to be before the first of all
1564 DeferredTriggerInit(void)
1567 * Since this context will never be reset, give it a minsize of 0.
1568 * This avoids using any memory if the session never stores anything.
1570 deftrig_gcxt = AllocSetContextCreate(TopMemoryContext,
1571 "DeferredTriggerSession",
1573 ALLOCSET_DEFAULT_INITSIZE,
1574 ALLOCSET_DEFAULT_MAXSIZE);
1579 * DeferredTriggerBeginXact()
1581 * Called at transaction start (either BEGIN or implicit for single
1582 * statement outside of transaction block).
1586 DeferredTriggerBeginXact(void)
1588 MemoryContext oldcxt;
1590 DeferredTriggerStatus dflstat;
1591 DeferredTriggerStatus stat;
1593 if (deftrig_cxt != NULL)
1595 "DeferredTriggerBeginXact() called while inside transaction");
1598 * Create the per transaction memory context and copy all states from
1599 * the per session context to here. Set the minsize to 0 to avoid
1600 * wasting memory if there is no deferred trigger data.
1602 deftrig_cxt = AllocSetContextCreate(TopTransactionContext,
1603 "DeferredTriggerXact",
1605 ALLOCSET_DEFAULT_INITSIZE,
1606 ALLOCSET_DEFAULT_MAXSIZE);
1607 oldcxt = MemoryContextSwitchTo(deftrig_cxt);
1609 deftrig_all_isset = deftrig_dfl_all_isset;
1610 deftrig_all_isdeferred = deftrig_dfl_all_isdeferred;
1612 deftrig_trigstates = NIL;
1613 foreach(l, deftrig_dfl_trigstates)
1615 dflstat = (DeferredTriggerStatus) lfirst(l);
1616 stat = (DeferredTriggerStatus)
1617 palloc(sizeof(DeferredTriggerStatusData));
1619 stat->dts_tgoid = dflstat->dts_tgoid;
1620 stat->dts_tgisdeferred = dflstat->dts_tgisdeferred;
1622 deftrig_trigstates = lappend(deftrig_trigstates, stat);
1625 MemoryContextSwitchTo(oldcxt);
1627 deftrig_events = NULL;
1628 deftrig_event_tail = NULL;
1633 * DeferredTriggerEndQuery()
1635 * Called after one query sent down by the user has completely been
1636 * processed. At this time we invoke all outstanding IMMEDIATE triggers.
1640 DeferredTriggerEndQuery(void)
1643 * Ignore call if we aren't in a transaction.
1645 if (deftrig_cxt == NULL)
1648 deferredTriggerInvokeEvents(true);
1653 * DeferredTriggerEndXact()
1655 * Called just before the current transaction is committed. At this
1656 * time we invoke all DEFERRED triggers and tidy up.
1660 DeferredTriggerEndXact(void)
1663 * Ignore call if we aren't in a transaction.
1665 if (deftrig_cxt == NULL)
1668 deferredTriggerInvokeEvents(false);
1670 MemoryContextDelete(deftrig_cxt);
1676 * DeferredTriggerAbortXact()
1678 * The current transaction has entered the abort state.
1679 * All outstanding triggers are canceled so we simply throw
1680 * away anything we know.
1684 DeferredTriggerAbortXact(void)
1687 * Ignore call if we aren't in a transaction.
1689 if (deftrig_cxt == NULL)
1692 MemoryContextDelete(deftrig_cxt);
1698 * DeferredTriggerSetState()
1700 * Called for the users SET CONSTRAINTS ... utility command.
1704 DeferredTriggerSetState(ConstraintsSetStmt *stmt)
1710 MemoryContext oldcxt;
1712 DeferredTriggerStatus state;
1715 * Handle SET CONSTRAINTS ALL ...
1717 if (stmt->constraints == NIL)
1719 if (!IsTransactionBlock())
1722 * ... outside of a transaction block
1724 * Drop all information about individual trigger states per
1727 l = deftrig_dfl_trigstates;
1730 List *next = lnext(l);
1736 deftrig_dfl_trigstates = NIL;
1739 * Set the session ALL state to known.
1741 deftrig_dfl_all_isset = true;
1742 deftrig_dfl_all_isdeferred = stmt->deferred;
1749 * ... inside of a transaction block
1751 * Drop all information about individual trigger states per
1754 l = deftrig_trigstates;
1757 List *next = lnext(l);
1763 deftrig_trigstates = NIL;
1766 * Set the per transaction ALL state to known.
1768 deftrig_all_isset = true;
1769 deftrig_all_isdeferred = stmt->deferred;
1776 * Handle SET CONSTRAINTS constraint-name [, ...]
1777 * First lookup all trigger Oid's for the constraint names.
1780 tgrel = heap_openr(TriggerRelationName, AccessShareLock);
1782 foreach(l, stmt->constraints)
1784 char *cname = strVal(lfirst(l));
1790 * Check that only named constraints are set explicitly
1792 if (strlen(cname) == 0)
1793 elog(ERROR, "unnamed constraints cannot be set explicitly");
1796 * Setup to scan pg_trigger by tgconstrname ...
1798 ScanKeyEntryInitialize(&skey,
1800 (AttrNumber) Anum_pg_trigger_tgconstrname,
1801 (RegProcedure) F_NAMEEQ,
1802 PointerGetDatum(cname));
1804 tgscan = systable_beginscan(tgrel, TriggerConstrNameIndex, true,
1805 SnapshotNow, 1, &skey);
1808 * ... and search for the constraint trigger row
1812 while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
1814 Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
1818 * If we found some, check that they fit the deferrability but
1819 * skip ON <event> RESTRICT ones, since they are silently
1822 if (stmt->deferred && !pg_trigger->tgdeferrable &&
1823 pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_UPD &&
1824 pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_DEL)
1825 elog(ERROR, "Constraint '%s' is not deferrable",
1828 constr_oid = htup->t_data->t_oid;
1829 loid = lappendi(loid, constr_oid);
1833 systable_endscan(tgscan);
1839 elog(ERROR, "Constraint '%s' does not exist", cname);
1841 heap_close(tgrel, AccessShareLock);
1843 if (!IsTransactionBlock())
1846 * Outside of a transaction block set the trigger states of
1847 * individual triggers on session level.
1849 oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
1854 foreach(ls, deftrig_dfl_trigstates)
1856 state = (DeferredTriggerStatus) lfirst(ls);
1857 if (state->dts_tgoid == (Oid) lfirsti(l))
1859 state->dts_tgisdeferred = stmt->deferred;
1866 state = (DeferredTriggerStatus)
1867 palloc(sizeof(DeferredTriggerStatusData));
1868 state->dts_tgoid = (Oid) lfirsti(l);
1869 state->dts_tgisdeferred = stmt->deferred;
1871 deftrig_dfl_trigstates =
1872 lappend(deftrig_dfl_trigstates, state);
1876 MemoryContextSwitchTo(oldcxt);
1883 * Inside of a transaction block set the trigger states of
1884 * individual triggers on transaction level.
1886 oldcxt = MemoryContextSwitchTo(deftrig_cxt);
1891 foreach(ls, deftrig_trigstates)
1893 state = (DeferredTriggerStatus) lfirst(ls);
1894 if (state->dts_tgoid == (Oid) lfirsti(l))
1896 state->dts_tgisdeferred = stmt->deferred;
1903 state = (DeferredTriggerStatus)
1904 palloc(sizeof(DeferredTriggerStatusData));
1905 state->dts_tgoid = (Oid) lfirsti(l);
1906 state->dts_tgisdeferred = stmt->deferred;
1908 deftrig_trigstates =
1909 lappend(deftrig_trigstates, state);
1913 MemoryContextSwitchTo(oldcxt);
1921 * DeferredTriggerSaveEvent()
1923 * Called by ExecAR...Triggers() to add the event to the queue.
1925 * NOTE: should be called only if we've determined that an event must
1926 * be added to the queue.
1930 DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
1931 HeapTuple oldtup, HeapTuple newtup)
1933 Relation rel = relinfo->ri_RelationDesc;
1934 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
1935 MemoryContext oldcxt;
1936 DeferredTriggerEvent new_event;
1941 ItemPointerData oldctid;
1942 ItemPointerData newctid;
1943 TriggerData LocTriggerData;
1945 if (deftrig_cxt == NULL)
1947 "DeferredTriggerSaveEvent() called outside of transaction");
1950 * Get the CTID's of OLD and NEW
1953 ItemPointerCopy(&(oldtup->t_self), &(oldctid));
1955 ItemPointerSetInvalid(&(oldctid));
1957 ItemPointerCopy(&(newtup->t_self), &(newctid));
1959 ItemPointerSetInvalid(&(newctid));
1962 * Create a new event
1964 oldcxt = MemoryContextSwitchTo(deftrig_cxt);
1966 ntriggers = trigdesc->n_after_row[event];
1967 tgindx = trigdesc->tg_after_row[event];
1968 new_size = offsetof(DeferredTriggerEventData, dte_item[0]) +
1969 ntriggers * sizeof(DeferredTriggerEventItem);
1971 new_event = (DeferredTriggerEvent) palloc(new_size);
1972 new_event->dte_next = NULL;
1973 new_event->dte_event = event & TRIGGER_EVENT_OPMASK;
1974 new_event->dte_relid = rel->rd_id;
1975 ItemPointerCopy(&oldctid, &(new_event->dte_oldctid));
1976 ItemPointerCopy(&newctid, &(new_event->dte_newctid));
1977 new_event->dte_n_items = ntriggers;
1978 for (i = 0; i < ntriggers; i++)
1980 Trigger *trigger = &trigdesc->triggers[tgindx[i]];
1982 new_event->dte_item[i].dti_tgoid = trigger->tgoid;
1983 new_event->dte_item[i].dti_state =
1984 ((trigger->tgdeferrable) ?
1985 TRIGGER_DEFERRED_DEFERRABLE : 0) |
1986 ((trigger->tginitdeferred) ?
1987 TRIGGER_DEFERRED_INITDEFERRED : 0) |
1988 ((trigdesc->n_before_row[event] > 0) ?
1989 TRIGGER_DEFERRED_HAS_BEFORE : 0);
1992 MemoryContextSwitchTo(oldcxt);
1994 switch (event & TRIGGER_EVENT_OPMASK)
1996 case TRIGGER_EVENT_INSERT:
2000 case TRIGGER_EVENT_UPDATE:
2002 * Check if one of the referenced keys is changed.
2004 for (i = 0; i < ntriggers; i++)
2006 Trigger *trigger = &trigdesc->triggers[tgindx[i]];
2011 * We are interested in RI_FKEY triggers only.
2013 switch (trigger->tgfoid)
2015 case F_RI_FKEY_NOACTION_UPD:
2016 case F_RI_FKEY_CASCADE_UPD:
2017 case F_RI_FKEY_RESTRICT_UPD:
2018 case F_RI_FKEY_SETNULL_UPD:
2019 case F_RI_FKEY_SETDEFAULT_UPD:
2020 is_ri_trigger = true;
2024 is_ri_trigger = false;
2030 LocTriggerData.type = T_TriggerData;
2031 LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE;
2032 LocTriggerData.tg_relation = rel;
2033 LocTriggerData.tg_trigtuple = oldtup;
2034 LocTriggerData.tg_newtuple = newtup;
2035 LocTriggerData.tg_trigger = trigger;
2037 key_unchanged = RI_FKey_keyequal_upd(&LocTriggerData);
2042 * The key hasn't changed, so no need later to invoke
2043 * the trigger at all.
2045 new_event->dte_item[i].dti_state |= TRIGGER_DEFERRED_DONE;
2051 case TRIGGER_EVENT_DELETE:
2057 * Add the new event to the queue.
2059 deferredTriggerAddEvent(new_event);