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.99 2001/11/16 16:31:16 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 TRIGGER_CLEAR_TYPE(tgtype);
110 TRIGGER_SETT_BEFORE(tgtype);
112 TRIGGER_SETT_ROW(tgtype);
114 elog(ERROR, "CreateTrigger: STATEMENT triggers are unimplemented, yet");
116 for (i = 0; i < 3 && stmt->actions[i]; i++)
118 switch (stmt->actions[i])
121 if (TRIGGER_FOR_INSERT(tgtype))
122 elog(ERROR, "CreateTrigger: double INSERT event specified");
123 TRIGGER_SETT_INSERT(tgtype);
126 if (TRIGGER_FOR_DELETE(tgtype))
127 elog(ERROR, "CreateTrigger: double DELETE event specified");
128 TRIGGER_SETT_DELETE(tgtype);
131 if (TRIGGER_FOR_UPDATE(tgtype))
132 elog(ERROR, "CreateTrigger: double UPDATE event specified");
133 TRIGGER_SETT_UPDATE(tgtype);
136 elog(ERROR, "CreateTrigger: unknown event specified");
142 * Scan pg_trigger for existing triggers on relation. NOTE that this
143 * is cool only because we have AccessExclusiveLock on the relation,
144 * so the trigger set won't be changing underneath us.
146 tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
147 ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
149 ObjectIdGetDatum(RelationGetRelid(rel)));
150 tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
151 while (HeapTupleIsValid(tuple = heap_getnext(tgscan, 0)))
153 Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
155 if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
156 elog(ERROR, "CreateTrigger: trigger %s already defined on relation %s",
157 stmt->trigname, stmt->relname);
160 heap_endscan(tgscan);
163 * Find and validate the trigger function.
165 MemSet(fargtypes, 0, FUNC_MAX_ARGS * sizeof(Oid));
166 tuple = SearchSysCache(PROCNAME,
167 PointerGetDatum(stmt->funcname),
169 PointerGetDatum(fargtypes),
171 if (!HeapTupleIsValid(tuple))
172 elog(ERROR, "CreateTrigger: function %s() does not exist",
174 if (((Form_pg_proc) GETSTRUCT(tuple))->prorettype != 0)
175 elog(ERROR, "CreateTrigger: function %s() must return OPAQUE",
177 funcoid = tuple->t_data->t_oid;
178 funclang = ((Form_pg_proc) GETSTRUCT(tuple))->prolang;
179 ReleaseSysCache(tuple);
181 if (funclang != ClanguageId && funclang != INTERNALlanguageId)
185 langTup = SearchSysCache(LANGOID,
186 ObjectIdGetDatum(funclang),
188 if (!HeapTupleIsValid(langTup))
189 elog(ERROR, "CreateTrigger: cache lookup for language %u failed",
191 if (((Form_pg_language) GETSTRUCT(langTup))->lanispl == false)
192 elog(ERROR, "CreateTrigger: only internal, C and PL functions are supported");
193 ReleaseSysCache(langTup);
197 * Build the new pg_trigger tuple.
199 MemSet(nulls, ' ', Natts_pg_trigger * sizeof(char));
201 values[Anum_pg_trigger_tgrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
202 values[Anum_pg_trigger_tgname - 1] = DirectFunctionCall1(namein,
203 CStringGetDatum(stmt->trigname));
204 values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
205 values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
206 values[Anum_pg_trigger_tgenabled - 1] = BoolGetDatum(true);
207 values[Anum_pg_trigger_tgisconstraint - 1] = BoolGetDatum(stmt->isconstraint);
208 values[Anum_pg_trigger_tgconstrname - 1] = PointerGetDatum(constrname);
209 values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
210 values[Anum_pg_trigger_tgdeferrable - 1] = BoolGetDatum(stmt->deferrable);
211 values[Anum_pg_trigger_tginitdeferred - 1] = BoolGetDatum(stmt->initdeferred);
217 int16 nargs = length(stmt->args);
220 foreach(le, stmt->args)
222 char *ar = ((Value *) lfirst(le))->val.str;
224 len += strlen(ar) + 4;
231 args = (char *) palloc(len + 1);
233 foreach(le, stmt->args)
235 char *s = ((Value *) lfirst(le))->val.str;
236 char *d = args + strlen(args);
246 values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
247 values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain,
248 CStringGetDatum(args));
252 values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
253 values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain,
254 CStringGetDatum(""));
256 MemSet(tgattr, 0, FUNC_MAX_ARGS * sizeof(int16));
257 values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
259 tuple = heap_formtuple(tgrel->rd_att, values, nulls);
262 * Insert tuple into pg_trigger.
264 heap_insert(tgrel, tuple);
265 CatalogOpenIndices(Num_pg_trigger_indices, Name_pg_trigger_indices, idescs);
266 CatalogIndexInsert(idescs, Num_pg_trigger_indices, tgrel, tuple);
267 CatalogCloseIndices(Num_pg_trigger_indices, idescs);
268 heap_freetuple(tuple);
269 heap_close(tgrel, RowExclusiveLock);
271 pfree(DatumGetPointer(values[Anum_pg_trigger_tgname - 1]));
272 pfree(DatumGetPointer(values[Anum_pg_trigger_tgargs - 1]));
275 * Update relation's pg_class entry. Crucial side-effect: other
276 * backends (and this one too!) are sent SI message to make them
277 * rebuild relcache entries.
279 pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
280 tuple = SearchSysCacheCopy(RELNAME,
281 PointerGetDatum(stmt->relname),
283 if (!HeapTupleIsValid(tuple))
284 elog(ERROR, "CreateTrigger: relation %s not found in pg_class",
287 ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found + 1;
288 simple_heap_update(pgrel, &tuple->t_self, tuple);
289 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
290 CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
291 CatalogCloseIndices(Num_pg_class_indices, ridescs);
292 heap_freetuple(tuple);
293 heap_close(pgrel, RowExclusiveLock);
296 * We used to try to update the rel's relcache entry here, but that's
297 * fairly pointless since it will happen as a byproduct of the
298 * upcoming CommandCounterIncrement...
301 /* Keep lock on target rel until end of xact */
302 heap_close(rel, NoLock);
306 DropTrigger(DropTrigStmt *stmt)
314 Relation ridescs[Num_pg_class_indices];
318 if (!pg_ownercheck(GetUserId(), stmt->relname, RELNAME))
319 elog(ERROR, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
321 rel = heap_openr(stmt->relname, AccessExclusiveLock);
324 * Search pg_trigger, delete target trigger, count remaining triggers
325 * for relation. Note this is OK only because we have
326 * AccessExclusiveLock on the rel, so no one else is creating/deleting
327 * triggers on this rel at the same time.
329 tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
330 ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
332 ObjectIdGetDatum(RelationGetRelid(rel)));
333 tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
334 while (HeapTupleIsValid(tuple = heap_getnext(tgscan, 0)))
336 Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
338 if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
340 /* Delete any comments associated with this trigger */
341 DeleteComments(tuple->t_data->t_oid, RelationGetRelid(tgrel));
343 simple_heap_delete(tgrel, &tuple->t_self);
350 elog(ERROR, "DropTrigger: there is no trigger %s on relation %s",
351 stmt->trigname, stmt->relname);
353 elog(NOTICE, "DropTrigger: found (and deleted) %d triggers %s on relation %s",
354 tgfound, stmt->trigname, stmt->relname);
355 heap_endscan(tgscan);
356 heap_close(tgrel, RowExclusiveLock);
359 * Update relation's pg_class entry. Crucial side-effect: other
360 * backends (and this one too!) are sent SI message to make them
361 * rebuild relcache entries.
363 pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
364 tuple = SearchSysCacheCopy(RELNAME,
365 PointerGetDatum(stmt->relname),
367 if (!HeapTupleIsValid(tuple))
368 elog(ERROR, "DropTrigger: relation %s not found in pg_class",
371 ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found;
372 simple_heap_update(pgrel, &tuple->t_self, tuple);
373 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
374 CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
375 CatalogCloseIndices(Num_pg_class_indices, ridescs);
376 heap_freetuple(tuple);
377 heap_close(pgrel, RowExclusiveLock);
380 * We used to try to update the rel's relcache entry here, but that's
381 * fairly pointless since it will happen as a byproduct of the
382 * upcoming CommandCounterIncrement...
385 /* Keep lock on target rel until end of xact */
386 heap_close(rel, NoLock);
390 * Remove all triggers for a relation that's being deleted.
393 RelationRemoveTriggers(Relation rel)
401 tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
402 ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
404 ObjectIdGetDatum(RelationGetRelid(rel)));
406 tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
408 while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0)))
410 /* Delete any comments associated with this trigger */
411 DeleteComments(tup->t_data->t_oid, RelationGetRelid(tgrel));
413 simple_heap_delete(tgrel, &tup->t_self);
418 heap_endscan(tgscan);
421 * If we deleted any triggers, must update pg_class entry and advance
422 * command counter to make the updated entry visible. This is fairly
423 * annoying, since we'e just going to drop the durn thing later, but
424 * it's necessary to have a consistent state in case we do
425 * CommandCounterIncrement() below --- if RelationBuildTriggers()
426 * runs, it will complain otherwise. Perhaps RelationBuildTriggers()
427 * shouldn't be so picky...
432 Relation ridescs[Num_pg_class_indices];
434 pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
435 tup = SearchSysCacheCopy(RELOID,
436 RelationGetRelid(rel),
438 if (!HeapTupleIsValid(tup))
439 elog(ERROR, "RelationRemoveTriggers: relation %u not found in pg_class",
440 RelationGetRelid(rel));
442 ((Form_pg_class) GETSTRUCT(tup))->reltriggers = 0;
443 simple_heap_update(pgrel, &tup->t_self, tup);
444 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
445 CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tup);
446 CatalogCloseIndices(Num_pg_class_indices, ridescs);
448 heap_close(pgrel, RowExclusiveLock);
449 CommandCounterIncrement();
453 * Also drop all constraint triggers referencing this relation
455 ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgconstrrelid,
457 ObjectIdGetDatum(RelationGetRelid(rel)));
459 tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
460 while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0)))
462 Form_pg_trigger pg_trigger;
466 pg_trigger = (Form_pg_trigger) GETSTRUCT(tup);
468 stmt.trigname = pstrdup(NameStr(pg_trigger->tgname));
470 /* May as well grab AccessExclusiveLock, since DropTrigger will. */
471 refrel = heap_open(pg_trigger->tgrelid, AccessExclusiveLock);
472 stmt.relname = pstrdup(RelationGetRelationName(refrel));
473 heap_close(refrel, NoLock);
475 elog(NOTICE, "DROP TABLE implicitly drops referential integrity trigger from table \"%s\"", stmt.relname);
480 * Need to do a command counter increment here to show up new
481 * pg_class.reltriggers in the next loop iteration (in case there
482 * are multiple referential integrity action triggers for the same
483 * FK table defined on the PK table).
485 CommandCounterIncrement();
488 pfree(stmt.trigname);
490 heap_endscan(tgscan);
492 heap_close(tgrel, RowExclusiveLock);
496 * Build trigger data to attach to the given relcache entry.
498 * Note that trigger data must be allocated in CacheMemoryContext
499 * to ensure it survives as long as the relcache entry. But we
500 * are probably running in a less long-lived working context.
503 RelationBuildTriggers(Relation relation)
505 TriggerDesc *trigdesc;
506 int ntrigs = relation->rd_rel->reltriggers;
507 Trigger *triggers = NULL;
510 Form_pg_trigger pg_trigger;
511 Relation irel = (Relation) NULL;
514 IndexScanDesc sd = (IndexScanDesc) NULL;
515 HeapScanDesc tgscan = (HeapScanDesc) NULL;
517 RetrieveIndexResult indexRes;
524 trigdesc = (TriggerDesc *) MemoryContextAlloc(CacheMemoryContext,
525 sizeof(TriggerDesc));
526 MemSet(trigdesc, 0, sizeof(TriggerDesc));
528 ScanKeyEntryInitialize(&skey,
531 (RegProcedure) F_OIDEQ,
532 ObjectIdGetDatum(RelationGetRelid(relation)));
534 tgrel = heap_openr(TriggerRelationName, AccessShareLock);
535 hasindex = (tgrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
538 irel = index_openr(TriggerRelidIndex);
539 sd = index_beginscan(irel, false, 1, &skey);
542 tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &skey);
548 indexRes = index_getnext(sd, ForwardScanDirection);
552 tuple.t_self = indexRes->heap_iptr;
553 heap_fetch(tgrel, SnapshotNow, &tuple, &buffer, sd);
561 htup = heap_getnext(tgscan, 0);
562 if (!HeapTupleIsValid(htup))
566 elog(ERROR, "RelationBuildTriggers: unexpected record found for rel %s",
567 RelationGetRelationName(relation));
569 pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
571 if (triggers == NULL)
572 triggers = (Trigger *) MemoryContextAlloc(CacheMemoryContext,
575 triggers = (Trigger *) repalloc(triggers,
576 (found + 1) * sizeof(Trigger));
577 build = &(triggers[found]);
579 build->tgoid = htup->t_data->t_oid;
580 build->tgname = MemoryContextStrdup(CacheMemoryContext,
581 DatumGetCString(DirectFunctionCall1(nameout,
582 NameGetDatum(&pg_trigger->tgname))));
583 build->tgfoid = pg_trigger->tgfoid;
584 build->tgtype = pg_trigger->tgtype;
585 build->tgenabled = pg_trigger->tgenabled;
586 build->tgisconstraint = pg_trigger->tgisconstraint;
587 build->tgdeferrable = pg_trigger->tgdeferrable;
588 build->tginitdeferred = pg_trigger->tginitdeferred;
589 build->tgnargs = pg_trigger->tgnargs;
590 memcpy(build->tgattr, &(pg_trigger->tgattr),
591 FUNC_MAX_ARGS * sizeof(int16));
592 if (build->tgnargs > 0)
597 val = (struct varlena *) fastgetattr(htup,
598 Anum_pg_trigger_tgargs,
599 tgrel->rd_att, &isnull);
601 elog(ERROR, "RelationBuildTriggers: tgargs IS NULL for rel %s",
602 RelationGetRelationName(relation));
603 p = (char *) VARDATA(val);
604 build->tgargs = (char **)
605 MemoryContextAlloc(CacheMemoryContext,
606 build->tgnargs * sizeof(char *));
607 for (i = 0; i < build->tgnargs; i++)
609 build->tgargs[i] = MemoryContextStrdup(CacheMemoryContext,
615 build->tgargs = NULL;
619 ReleaseBuffer(buffer);
623 elog(ERROR, "RelationBuildTriggers: %d record(s) not found for rel %s",
625 RelationGetRelationName(relation));
633 heap_endscan(tgscan);
634 heap_close(tgrel, AccessShareLock);
637 trigdesc->triggers = triggers;
638 trigdesc->numtriggers = ntrigs;
639 for (found = 0; found < ntrigs; found++)
640 InsertTrigger(trigdesc, &(triggers[found]), found);
642 relation->trigdesc = trigdesc;
645 /* Insert the given trigger into the appropriate index list(s) for it */
647 InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx)
653 if (TRIGGER_FOR_ROW(trigger->tgtype))
656 if (TRIGGER_FOR_BEFORE(trigger->tgtype))
658 n = trigdesc->n_before_row;
659 t = trigdesc->tg_before_row;
663 n = trigdesc->n_after_row;
664 t = trigdesc->tg_after_row;
669 /* STATEMENT trigger */
670 if (TRIGGER_FOR_BEFORE(trigger->tgtype))
672 n = trigdesc->n_before_statement;
673 t = trigdesc->tg_before_statement;
677 n = trigdesc->n_after_statement;
678 t = trigdesc->tg_after_statement;
682 if (TRIGGER_FOR_INSERT(trigger->tgtype))
684 tp = &(t[TRIGGER_EVENT_INSERT]);
686 *tp = (int *) MemoryContextAlloc(CacheMemoryContext,
689 *tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
691 (*tp)[n[TRIGGER_EVENT_INSERT]] = indx;
692 (n[TRIGGER_EVENT_INSERT])++;
695 if (TRIGGER_FOR_DELETE(trigger->tgtype))
697 tp = &(t[TRIGGER_EVENT_DELETE]);
699 *tp = (int *) MemoryContextAlloc(CacheMemoryContext,
702 *tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
704 (*tp)[n[TRIGGER_EVENT_DELETE]] = indx;
705 (n[TRIGGER_EVENT_DELETE])++;
708 if (TRIGGER_FOR_UPDATE(trigger->tgtype))
710 tp = &(t[TRIGGER_EVENT_UPDATE]);
712 *tp = (int *) MemoryContextAlloc(CacheMemoryContext,
715 *tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
717 (*tp)[n[TRIGGER_EVENT_UPDATE]] = indx;
718 (n[TRIGGER_EVENT_UPDATE])++;
723 FreeTriggerDesc(TriggerDesc *trigdesc)
729 if (trigdesc == NULL)
732 t = trigdesc->tg_before_statement;
733 for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
736 t = trigdesc->tg_before_row;
737 for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
740 t = trigdesc->tg_after_row;
741 for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
744 t = trigdesc->tg_after_statement;
745 for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
749 trigger = trigdesc->triggers;
750 for (i = 0; i < trigdesc->numtriggers; i++)
752 pfree(trigger->tgname);
753 if (trigger->tgnargs > 0)
755 while (--(trigger->tgnargs) >= 0)
756 pfree(trigger->tgargs[trigger->tgnargs]);
757 pfree(trigger->tgargs);
761 pfree(trigdesc->triggers);
766 equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
772 * We need not examine the "index" data, just the trigger array
773 * itself; if we have the same triggers with the same types, the
774 * derived index data should match.
776 if (trigdesc1 != NULL)
778 if (trigdesc2 == NULL)
780 if (trigdesc1->numtriggers != trigdesc2->numtriggers)
782 for (i = 0; i < trigdesc1->numtriggers; i++)
784 Trigger *trig1 = trigdesc1->triggers + i;
785 Trigger *trig2 = NULL;
788 * We can't assume that the triggers are always read from
789 * pg_trigger in the same order; so use the trigger OIDs to
790 * identify the triggers to compare. (We assume here that the
791 * same OID won't appear twice in either trigger set.)
793 for (j = 0; j < trigdesc2->numtriggers; j++)
795 trig2 = trigdesc2->triggers + i;
796 if (trig1->tgoid == trig2->tgoid)
799 if (j >= trigdesc2->numtriggers)
801 if (strcmp(trig1->tgname, trig2->tgname) != 0)
803 if (trig1->tgfoid != trig2->tgfoid)
805 if (trig1->tgtype != trig2->tgtype)
807 if (trig1->tgenabled != trig2->tgenabled)
809 if (trig1->tgisconstraint != trig2->tgisconstraint)
811 if (trig1->tgdeferrable != trig2->tgdeferrable)
813 if (trig1->tginitdeferred != trig2->tginitdeferred)
815 if (trig1->tgnargs != trig2->tgnargs)
817 if (memcmp(trig1->tgattr, trig2->tgattr,
818 sizeof(trig1->tgattr)) != 0)
820 for (j = 0; j < trig1->tgnargs; j++)
821 if (strcmp(trig1->tgargs[j], trig2->tgargs[j]) != 0)
825 else if (trigdesc2 != NULL)
831 * Call a trigger function.
833 * trigdata: trigger descriptor.
834 * finfo: possibly-cached call info for the function.
835 * per_tuple_context: memory context to execute the function in.
837 * Returns the tuple (or NULL) as returned by the function.
840 ExecCallTriggerFunc(TriggerData *trigdata,
842 MemoryContext per_tuple_context)
844 FunctionCallInfoData fcinfo;
846 MemoryContext oldContext;
849 * We cache fmgr lookup info, to avoid making the lookup again on each
852 if (finfo->fn_oid == InvalidOid)
853 fmgr_info(trigdata->tg_trigger->tgfoid, finfo);
855 Assert(finfo->fn_oid == trigdata->tg_trigger->tgfoid);
858 * Do the function evaluation in the per-tuple memory context, so that
859 * leaked memory will be reclaimed once per tuple. Note in particular
860 * that any new tuple created by the trigger function will live till
861 * the end of the tuple cycle.
863 oldContext = MemoryContextSwitchTo(per_tuple_context);
866 * Call the function, passing no arguments but setting a context.
868 MemSet(&fcinfo, 0, sizeof(fcinfo));
870 fcinfo.flinfo = finfo;
871 fcinfo.context = (Node *) trigdata;
873 result = FunctionCallInvoke(&fcinfo);
875 MemoryContextSwitchTo(oldContext);
878 * Trigger protocol allows function to return a null pointer, but NOT
879 * to set the isnull result flag.
882 elog(ERROR, "ExecCallTriggerFunc: function %u returned NULL",
883 fcinfo.flinfo->fn_oid);
885 return (HeapTuple) DatumGetPointer(result);
889 ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
892 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
893 int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
894 int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
895 HeapTuple newtuple = trigtuple;
897 TriggerData LocTriggerData;
900 /* Allocate cache space for fmgr lookup info, if not done yet */
901 if (relinfo->ri_TrigFunctions == NULL)
903 relinfo->ri_TrigFunctions = (FmgrInfo *)
904 palloc(trigdesc->numtriggers * sizeof(FmgrInfo));
905 MemSet(relinfo->ri_TrigFunctions, 0,
906 trigdesc->numtriggers * sizeof(FmgrInfo));
909 LocTriggerData.type = T_TriggerData;
910 LocTriggerData.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
911 LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
912 LocTriggerData.tg_newtuple = NULL;
913 for (i = 0; i < ntrigs; i++)
915 Trigger *trigger = &trigdesc->triggers[tgindx[i]];
917 if (!trigger->tgenabled)
919 LocTriggerData.tg_trigtuple = oldtuple = newtuple;
920 LocTriggerData.tg_trigger = trigger;
921 newtuple = ExecCallTriggerFunc(&LocTriggerData,
922 relinfo->ri_TrigFunctions + tgindx[i],
923 GetPerTupleMemoryContext(estate));
924 if (oldtuple != newtuple && oldtuple != trigtuple)
925 heap_freetuple(oldtuple);
926 if (newtuple == NULL)
933 ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo,
936 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
938 if (trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0)
939 DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_INSERT,
944 ExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
947 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
948 int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
949 int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
950 TriggerData LocTriggerData;
952 HeapTuple newtuple = NULL;
953 TupleTableSlot *newSlot;
956 trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
957 if (trigtuple == NULL)
960 /* Allocate cache space for fmgr lookup info, if not done yet */
961 if (relinfo->ri_TrigFunctions == NULL)
963 relinfo->ri_TrigFunctions = (FmgrInfo *)
964 palloc(trigdesc->numtriggers * sizeof(FmgrInfo));
965 MemSet(relinfo->ri_TrigFunctions, 0,
966 trigdesc->numtriggers * sizeof(FmgrInfo));
969 LocTriggerData.type = T_TriggerData;
970 LocTriggerData.tg_event = TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
971 LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
972 LocTriggerData.tg_newtuple = NULL;
973 for (i = 0; i < ntrigs; i++)
975 Trigger *trigger = &trigdesc->triggers[tgindx[i]];
977 if (!trigger->tgenabled)
979 LocTriggerData.tg_trigtuple = trigtuple;
980 LocTriggerData.tg_trigger = trigger;
981 newtuple = ExecCallTriggerFunc(&LocTriggerData,
982 relinfo->ri_TrigFunctions + tgindx[i],
983 GetPerTupleMemoryContext(estate));
984 if (newtuple == NULL)
986 if (newtuple != trigtuple)
987 heap_freetuple(newtuple);
989 heap_freetuple(trigtuple);
991 return (newtuple == NULL) ? false : true;
995 ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
998 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
1000 if (trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
1002 HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo,
1005 DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_DELETE,
1007 heap_freetuple(trigtuple);
1012 ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
1013 ItemPointer tupleid, HeapTuple newtuple)
1015 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
1016 int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
1017 int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
1018 TriggerData LocTriggerData;
1019 HeapTuple trigtuple;
1021 HeapTuple intuple = newtuple;
1022 TupleTableSlot *newSlot;
1025 trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
1026 if (trigtuple == NULL)
1030 * In READ COMMITTED isolevel it's possible that newtuple was changed
1031 * due to concurrent update.
1033 if (newSlot != NULL)
1034 intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot);
1036 /* Allocate cache space for fmgr lookup info, if not done yet */
1037 if (relinfo->ri_TrigFunctions == NULL)
1039 relinfo->ri_TrigFunctions = (FmgrInfo *)
1040 palloc(trigdesc->numtriggers * sizeof(FmgrInfo));
1041 MemSet(relinfo->ri_TrigFunctions, 0,
1042 trigdesc->numtriggers * sizeof(FmgrInfo));
1045 LocTriggerData.type = T_TriggerData;
1046 LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
1047 LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
1048 for (i = 0; i < ntrigs; i++)
1050 Trigger *trigger = &trigdesc->triggers[tgindx[i]];
1052 if (!trigger->tgenabled)
1054 LocTriggerData.tg_trigtuple = trigtuple;
1055 LocTriggerData.tg_newtuple = oldtuple = newtuple;
1056 LocTriggerData.tg_trigger = trigger;
1057 newtuple = ExecCallTriggerFunc(&LocTriggerData,
1058 relinfo->ri_TrigFunctions + tgindx[i],
1059 GetPerTupleMemoryContext(estate));
1060 if (oldtuple != newtuple && oldtuple != intuple)
1061 heap_freetuple(oldtuple);
1062 if (newtuple == NULL)
1065 heap_freetuple(trigtuple);
1070 ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
1071 ItemPointer tupleid, HeapTuple newtuple)
1073 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
1075 if (trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0)
1077 HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo,
1080 DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_UPDATE,
1081 trigtuple, newtuple);
1082 heap_freetuple(trigtuple);
1088 GetTupleForTrigger(EState *estate, ResultRelInfo *relinfo,
1089 ItemPointer tid, TupleTableSlot **newSlot)
1091 Relation relation = relinfo->ri_RelationDesc;
1092 HeapTupleData tuple;
1096 if (newSlot != NULL)
1101 * mark tuple for update
1104 tuple.t_self = *tid;
1106 test = heap_mark4update(relation, &tuple, &buffer);
1109 case HeapTupleSelfUpdated:
1110 ReleaseBuffer(buffer);
1113 case HeapTupleMayBeUpdated:
1116 case HeapTupleUpdated:
1117 ReleaseBuffer(buffer);
1118 if (XactIsoLevel == XACT_SERIALIZABLE)
1119 elog(ERROR, "Can't serialize access due to concurrent update");
1120 else if (!(ItemPointerEquals(&(tuple.t_self), tid)))
1122 TupleTableSlot *epqslot = EvalPlanQual(estate,
1123 relinfo->ri_RangeTableIndex,
1126 if (!(TupIsNull(epqslot)))
1128 *tid = tuple.t_self;
1135 * if tuple was deleted or PlanQual failed for updated
1136 * tuple - we have not process this tuple!
1141 ReleaseBuffer(buffer);
1142 elog(ERROR, "Unknown status %u from heap_mark4update", test);
1151 buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
1153 if (!BufferIsValid(buffer))
1154 elog(ERROR, "GetTupleForTrigger: failed ReadBuffer");
1156 dp = (PageHeader) BufferGetPage(buffer);
1157 lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
1159 Assert(ItemIdIsUsed(lp));
1161 tuple.t_datamcxt = NULL;
1162 tuple.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
1163 tuple.t_len = ItemIdGetLength(lp);
1164 tuple.t_self = *tid;
1167 result = heap_copytuple(&tuple);
1168 ReleaseBuffer(buffer);
1175 * Deferred trigger stuff
1181 * Internal data to the deferred trigger mechanism is held
1182 * during entire session in a global context created at startup and
1183 * over statements/commands in a separate context which
1184 * is created at transaction start and destroyed at transaction end.
1187 static MemoryContext deftrig_gcxt = NULL;
1188 static MemoryContext deftrig_cxt = NULL;
1191 * Global data that tells which triggers are actually in
1192 * state IMMEDIATE or DEFERRED.
1195 static bool deftrig_dfl_all_isset = false;
1196 static bool deftrig_dfl_all_isdeferred = false;
1197 static List *deftrig_dfl_trigstates = NIL;
1199 static bool deftrig_all_isset;
1200 static bool deftrig_all_isdeferred;
1201 static List *deftrig_trigstates;
1204 * The list of pending deferred trigger events during the current transaction.
1206 * deftrig_events is the head, deftrig_event_tail is the last entry.
1207 * Because this can grow pretty large, we don't use separate List nodes,
1208 * but instead thread the list through the dte_next fields of the member
1209 * nodes. Saves just a few bytes per entry, but that adds up.
1211 * XXX Need to be able to shove this data out to a file if it grows too
1215 static DeferredTriggerEvent deftrig_events;
1216 static DeferredTriggerEvent deftrig_event_tail;
1220 * deferredTriggerCheckState()
1222 * Returns true if the trigger identified by tgoid is actually
1223 * in state DEFERRED.
1227 deferredTriggerCheckState(Oid tgoid, int32 itemstate)
1229 MemoryContext oldcxt;
1231 DeferredTriggerStatus trigstate;
1234 * Not deferrable triggers (i.e. normal AFTER ROW triggers and
1235 * constraints declared NOT DEFERRABLE, the state is allways false.
1237 if ((itemstate & TRIGGER_DEFERRED_DEFERRABLE) == 0)
1241 * Lookup if we know an individual state for this trigger
1243 foreach(sl, deftrig_trigstates)
1245 trigstate = (DeferredTriggerStatus) lfirst(sl);
1246 if (trigstate->dts_tgoid == tgoid)
1247 return trigstate->dts_tgisdeferred;
1251 * No individual state known - so if the user issued a SET CONSTRAINT
1252 * ALL ..., we return that instead of the triggers default state.
1254 if (deftrig_all_isset)
1255 return deftrig_all_isdeferred;
1258 * No ALL state known either, remember the default state as the
1259 * current and return that.
1261 oldcxt = MemoryContextSwitchTo(deftrig_cxt);
1263 trigstate = (DeferredTriggerStatus)
1264 palloc(sizeof(DeferredTriggerStatusData));
1265 trigstate->dts_tgoid = tgoid;
1266 trigstate->dts_tgisdeferred =
1267 ((itemstate & TRIGGER_DEFERRED_INITDEFERRED) != 0);
1268 deftrig_trigstates = lappend(deftrig_trigstates, trigstate);
1270 MemoryContextSwitchTo(oldcxt);
1272 return trigstate->dts_tgisdeferred;
1277 * deferredTriggerAddEvent()
1279 * Add a new trigger event to the queue.
1283 deferredTriggerAddEvent(DeferredTriggerEvent event)
1286 * Since the event list could grow quite long, we keep track of the
1287 * list tail and append there, rather than just doing a stupid
1288 * "lappend". This avoids O(N^2) behavior for large numbers of events.
1290 event->dte_next = NULL;
1291 if (deftrig_event_tail == NULL)
1293 /* first list entry */
1294 deftrig_events = event;
1295 deftrig_event_tail = event;
1299 deftrig_event_tail->dte_next = event;
1300 deftrig_event_tail = event;
1306 * DeferredTriggerExecute()
1308 * Fetch the required tuples back from the heap and fire one
1309 * single trigger function.
1311 * Frequently, this will be fired many times in a row for triggers of
1312 * a single relation. Therefore, we cache the open relation and provide
1313 * fmgr lookup cache space at the caller level.
1315 * event: event currently being fired.
1316 * itemno: item within event currently being fired.
1317 * rel: open relation for event.
1318 * finfo: array of fmgr lookup cache entries (one per trigger of relation).
1319 * per_tuple_context: memory context to call trigger function in.
1323 DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
1324 Relation rel, FmgrInfo *finfo,
1325 MemoryContext per_tuple_context)
1327 Oid tgoid = event->dte_item[itemno].dti_tgoid;
1328 TriggerDesc *trigdesc = rel->trigdesc;
1329 TriggerData LocTriggerData;
1330 HeapTupleData oldtuple;
1331 HeapTupleData newtuple;
1338 * Fetch the required OLD and NEW tuples.
1340 if (ItemPointerIsValid(&(event->dte_oldctid)))
1342 ItemPointerCopy(&(event->dte_oldctid), &(oldtuple.t_self));
1343 heap_fetch(rel, SnapshotAny, &oldtuple, &oldbuffer, NULL);
1344 if (!oldtuple.t_data)
1345 elog(ERROR, "DeferredTriggerExecute: failed to fetch old tuple");
1348 if (ItemPointerIsValid(&(event->dte_newctid)))
1350 ItemPointerCopy(&(event->dte_newctid), &(newtuple.t_self));
1351 heap_fetch(rel, SnapshotAny, &newtuple, &newbuffer, NULL);
1352 if (!newtuple.t_data)
1353 elog(ERROR, "DeferredTriggerExecute: failed to fetch new tuple");
1357 * Setup the trigger information
1359 LocTriggerData.type = T_TriggerData;
1360 LocTriggerData.tg_event = (event->dte_event & TRIGGER_EVENT_OPMASK) |
1362 LocTriggerData.tg_relation = rel;
1364 LocTriggerData.tg_trigger = NULL;
1365 for (tgindx = 0; tgindx < trigdesc->numtriggers; tgindx++)
1367 if (trigdesc->triggers[tgindx].tgoid == tgoid)
1369 LocTriggerData.tg_trigger = &(trigdesc->triggers[tgindx]);
1373 if (LocTriggerData.tg_trigger == NULL)
1374 elog(ERROR, "DeferredTriggerExecute: can't find trigger %u", tgoid);
1376 switch (event->dte_event & TRIGGER_EVENT_OPMASK)
1378 case TRIGGER_EVENT_INSERT:
1379 LocTriggerData.tg_trigtuple = &newtuple;
1380 LocTriggerData.tg_newtuple = NULL;
1383 case TRIGGER_EVENT_UPDATE:
1384 LocTriggerData.tg_trigtuple = &oldtuple;
1385 LocTriggerData.tg_newtuple = &newtuple;
1388 case TRIGGER_EVENT_DELETE:
1389 LocTriggerData.tg_trigtuple = &oldtuple;
1390 LocTriggerData.tg_newtuple = NULL;
1395 * Call the trigger and throw away an eventually returned updated
1398 rettuple = ExecCallTriggerFunc(&LocTriggerData,
1401 if (rettuple != NULL && rettuple != &oldtuple && rettuple != &newtuple)
1402 heap_freetuple(rettuple);
1405 * Might have been a referential integrity constraint trigger. Reset
1406 * the snapshot overriding flag.
1408 ReferentialIntegritySnapshotOverride = false;
1413 if (ItemPointerIsValid(&(event->dte_oldctid)))
1414 ReleaseBuffer(oldbuffer);
1415 if (ItemPointerIsValid(&(event->dte_newctid)))
1416 ReleaseBuffer(newbuffer);
1421 * deferredTriggerInvokeEvents()
1423 * Scan the event queue for not yet invoked triggers. Check if they
1424 * should be invoked now and do so.
1428 deferredTriggerInvokeEvents(bool immediate_only)
1430 DeferredTriggerEvent event,
1432 MemoryContext per_tuple_context;
1433 Relation rel = NULL;
1434 FmgrInfo *finfo = NULL;
1437 * If immediate_only is true, we remove fully-processed events from
1438 * the event queue to recycle space. If immediate_only is false,
1439 * we are going to discard the whole event queue on return anyway,
1440 * so no need to bother with "retail" pfree's.
1442 * In a scenario with many commands in a transaction and many
1443 * deferred-to-end-of-transaction triggers, it could get annoying
1444 * to rescan all the deferred triggers at each command end.
1445 * To speed this up, we could remember the actual end of the queue at
1446 * EndQuery and examine only events that are newer. On state changes
1447 * we simply reset the saved position to the beginning of the queue
1448 * and process all events once with the new states.
1451 /* Make a per-tuple memory context for trigger function calls */
1453 AllocSetContextCreate(CurrentMemoryContext,
1454 "DeferredTriggerTupleContext",
1455 ALLOCSET_DEFAULT_MINSIZE,
1456 ALLOCSET_DEFAULT_INITSIZE,
1457 ALLOCSET_DEFAULT_MAXSIZE);
1459 event = deftrig_events;
1460 while (event != NULL)
1462 bool still_deferred_ones = false;
1463 DeferredTriggerEvent next_event;
1467 * Check if event is already completely done.
1469 if (! (event->dte_event & (TRIGGER_DEFERRED_DONE |
1470 TRIGGER_DEFERRED_CANCELED)))
1472 MemoryContextReset(per_tuple_context);
1475 * Check each trigger item in the event.
1477 for (i = 0; i < event->dte_n_items; i++)
1479 if (event->dte_item[i].dti_state & TRIGGER_DEFERRED_DONE)
1483 * This trigger item hasn't been called yet. Check if we
1484 * should call it now.
1486 if (immediate_only &&
1487 deferredTriggerCheckState(event->dte_item[i].dti_tgoid,
1488 event->dte_item[i].dti_state))
1490 still_deferred_ones = true;
1495 * So let's fire it... but first, open the correct relation
1496 * if this is not the same relation as before.
1498 if (rel == NULL || rel->rd_id != event->dte_relid)
1501 heap_close(rel, NoLock);
1506 * We assume that an appropriate lock is still held by the
1507 * executor, so grab no new lock here.
1509 rel = heap_open(event->dte_relid, NoLock);
1512 * Allocate space to cache fmgr lookup info for triggers
1515 finfo = (FmgrInfo *)
1516 palloc(rel->trigdesc->numtriggers * sizeof(FmgrInfo));
1518 rel->trigdesc->numtriggers * sizeof(FmgrInfo));
1521 DeferredTriggerExecute(event, i, rel, finfo,
1524 event->dte_item[i].dti_state |= TRIGGER_DEFERRED_DONE;
1525 } /* end loop over items within event */
1529 * If it's now completely done, throw it away.
1531 * NB: it's possible the trigger calls above added more events to the
1532 * queue, or that calls we will do later will want to add more,
1533 * so we have to be careful about maintaining list validity here.
1535 next_event = event->dte_next;
1537 if (still_deferred_ones)
1539 /* Not done, keep in list */
1547 /* delink it from list and free it */
1549 prev_event->dte_next = next_event;
1551 deftrig_events = next_event;
1557 * We will clean up later, but just for paranoia's sake,
1558 * mark the event done.
1560 event->dte_event |= TRIGGER_DEFERRED_DONE;
1567 /* Update list tail pointer in case we just deleted tail event */
1568 deftrig_event_tail = prev_event;
1570 /* Release working resources */
1572 heap_close(rel, NoLock);
1575 MemoryContextDelete(per_tuple_context);
1580 * DeferredTriggerInit()
1582 * Initialize the deferred trigger mechanism. This is called during
1583 * backend startup and is guaranteed to be before the first of all
1588 DeferredTriggerInit(void)
1591 * Since this context will never be reset, give it a minsize of 0.
1592 * This avoids using any memory if the session never stores anything.
1594 deftrig_gcxt = AllocSetContextCreate(TopMemoryContext,
1595 "DeferredTriggerSession",
1597 ALLOCSET_DEFAULT_INITSIZE,
1598 ALLOCSET_DEFAULT_MAXSIZE);
1603 * DeferredTriggerBeginXact()
1605 * Called at transaction start (either BEGIN or implicit for single
1606 * statement outside of transaction block).
1610 DeferredTriggerBeginXact(void)
1612 MemoryContext oldcxt;
1614 DeferredTriggerStatus dflstat;
1615 DeferredTriggerStatus stat;
1617 if (deftrig_cxt != NULL)
1619 "DeferredTriggerBeginXact() called while inside transaction");
1622 * Create the per transaction memory context and copy all states from
1623 * the per session context to here. Set the minsize to 0 to avoid
1624 * wasting memory if there is no deferred trigger data.
1626 deftrig_cxt = AllocSetContextCreate(TopTransactionContext,
1627 "DeferredTriggerXact",
1629 ALLOCSET_DEFAULT_INITSIZE,
1630 ALLOCSET_DEFAULT_MAXSIZE);
1631 oldcxt = MemoryContextSwitchTo(deftrig_cxt);
1633 deftrig_all_isset = deftrig_dfl_all_isset;
1634 deftrig_all_isdeferred = deftrig_dfl_all_isdeferred;
1636 deftrig_trigstates = NIL;
1637 foreach(l, deftrig_dfl_trigstates)
1639 dflstat = (DeferredTriggerStatus) lfirst(l);
1640 stat = (DeferredTriggerStatus)
1641 palloc(sizeof(DeferredTriggerStatusData));
1643 stat->dts_tgoid = dflstat->dts_tgoid;
1644 stat->dts_tgisdeferred = dflstat->dts_tgisdeferred;
1646 deftrig_trigstates = lappend(deftrig_trigstates, stat);
1649 MemoryContextSwitchTo(oldcxt);
1651 deftrig_events = NULL;
1652 deftrig_event_tail = NULL;
1657 * DeferredTriggerEndQuery()
1659 * Called after one query sent down by the user has completely been
1660 * processed. At this time we invoke all outstanding IMMEDIATE triggers.
1664 DeferredTriggerEndQuery(void)
1667 * Ignore call if we aren't in a transaction.
1669 if (deftrig_cxt == NULL)
1672 deferredTriggerInvokeEvents(true);
1677 * DeferredTriggerEndXact()
1679 * Called just before the current transaction is committed. At this
1680 * time we invoke all DEFERRED triggers and tidy up.
1684 DeferredTriggerEndXact(void)
1687 * Ignore call if we aren't in a transaction.
1689 if (deftrig_cxt == NULL)
1692 deferredTriggerInvokeEvents(false);
1694 MemoryContextDelete(deftrig_cxt);
1700 * DeferredTriggerAbortXact()
1702 * The current transaction has entered the abort state.
1703 * All outstanding triggers are canceled so we simply throw
1704 * away anything we know.
1708 DeferredTriggerAbortXact(void)
1711 * Ignore call if we aren't in a transaction.
1713 if (deftrig_cxt == NULL)
1716 MemoryContextDelete(deftrig_cxt);
1722 * DeferredTriggerSetState()
1724 * Called for the users SET CONSTRAINTS ... utility command.
1728 DeferredTriggerSetState(ConstraintsSetStmt *stmt)
1731 Relation irel = (Relation) NULL;
1735 MemoryContext oldcxt;
1737 DeferredTriggerStatus state;
1741 * Handle SET CONSTRAINTS ALL ...
1743 if (stmt->constraints == NIL)
1745 if (!IsTransactionBlock())
1748 * ... outside of a transaction block
1750 * Drop all information about individual trigger states per
1753 l = deftrig_dfl_trigstates;
1756 List *next = lnext(l);
1762 deftrig_dfl_trigstates = NIL;
1765 * Set the session ALL state to known.
1767 deftrig_dfl_all_isset = true;
1768 deftrig_dfl_all_isdeferred = stmt->deferred;
1775 * ... inside of a transaction block
1777 * Drop all information about individual trigger states per
1780 l = deftrig_trigstates;
1783 List *next = lnext(l);
1789 deftrig_trigstates = NIL;
1792 * Set the per transaction ALL state to known.
1794 deftrig_all_isset = true;
1795 deftrig_all_isdeferred = stmt->deferred;
1802 * Handle SET CONSTRAINTS constraint-name [, ...]
1803 * First lookup all trigger Oid's for the constraint names.
1806 tgrel = heap_openr(TriggerRelationName, AccessShareLock);
1807 hasindex = (tgrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
1809 irel = index_openr(TriggerConstrNameIndex);
1811 foreach(l, stmt->constraints)
1814 HeapTupleData tuple;
1815 IndexScanDesc sd = (IndexScanDesc) NULL;
1816 HeapScanDesc tgscan = (HeapScanDesc) NULL;
1818 RetrieveIndexResult indexRes;
1820 Form_pg_trigger pg_trigger;
1824 * Check that only named constraints are set explicitly
1826 if (strcmp((char *) lfirst(l), "") == 0)
1827 elog(ERROR, "unnamed constraints cannot be set explicitly");
1830 * Setup to scan pg_trigger by tgconstrname ...
1832 ScanKeyEntryInitialize(&skey,
1835 (RegProcedure) F_NAMEEQ,
1836 PointerGetDatum((char *) lfirst(l)));
1839 sd = index_beginscan(irel, false, 1, &skey);
1841 tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &skey);
1844 * ... and search for the constraint trigger row
1851 indexRes = index_getnext(sd, ForwardScanDirection);
1855 tuple.t_self = indexRes->heap_iptr;
1856 heap_fetch(tgrel, SnapshotNow, &tuple, &buffer, sd);
1864 htup = heap_getnext(tgscan, 0);
1865 if (!HeapTupleIsValid(htup))
1870 * If we found some, check that they fit the deferrability but
1871 * skip ON <event> RESTRICT ones, since they are silently
1874 pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
1875 if (stmt->deferred && !pg_trigger->tgdeferrable &&
1876 pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_UPD &&
1877 pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_DEL)
1878 elog(ERROR, "Constraint '%s' is not deferrable",
1879 (char *) lfirst(l));
1881 constr_oid = htup->t_data->t_oid;
1882 loid = lappendi(loid, constr_oid);
1886 ReleaseBuffer(buffer);
1893 elog(ERROR, "Constraint '%s' does not exist", (char *) lfirst(l));
1898 heap_endscan(tgscan);
1902 heap_close(tgrel, AccessShareLock);
1904 if (!IsTransactionBlock())
1907 * Outside of a transaction block set the trigger states of
1908 * individual triggers on session level.
1910 oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
1915 foreach(ls, deftrig_dfl_trigstates)
1917 state = (DeferredTriggerStatus) lfirst(ls);
1918 if (state->dts_tgoid == (Oid) lfirsti(l))
1920 state->dts_tgisdeferred = stmt->deferred;
1927 state = (DeferredTriggerStatus)
1928 palloc(sizeof(DeferredTriggerStatusData));
1929 state->dts_tgoid = (Oid) lfirsti(l);
1930 state->dts_tgisdeferred = stmt->deferred;
1932 deftrig_dfl_trigstates =
1933 lappend(deftrig_dfl_trigstates, state);
1937 MemoryContextSwitchTo(oldcxt);
1944 * Inside of a transaction block set the trigger states of
1945 * individual triggers on transaction level.
1947 oldcxt = MemoryContextSwitchTo(deftrig_cxt);
1952 foreach(ls, deftrig_trigstates)
1954 state = (DeferredTriggerStatus) lfirst(ls);
1955 if (state->dts_tgoid == (Oid) lfirsti(l))
1957 state->dts_tgisdeferred = stmt->deferred;
1964 state = (DeferredTriggerStatus)
1965 palloc(sizeof(DeferredTriggerStatusData));
1966 state->dts_tgoid = (Oid) lfirsti(l);
1967 state->dts_tgisdeferred = stmt->deferred;
1969 deftrig_trigstates =
1970 lappend(deftrig_trigstates, state);
1974 MemoryContextSwitchTo(oldcxt);
1982 * DeferredTriggerSaveEvent()
1984 * Called by ExecAR...Triggers() to add the event to the queue.
1986 * NOTE: should be called only if we've determined that an event must
1987 * be added to the queue.
1991 DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
1992 HeapTuple oldtup, HeapTuple newtup)
1994 Relation rel = relinfo->ri_RelationDesc;
1995 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
1996 MemoryContext oldcxt;
1997 DeferredTriggerEvent new_event;
2002 ItemPointerData oldctid;
2003 ItemPointerData newctid;
2004 TriggerData LocTriggerData;
2006 if (deftrig_cxt == NULL)
2008 "DeferredTriggerSaveEvent() called outside of transaction");
2011 * Get the CTID's of OLD and NEW
2014 ItemPointerCopy(&(oldtup->t_self), &(oldctid));
2016 ItemPointerSetInvalid(&(oldctid));
2018 ItemPointerCopy(&(newtup->t_self), &(newctid));
2020 ItemPointerSetInvalid(&(newctid));
2023 * Create a new event
2025 oldcxt = MemoryContextSwitchTo(deftrig_cxt);
2027 ntriggers = trigdesc->n_after_row[event];
2028 tgindx = trigdesc->tg_after_row[event];
2029 new_size = offsetof(DeferredTriggerEventData, dte_item[0]) +
2030 ntriggers * sizeof(DeferredTriggerEventItem);
2032 new_event = (DeferredTriggerEvent) palloc(new_size);
2033 new_event->dte_next = NULL;
2034 new_event->dte_event = event & TRIGGER_EVENT_OPMASK;
2035 new_event->dte_relid = rel->rd_id;
2036 ItemPointerCopy(&oldctid, &(new_event->dte_oldctid));
2037 ItemPointerCopy(&newctid, &(new_event->dte_newctid));
2038 new_event->dte_n_items = ntriggers;
2039 for (i = 0; i < ntriggers; i++)
2041 Trigger *trigger = &trigdesc->triggers[tgindx[i]];
2043 new_event->dte_item[i].dti_tgoid = trigger->tgoid;
2044 new_event->dte_item[i].dti_state =
2045 ((trigger->tgdeferrable) ?
2046 TRIGGER_DEFERRED_DEFERRABLE : 0) |
2047 ((trigger->tginitdeferred) ?
2048 TRIGGER_DEFERRED_INITDEFERRED : 0) |
2049 ((trigdesc->n_before_row[event] > 0) ?
2050 TRIGGER_DEFERRED_HAS_BEFORE : 0);
2053 MemoryContextSwitchTo(oldcxt);
2055 switch (event & TRIGGER_EVENT_OPMASK)
2057 case TRIGGER_EVENT_INSERT:
2061 case TRIGGER_EVENT_UPDATE:
2063 * Check if one of the referenced keys is changed.
2065 for (i = 0; i < ntriggers; i++)
2067 Trigger *trigger = &trigdesc->triggers[tgindx[i]];
2072 * We are interested in RI_FKEY triggers only.
2074 switch (trigger->tgfoid)
2076 case F_RI_FKEY_NOACTION_UPD:
2077 case F_RI_FKEY_CASCADE_UPD:
2078 case F_RI_FKEY_RESTRICT_UPD:
2079 case F_RI_FKEY_SETNULL_UPD:
2080 case F_RI_FKEY_SETDEFAULT_UPD:
2081 is_ri_trigger = true;
2085 is_ri_trigger = false;
2091 LocTriggerData.type = T_TriggerData;
2092 LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE;
2093 LocTriggerData.tg_relation = rel;
2094 LocTriggerData.tg_trigtuple = oldtup;
2095 LocTriggerData.tg_newtuple = newtup;
2096 LocTriggerData.tg_trigger = trigger;
2098 key_unchanged = RI_FKey_keyequal_upd(&LocTriggerData);
2103 * The key hasn't changed, so no need later to invoke
2104 * the trigger at all.
2106 new_event->dte_item[i].dti_state |= TRIGGER_DEFERRED_DONE;
2112 case TRIGGER_EVENT_DELETE:
2118 * Add the new event to the queue.
2120 deferredTriggerAddEvent(new_event);