1 /*-------------------------------------------------------------------------
4 * PostgreSQL TRIGGERs support code.
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.78 2000/10/16 17:08:05 momjian 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 DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger);
36 static HeapTuple GetTupleForTrigger(EState *estate, ItemPointer tid,
37 TupleTableSlot **newSlot);
38 static HeapTuple ExecCallTriggerFunc(Trigger *trigger,
39 TriggerData *trigdata);
40 static void DeferredTriggerSaveEvent(Relation rel, int event,
41 HeapTuple oldtup, HeapTuple newtup);
45 CreateTrigger(CreateTrigStmt *stmt)
48 int16 tgattr[FUNC_MAX_ARGS];
49 Datum values[Natts_pg_trigger];
50 char nulls[Natts_pg_trigger];
57 Relation idescs[Num_pg_trigger_indices];
58 Relation ridescs[Num_pg_class_indices];
59 Oid fargtypes[FUNC_MAX_ARGS];
64 char constrtrigname[NAMEDATALEN];
65 char *constrname = "";
66 Oid constrrelid = InvalidOid;
68 if (!allowSystemTableMods && IsSystemRelationName(stmt->relname))
69 elog(ERROR, "CreateTrigger: can't create trigger for system relation %s", stmt->relname);
71 if (!pg_ownercheck(GetUserId(), stmt->relname, RELNAME))
72 elog(ERROR, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
75 * If trigger is a constraint, user trigger name as constraint
76 * name and build a unique trigger name instead.
79 if (stmt->isconstraint)
81 constrname = stmt->trigname;
82 stmt->trigname = constrtrigname;
83 sprintf(constrtrigname, "RI_ConstraintTrigger_%u", newoid());
85 if (strcmp(stmt->constrrelname, "") == 0)
86 constrrelid = InvalidOid;
89 /* NoLock is probably sufficient here, since we're only
90 * interested in getting the relation's OID...
92 rel = heap_openr(stmt->constrrelname, NoLock);
93 constrrelid = rel->rd_id;
94 heap_close(rel, NoLock);
98 rel = heap_openr(stmt->relname, AccessExclusiveLock);
100 TRIGGER_CLEAR_TYPE(tgtype);
102 TRIGGER_SETT_BEFORE(tgtype);
104 TRIGGER_SETT_ROW(tgtype);
106 elog(ERROR, "CreateTrigger: STATEMENT triggers are unimplemented, yet");
108 for (i = 0; i < 3 && stmt->actions[i]; i++)
110 switch (stmt->actions[i])
113 if (TRIGGER_FOR_INSERT(tgtype))
114 elog(ERROR, "CreateTrigger: double INSERT event specified");
115 TRIGGER_SETT_INSERT(tgtype);
118 if (TRIGGER_FOR_DELETE(tgtype))
119 elog(ERROR, "CreateTrigger: double DELETE event specified");
120 TRIGGER_SETT_DELETE(tgtype);
123 if (TRIGGER_FOR_UPDATE(tgtype))
124 elog(ERROR, "CreateTrigger: double UPDATE event specified");
125 TRIGGER_SETT_UPDATE(tgtype);
128 elog(ERROR, "CreateTrigger: unknown event specified");
134 * Scan pg_trigger for existing triggers on relation. NOTE that this
135 * is cool only because we have AccessExclusiveLock on the relation,
136 * so the trigger set won't be changing underneath us.
138 tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
139 ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
140 F_OIDEQ, RelationGetRelid(rel));
141 tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
142 while (HeapTupleIsValid(tuple = heap_getnext(tgscan, 0)))
144 Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
146 if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
147 elog(ERROR, "CreateTrigger: trigger %s already defined on relation %s",
148 stmt->trigname, stmt->relname);
151 heap_endscan(tgscan);
154 * Find and validate the trigger function.
156 MemSet(fargtypes, 0, FUNC_MAX_ARGS * sizeof(Oid));
157 tuple = SearchSysCacheTuple(PROCNAME,
158 PointerGetDatum(stmt->funcname),
160 PointerGetDatum(fargtypes),
162 if (!HeapTupleIsValid(tuple))
163 elog(ERROR, "CreateTrigger: function %s() does not exist",
165 if (((Form_pg_proc) GETSTRUCT(tuple))->prorettype != 0)
166 elog(ERROR, "CreateTrigger: function %s() must return OPAQUE",
168 funcoid = tuple->t_data->t_oid;
169 funclang = ((Form_pg_proc) GETSTRUCT(tuple))->prolang;
170 if (funclang != ClanguageId &&
171 funclang != NEWClanguageId &&
172 funclang != INTERNALlanguageId &&
173 funclang != NEWINTERNALlanguageId)
177 langTup = SearchSysCacheTuple(LANGOID,
178 ObjectIdGetDatum(funclang),
180 if (!HeapTupleIsValid(langTup))
181 elog(ERROR, "CreateTrigger: cache lookup for PL %u failed",
183 if (((Form_pg_language) GETSTRUCT(langTup))->lanispl == false)
184 elog(ERROR, "CreateTrigger: only builtin, C and PL functions are supported");
188 * Build the new pg_trigger tuple.
190 MemSet(nulls, ' ', Natts_pg_trigger * sizeof(char));
192 values[Anum_pg_trigger_tgrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
193 values[Anum_pg_trigger_tgname - 1] = DirectFunctionCall1(namein,
194 CStringGetDatum(stmt->trigname));
195 values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
196 values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
197 values[Anum_pg_trigger_tgenabled - 1] = BoolGetDatum(true);
198 values[Anum_pg_trigger_tgisconstraint - 1] = BoolGetDatum(stmt->isconstraint);
199 values[Anum_pg_trigger_tgconstrname - 1] = PointerGetDatum(constrname);
200 values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
201 values[Anum_pg_trigger_tgdeferrable - 1] = BoolGetDatum(stmt->deferrable);
202 values[Anum_pg_trigger_tginitdeferred - 1] = BoolGetDatum(stmt->initdeferred);
208 int16 nargs = length(stmt->args);
211 foreach(le, stmt->args)
213 char *ar = ((Value*) lfirst(le))->val.str;
215 len += strlen(ar) + 4;
222 args = (char *) palloc(len + 1);
224 foreach(le, stmt->args)
226 char *s = ((Value*) lfirst(le))->val.str;
227 char *d = args + strlen(args);
237 values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
238 values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain,
239 CStringGetDatum(args));
243 values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
244 values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain,
245 CStringGetDatum(""));
247 MemSet(tgattr, 0, FUNC_MAX_ARGS * sizeof(int16));
248 values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
250 tuple = heap_formtuple(tgrel->rd_att, values, nulls);
253 * Insert tuple into pg_trigger.
255 heap_insert(tgrel, tuple);
256 CatalogOpenIndices(Num_pg_trigger_indices, Name_pg_trigger_indices, idescs);
257 CatalogIndexInsert(idescs, Num_pg_trigger_indices, tgrel, tuple);
258 CatalogCloseIndices(Num_pg_trigger_indices, idescs);
259 heap_freetuple(tuple);
260 heap_close(tgrel, RowExclusiveLock);
262 pfree(DatumGetPointer(values[Anum_pg_trigger_tgname - 1]));
263 pfree(DatumGetPointer(values[Anum_pg_trigger_tgargs - 1]));
266 * Update relation's pg_class entry. Crucial side-effect: other
267 * backends (and this one too!) are sent SI message to make them
268 * rebuild relcache entries.
270 pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
271 tuple = SearchSysCacheTupleCopy(RELNAME,
272 PointerGetDatum(stmt->relname),
274 if (!HeapTupleIsValid(tuple))
275 elog(ERROR, "CreateTrigger: relation %s not found in pg_class",
278 ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found + 1;
279 heap_update(pgrel, &tuple->t_self, tuple, NULL);
280 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
281 CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
282 CatalogCloseIndices(Num_pg_class_indices, ridescs);
283 heap_freetuple(tuple);
284 heap_close(pgrel, RowExclusiveLock);
287 * We used to try to update the rel's relcache entry here, but that's
288 * fairly pointless since it will happen as a byproduct of the
289 * upcoming CommandCounterIncrement...
292 /* Keep lock on target rel until end of xact */
293 heap_close(rel, NoLock);
297 DropTrigger(DropTrigStmt *stmt)
305 Relation ridescs[Num_pg_class_indices];
309 if (!pg_ownercheck(GetUserId(), stmt->relname, RELNAME))
310 elog(ERROR, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
312 rel = heap_openr(stmt->relname, AccessExclusiveLock);
315 * Search pg_trigger, delete target trigger, count remaining triggers
316 * for relation. Note this is OK only because we have
317 * AccessExclusiveLock on the rel, so no one else is creating/deleting
318 * triggers on this rel at the same time.
320 tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
321 ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
322 F_OIDEQ, RelationGetRelid(rel));
323 tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
324 while (HeapTupleIsValid(tuple = heap_getnext(tgscan, 0)))
326 Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
328 if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
331 /*** Delete any comments associated with this trigger ***/
333 DeleteComments(tuple->t_data->t_oid);
335 heap_delete(tgrel, &tuple->t_self, NULL);
342 elog(ERROR, "DropTrigger: there is no trigger %s on relation %s",
343 stmt->trigname, stmt->relname);
345 elog(NOTICE, "DropTrigger: found (and deleted) %d triggers %s on relation %s",
346 tgfound, stmt->trigname, stmt->relname);
347 heap_endscan(tgscan);
348 heap_close(tgrel, RowExclusiveLock);
351 * Update relation's pg_class entry. Crucial side-effect: other
352 * backends (and this one too!) are sent SI message to make them
353 * rebuild relcache entries.
355 pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
356 tuple = SearchSysCacheTupleCopy(RELNAME,
357 PointerGetDatum(stmt->relname),
359 if (!HeapTupleIsValid(tuple))
360 elog(ERROR, "DropTrigger: relation %s not found in pg_class",
363 ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found;
364 heap_update(pgrel, &tuple->t_self, tuple, NULL);
365 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
366 CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
367 CatalogCloseIndices(Num_pg_class_indices, ridescs);
368 heap_freetuple(tuple);
369 heap_close(pgrel, RowExclusiveLock);
372 * We used to try to update the rel's relcache entry here, but that's
373 * fairly pointless since it will happen as a byproduct of the
374 * upcoming CommandCounterIncrement...
377 /* Keep lock on target rel until end of xact */
378 heap_close(rel, NoLock);
382 * Remove all triggers for a relation that's being deleted.
385 RelationRemoveTriggers(Relation rel)
392 tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
393 ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
394 F_OIDEQ, RelationGetRelid(rel));
396 tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
398 while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0)))
401 /*** Delete any comments associated with this trigger ***/
403 DeleteComments(tup->t_data->t_oid);
405 heap_delete(tgrel, &tup->t_self, NULL);
408 heap_endscan(tgscan);
411 * Need to bump it here so the following doesn't see
412 * the already deleted triggers again for a self-referencing
416 CommandCounterIncrement();
419 * Also drop all constraint triggers referencing this relation
422 ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgconstrrelid,
423 F_OIDEQ, RelationGetRelid(rel));
425 tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
426 while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0)))
428 Form_pg_trigger pg_trigger;
432 pg_trigger = (Form_pg_trigger) GETSTRUCT(tup);
434 refrel = heap_open(pg_trigger->tgrelid, NoLock);
435 stmt.relname = pstrdup(RelationGetRelationName(refrel));
436 heap_close(refrel, NoLock);
438 stmt.trigname = DatumGetCString(DirectFunctionCall1(nameout,
439 NameGetDatum(&pg_trigger->tgname)));
442 elog(NOTICE, "DROP TABLE implicitly drops referential integrity trigger from table \"%s\"", stmt.relname);
447 * Need to do a command counter increment here to show up
448 * new pg_class.reltriggers in the next loop invocation already
449 * (there are multiple referential integrity action
450 * triggers for the same FK table defined on the PK table).
453 CommandCounterIncrement();
456 pfree(stmt.trigname);
458 heap_endscan(tgscan);
460 heap_close(tgrel, RowExclusiveLock);
464 * Build trigger data to attach to the given relcache entry.
466 * Note that trigger data must be allocated in CacheMemoryContext
467 * to ensure it survives as long as the relcache entry. But we
468 * are probably running in a less long-lived working context.
471 RelationBuildTriggers(Relation relation)
473 TriggerDesc *trigdesc;
474 int ntrigs = relation->rd_rel->reltriggers;
475 Trigger *triggers = NULL;
478 Form_pg_trigger pg_trigger;
479 Relation irel = (Relation) NULL;
482 IndexScanDesc sd = (IndexScanDesc) NULL;
483 HeapScanDesc tgscan = (HeapScanDesc) NULL;
485 RetrieveIndexResult indexRes;
492 trigdesc = (TriggerDesc *) MemoryContextAlloc(CacheMemoryContext,
493 sizeof(TriggerDesc));
494 MemSet(trigdesc, 0, sizeof(TriggerDesc));
496 ScanKeyEntryInitialize(&skey,
499 (RegProcedure) F_OIDEQ,
500 ObjectIdGetDatum(RelationGetRelid(relation)));
502 tgrel = heap_openr(TriggerRelationName, AccessShareLock);
503 hasindex = (tgrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
506 irel = index_openr(TriggerRelidIndex);
507 sd = index_beginscan(irel, false, 1, &skey);
510 tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &skey);
516 indexRes = index_getnext(sd, ForwardScanDirection);
520 tuple.t_self = indexRes->heap_iptr;
521 heap_fetch(tgrel, SnapshotNow, &tuple, &buffer);
529 htup = heap_getnext(tgscan, 0);
530 if (!HeapTupleIsValid(htup))
534 elog(ERROR, "RelationBuildTriggers: unexpected record found for rel %s",
535 RelationGetRelationName(relation));
537 pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
539 if (triggers == NULL)
540 triggers = (Trigger *) MemoryContextAlloc(CacheMemoryContext,
543 triggers = (Trigger *) repalloc(triggers,
544 (found + 1) * sizeof(Trigger));
545 build = &(triggers[found]);
547 build->tgoid = htup->t_data->t_oid;
548 build->tgname = MemoryContextStrdup(CacheMemoryContext,
549 DatumGetCString(DirectFunctionCall1(nameout,
550 NameGetDatum(&pg_trigger->tgname))));
551 build->tgfoid = pg_trigger->tgfoid;
552 build->tgfunc.fn_oid = InvalidOid; /* mark FmgrInfo as uninitialized */
553 build->tgtype = pg_trigger->tgtype;
554 build->tgenabled = pg_trigger->tgenabled;
555 build->tgisconstraint = pg_trigger->tgisconstraint;
556 build->tgdeferrable = pg_trigger->tgdeferrable;
557 build->tginitdeferred = pg_trigger->tginitdeferred;
558 build->tgnargs = pg_trigger->tgnargs;
559 memcpy(build->tgattr, &(pg_trigger->tgattr),
560 FUNC_MAX_ARGS * sizeof(int16));
561 val = (struct varlena *) fastgetattr(htup,
562 Anum_pg_trigger_tgargs,
563 tgrel->rd_att, &isnull);
565 elog(ERROR, "RelationBuildTriggers: tgargs IS NULL for rel %s",
566 RelationGetRelationName(relation));
567 if (build->tgnargs > 0)
572 val = (struct varlena *) fastgetattr(htup,
573 Anum_pg_trigger_tgargs,
574 tgrel->rd_att, &isnull);
576 elog(ERROR, "RelationBuildTriggers: tgargs IS NULL for rel %s",
577 RelationGetRelationName(relation));
578 p = (char *) VARDATA(val);
579 build->tgargs = (char **)
580 MemoryContextAlloc(CacheMemoryContext,
581 build->tgnargs * sizeof(char *));
582 for (i = 0; i < build->tgnargs; i++)
584 build->tgargs[i] = MemoryContextStrdup(CacheMemoryContext,
590 build->tgargs = NULL;
594 ReleaseBuffer(buffer);
598 elog(ERROR, "RelationBuildTriggers: %d record(s) not found for rel %s",
600 RelationGetRelationName(relation));
608 heap_endscan(tgscan);
609 heap_close(tgrel, AccessShareLock);
612 trigdesc->triggers = triggers;
613 trigdesc->numtriggers = ntrigs;
614 for (found = 0; found < ntrigs; found++)
615 DescribeTrigger(trigdesc, &(triggers[found]));
617 relation->trigdesc = trigdesc;
621 DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
627 if (TRIGGER_FOR_ROW(trigger->tgtype)) /* Is ROW/STATEMENT
630 if (TRIGGER_FOR_BEFORE(trigger->tgtype))
632 n = trigdesc->n_before_row;
633 t = trigdesc->tg_before_row;
637 n = trigdesc->n_after_row;
638 t = trigdesc->tg_after_row;
644 if (TRIGGER_FOR_BEFORE(trigger->tgtype))
646 n = trigdesc->n_before_statement;
647 t = trigdesc->tg_before_statement;
651 n = trigdesc->n_after_statement;
652 t = trigdesc->tg_after_statement;
656 if (TRIGGER_FOR_INSERT(trigger->tgtype))
658 tp = &(t[TRIGGER_EVENT_INSERT]);
660 *tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext,
663 *tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
665 (*tp)[n[TRIGGER_EVENT_INSERT]] = trigger;
666 (n[TRIGGER_EVENT_INSERT])++;
669 if (TRIGGER_FOR_DELETE(trigger->tgtype))
671 tp = &(t[TRIGGER_EVENT_DELETE]);
673 *tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext,
676 *tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
678 (*tp)[n[TRIGGER_EVENT_DELETE]] = trigger;
679 (n[TRIGGER_EVENT_DELETE])++;
682 if (TRIGGER_FOR_UPDATE(trigger->tgtype))
684 tp = &(t[TRIGGER_EVENT_UPDATE]);
686 *tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext,
689 *tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
691 (*tp)[n[TRIGGER_EVENT_UPDATE]] = trigger;
692 (n[TRIGGER_EVENT_UPDATE])++;
698 FreeTriggerDesc(TriggerDesc *trigdesc)
704 if (trigdesc == NULL)
707 t = trigdesc->tg_before_statement;
708 for (i = 0; i < 4; i++)
711 t = trigdesc->tg_before_row;
712 for (i = 0; i < 4; i++)
715 t = trigdesc->tg_after_row;
716 for (i = 0; i < 4; i++)
719 t = trigdesc->tg_after_statement;
720 for (i = 0; i < 4; i++)
724 trigger = trigdesc->triggers;
725 for (i = 0; i < trigdesc->numtriggers; i++)
727 pfree(trigger->tgname);
728 if (trigger->tgnargs > 0)
730 while (--(trigger->tgnargs) >= 0)
731 pfree(trigger->tgargs[trigger->tgnargs]);
732 pfree(trigger->tgargs);
736 pfree(trigdesc->triggers);
741 equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
747 * We need not examine the "index" data, just the trigger array
748 * itself; if we have the same triggers with the same types, the
749 * derived index data should match.
751 * XXX It seems possible that the same triggers could appear in different
752 * orders in the two trigger arrays; do we need to handle that?
754 if (trigdesc1 != NULL)
756 if (trigdesc2 == NULL)
758 if (trigdesc1->numtriggers != trigdesc2->numtriggers)
760 for (i = 0; i < trigdesc1->numtriggers; i++)
762 Trigger *trig1 = trigdesc1->triggers + i;
763 Trigger *trig2 = NULL;
766 * We can't assume that the triggers are always read from
767 * pg_trigger in the same order; so use the trigger OIDs to
768 * identify the triggers to compare. (We assume here that the
769 * same OID won't appear twice in either trigger set.)
771 for (j = 0; j < trigdesc2->numtriggers; j++)
773 trig2 = trigdesc2->triggers + i;
774 if (trig1->tgoid == trig2->tgoid)
777 if (j >= trigdesc2->numtriggers)
779 if (strcmp(trig1->tgname, trig2->tgname) != 0)
781 if (trig1->tgfoid != trig2->tgfoid)
783 /* need not examine tgfunc, if tgfoid matches */
784 if (trig1->tgtype != trig2->tgtype)
786 if (trig1->tgenabled != trig2->tgenabled)
788 if (trig1->tgisconstraint != trig2->tgisconstraint)
790 if (trig1->tgdeferrable != trig2->tgdeferrable)
792 if (trig1->tginitdeferred != trig2->tginitdeferred)
794 if (trig1->tgnargs != trig2->tgnargs)
796 if (memcmp(trig1->tgattr, trig2->tgattr,
797 sizeof(trig1->tgattr)) != 0)
799 for (j = 0; j < trig1->tgnargs; j++)
800 if (strcmp(trig1->tgargs[j], trig2->tgargs[j]) != 0)
804 else if (trigdesc2 != NULL)
810 ExecCallTriggerFunc(Trigger *trigger, TriggerData *trigdata)
812 FunctionCallInfoData fcinfo;
816 * Fmgr lookup info is cached in the Trigger structure,
817 * so that we need not repeat the lookup on every call.
819 if (trigger->tgfunc.fn_oid == InvalidOid)
820 fmgr_info(trigger->tgfoid, &trigger->tgfunc);
823 * Call the function, passing no arguments but setting a context.
825 MemSet(&fcinfo, 0, sizeof(fcinfo));
827 fcinfo.flinfo = &trigger->tgfunc;
828 fcinfo.context = (Node *) trigdata;
830 result = FunctionCallInvoke(&fcinfo);
833 * Trigger protocol allows function to return a null pointer,
834 * but NOT to set the isnull result flag.
837 elog(ERROR, "ExecCallTriggerFunc: function %u returned NULL",
838 fcinfo.flinfo->fn_oid);
840 return (HeapTuple) DatumGetPointer(result);
844 ExecBRInsertTriggers(Relation rel, HeapTuple trigtuple)
846 int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
847 Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
848 HeapTuple newtuple = trigtuple;
850 TriggerData LocTriggerData;
853 LocTriggerData.type = T_TriggerData;
854 LocTriggerData.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
855 LocTriggerData.tg_relation = rel;
856 LocTriggerData.tg_newtuple = NULL;
857 for (i = 0; i < ntrigs; i++)
859 if (!trigger[i]->tgenabled)
861 LocTriggerData.tg_trigtuple = oldtuple = newtuple;
862 LocTriggerData.tg_trigger = trigger[i];
863 newtuple = ExecCallTriggerFunc(trigger[i], &LocTriggerData);
864 if (newtuple == NULL)
866 else if (oldtuple != newtuple && oldtuple != trigtuple)
867 heap_freetuple(oldtuple);
873 ExecARInsertTriggers(Relation rel, HeapTuple trigtuple)
875 DeferredTriggerSaveEvent(rel, TRIGGER_EVENT_INSERT, NULL, trigtuple);
880 ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
882 Relation rel = estate->es_result_relation_info->ri_RelationDesc;
883 int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
884 Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
885 TriggerData LocTriggerData;
887 HeapTuple newtuple = NULL;
888 TupleTableSlot *newSlot;
891 trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot);
892 if (trigtuple == NULL)
895 LocTriggerData.type = T_TriggerData;
896 LocTriggerData.tg_event = TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
897 LocTriggerData.tg_relation = rel;
898 LocTriggerData.tg_newtuple = NULL;
899 for (i = 0; i < ntrigs; i++)
901 if (!trigger[i]->tgenabled)
903 LocTriggerData.tg_trigtuple = trigtuple;
904 LocTriggerData.tg_trigger = trigger[i];
905 newtuple = ExecCallTriggerFunc(trigger[i], &LocTriggerData);
906 if (newtuple == NULL)
908 if (newtuple != trigtuple)
909 heap_freetuple(newtuple);
911 heap_freetuple(trigtuple);
913 return (newtuple == NULL) ? false : true;
917 ExecARDeleteTriggers(EState *estate, ItemPointer tupleid)
919 Relation rel = estate->es_result_relation_info->ri_RelationDesc;
920 HeapTuple trigtuple = GetTupleForTrigger(estate, tupleid, NULL);
922 DeferredTriggerSaveEvent(rel, TRIGGER_EVENT_DELETE, trigtuple, NULL);
927 ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
929 Relation rel = estate->es_result_relation_info->ri_RelationDesc;
930 int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
931 Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
932 TriggerData LocTriggerData;
935 HeapTuple intuple = newtuple;
936 TupleTableSlot *newSlot;
939 trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot);
940 if (trigtuple == NULL)
944 * In READ COMMITTED isolevel it's possible that newtuple was changed
945 * due to concurrent update.
948 intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot);
950 LocTriggerData.type = T_TriggerData;
951 LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
952 LocTriggerData.tg_relation = rel;
953 for (i = 0; i < ntrigs; i++)
955 if (!trigger[i]->tgenabled)
957 LocTriggerData.tg_trigtuple = trigtuple;
958 LocTriggerData.tg_newtuple = oldtuple = newtuple;
959 LocTriggerData.tg_trigger = trigger[i];
960 newtuple = ExecCallTriggerFunc(trigger[i], &LocTriggerData);
961 if (newtuple == NULL)
963 else if (oldtuple != newtuple && oldtuple != intuple)
964 heap_freetuple(oldtuple);
966 heap_freetuple(trigtuple);
971 ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
973 Relation rel = estate->es_result_relation_info->ri_RelationDesc;
974 HeapTuple trigtuple = GetTupleForTrigger(estate, tupleid, NULL);
976 DeferredTriggerSaveEvent(rel, TRIGGER_EVENT_UPDATE, trigtuple, newtuple);
982 GetTupleForTrigger(EState *estate, ItemPointer tid, TupleTableSlot **newSlot)
984 Relation relation = estate->es_result_relation_info->ri_RelationDesc;
994 * mark tuple for update
999 test = heap_mark4update(relation, &tuple, &buffer);
1002 case HeapTupleSelfUpdated:
1003 ReleaseBuffer(buffer);
1006 case HeapTupleMayBeUpdated:
1009 case HeapTupleUpdated:
1010 ReleaseBuffer(buffer);
1011 if (XactIsoLevel == XACT_SERIALIZABLE)
1012 elog(ERROR, "Can't serialize access due to concurrent update");
1013 else if (!(ItemPointerEquals(&(tuple.t_self), tid)))
1015 TupleTableSlot *epqslot = EvalPlanQual(estate,
1016 estate->es_result_relation_info->ri_RangeTableIndex,
1019 if (!(TupIsNull(epqslot)))
1021 *tid = tuple.t_self;
1028 * if tuple was deleted or PlanQual failed for updated
1029 * tuple - we have not process this tuple!
1034 ReleaseBuffer(buffer);
1035 elog(ERROR, "Unknown status %u from heap_mark4update", test);
1044 buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
1046 if (!BufferIsValid(buffer))
1047 elog(ERROR, "GetTupleForTrigger: failed ReadBuffer");
1049 dp = (PageHeader) BufferGetPage(buffer);
1050 lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
1052 Assert(ItemIdIsUsed(lp));
1054 tuple.t_datamcxt = NULL;
1055 tuple.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
1056 tuple.t_len = ItemIdGetLength(lp);
1057 tuple.t_self = *tid;
1060 result = heap_copytuple(&tuple);
1061 ReleaseBuffer(buffer);
1068 * Deferred trigger stuff
1074 * Internal data to the deferred trigger mechanism is held
1075 * during entire session in a global context created at startup and
1076 * over statements/commands in a separate context which
1077 * is created at transaction start and destroyed at transaction end.
1080 static MemoryContext deftrig_gcxt = NULL;
1081 static MemoryContext deftrig_cxt = NULL;
1084 * Global data that tells which triggers are actually in
1085 * state IMMEDIATE or DEFERRED.
1088 static bool deftrig_dfl_all_isset = false;
1089 static bool deftrig_dfl_all_isdeferred = false;
1090 static List *deftrig_dfl_trigstates = NIL;
1092 static bool deftrig_all_isset;
1093 static bool deftrig_all_isdeferred;
1094 static List *deftrig_trigstates;
1097 * The list of events during the entire transaction.
1099 * XXX This must finally be held in a file because of the huge
1100 * number of events that could occur in the real world.
1103 static int deftrig_n_events;
1104 static List *deftrig_events;
1108 * deferredTriggerCheckState()
1110 * Returns true if the trigger identified by tgoid is actually
1111 * in state DEFERRED.
1115 deferredTriggerCheckState(Oid tgoid, int32 itemstate)
1117 MemoryContext oldcxt;
1119 DeferredTriggerStatus trigstate;
1122 * Not deferrable triggers (i.e. normal AFTER ROW triggers
1123 * and constraints declared NOT DEFERRABLE, the state is
1127 if ((itemstate & TRIGGER_DEFERRED_DEFERRABLE) == 0)
1131 * Lookup if we know an individual state for this trigger
1134 foreach(sl, deftrig_trigstates)
1136 trigstate = (DeferredTriggerStatus) lfirst(sl);
1137 if (trigstate->dts_tgoid == tgoid)
1138 return trigstate->dts_tgisdeferred;
1142 * No individual state known - so if the user issued a
1143 * SET CONSTRAINT ALL ..., we return that instead of the
1144 * triggers default state.
1147 if (deftrig_all_isset)
1148 return deftrig_all_isdeferred;
1151 * No ALL state known either, remember the default state
1152 * as the current and return that.
1155 oldcxt = MemoryContextSwitchTo(deftrig_cxt);
1157 trigstate = (DeferredTriggerStatus)
1158 palloc(sizeof(DeferredTriggerStatusData));
1159 trigstate->dts_tgoid = tgoid;
1160 trigstate->dts_tgisdeferred =
1161 ((itemstate & TRIGGER_DEFERRED_INITDEFERRED) != 0);
1162 deftrig_trigstates = lappend(deftrig_trigstates, trigstate);
1164 MemoryContextSwitchTo(oldcxt);
1166 return trigstate->dts_tgisdeferred;
1171 * deferredTriggerAddEvent()
1173 * Add a new trigger event to the queue.
1174 * Caller must have switched into appropriate memory context!
1178 deferredTriggerAddEvent(DeferredTriggerEvent event)
1180 deftrig_events = lappend(deftrig_events, event);
1186 * deferredTriggerGetPreviousEvent()
1188 * Backward scan the eventlist to find the event a given OLD tuple
1189 * resulted from in the same transaction.
1192 static DeferredTriggerEvent
1193 deferredTriggerGetPreviousEvent(Oid relid, ItemPointer ctid)
1195 DeferredTriggerEvent previous;
1198 for (n = deftrig_n_events - 1; n >= 0; n--)
1200 previous = (DeferredTriggerEvent) nth(n, deftrig_events);
1202 if (previous->dte_relid != relid)
1204 if (previous->dte_event & TRIGGER_DEFERRED_CANCELED)
1207 if (ItemPointerGetBlockNumber(ctid) ==
1208 ItemPointerGetBlockNumber(&(previous->dte_newctid)) &&
1209 ItemPointerGetOffsetNumber(ctid) ==
1210 ItemPointerGetOffsetNumber(&(previous->dte_newctid)))
1215 "deferredTriggerGetPreviousEvent(): event for tuple %s not found",
1216 DatumGetCString(DirectFunctionCall1(tidout, PointerGetDatum(ctid))));
1222 * deferredTriggerExecute()
1224 * Fetch the required tuples back from the heap and fire one
1225 * single trigger function.
1229 deferredTriggerExecute(DeferredTriggerEvent event, int itemno)
1232 TriggerData LocTriggerData;
1233 HeapTupleData oldtuple;
1234 HeapTupleData newtuple;
1240 * Open the heap and fetch the required OLD and NEW tuples.
1243 rel = heap_open(event->dte_relid, NoLock);
1245 if (ItemPointerIsValid(&(event->dte_oldctid)))
1247 ItemPointerCopy(&(event->dte_oldctid), &(oldtuple.t_self));
1248 heap_fetch(rel, SnapshotAny, &oldtuple, &oldbuffer);
1249 if (!oldtuple.t_data)
1250 elog(ERROR, "deferredTriggerExecute(): failed to fetch old tuple");
1253 if (ItemPointerIsValid(&(event->dte_newctid)))
1255 ItemPointerCopy(&(event->dte_newctid), &(newtuple.t_self));
1256 heap_fetch(rel, SnapshotAny, &newtuple, &newbuffer);
1257 if (!newtuple.t_data)
1258 elog(ERROR, "deferredTriggerExecute(): failed to fetch new tuple");
1262 * Setup the trigger information
1265 LocTriggerData.type = T_TriggerData;
1266 LocTriggerData.tg_event = (event->dte_event & TRIGGER_EVENT_OPMASK) |
1268 LocTriggerData.tg_relation = rel;
1270 switch (event->dte_event & TRIGGER_EVENT_OPMASK)
1272 case TRIGGER_EVENT_INSERT:
1273 LocTriggerData.tg_trigtuple = &newtuple;
1274 LocTriggerData.tg_newtuple = NULL;
1275 LocTriggerData.tg_trigger =
1276 rel->trigdesc->tg_after_row[TRIGGER_EVENT_INSERT][itemno];
1279 case TRIGGER_EVENT_UPDATE:
1280 LocTriggerData.tg_trigtuple = &oldtuple;
1281 LocTriggerData.tg_newtuple = &newtuple;
1282 LocTriggerData.tg_trigger =
1283 rel->trigdesc->tg_after_row[TRIGGER_EVENT_UPDATE][itemno];
1286 case TRIGGER_EVENT_DELETE:
1287 LocTriggerData.tg_trigtuple = &oldtuple;
1288 LocTriggerData.tg_newtuple = NULL;
1289 LocTriggerData.tg_trigger =
1290 rel->trigdesc->tg_after_row[TRIGGER_EVENT_DELETE][itemno];
1295 * Call the trigger and throw away an eventually returned
1299 rettuple = ExecCallTriggerFunc(LocTriggerData.tg_trigger, &LocTriggerData);
1300 if (rettuple != NULL && rettuple != &oldtuple && rettuple != &newtuple)
1301 heap_freetuple(rettuple);
1304 * Might have been a referential integrity constraint trigger.
1305 * Reset the snapshot overriding flag.
1308 ReferentialIntegritySnapshotOverride = false;
1311 * Release buffers and close the relation
1314 if (ItemPointerIsValid(&(event->dte_oldctid)))
1315 ReleaseBuffer(oldbuffer);
1316 if (ItemPointerIsValid(&(event->dte_newctid)))
1317 ReleaseBuffer(newbuffer);
1319 heap_close(rel, NoLock);
1324 * deferredTriggerInvokeEvents()
1326 * Scan the event queue for not yet invoked triggers. Check if they
1327 * should be invoked now and do so.
1331 deferredTriggerInvokeEvents(bool immediate_only)
1334 DeferredTriggerEvent event;
1335 int still_deferred_ones;
1340 * For now we process all events - to speedup transaction blocks
1341 * we need to remember the actual end of the queue at EndQuery
1342 * and process only events that are newer. On state changes we
1343 * simply reset the position to the beginning of the queue and
1344 * process all events once with the new states when the
1345 * SET CONSTRAINTS ... command finishes and calls EndQuery.
1348 foreach(el, deftrig_events)
1353 * Get the event and check if it is completely done.
1356 event = (DeferredTriggerEvent) lfirst(el);
1357 if (event->dte_event & (TRIGGER_DEFERRED_DONE |
1358 TRIGGER_DEFERRED_CANCELED))
1362 * Check each trigger item in the event.
1365 still_deferred_ones = false;
1366 for (i = 0; i < event->dte_n_items; i++)
1368 if (event->dte_item[i].dti_state & TRIGGER_DEFERRED_DONE)
1372 * This trigger item hasn't been called yet. Check if
1373 * we should call it now.
1376 if (immediate_only && deferredTriggerCheckState(
1377 event->dte_item[i].dti_tgoid,
1378 event->dte_item[i].dti_state))
1380 still_deferred_ones = true;
1385 * So let's fire it...
1388 deferredTriggerExecute(event, i);
1389 event->dte_item[i].dti_state |= TRIGGER_DEFERRED_DONE;
1393 * Remember in the event itself if all trigger items are
1397 if (!still_deferred_ones)
1398 event->dte_event |= TRIGGER_DEFERRED_DONE;
1404 * DeferredTriggerInit()
1406 * Initialize the deferred trigger mechanism. This is called during
1407 * backend startup and is guaranteed to be before the first of all
1412 DeferredTriggerInit(void)
1414 deftrig_gcxt = AllocSetContextCreate(TopMemoryContext,
1415 "DeferredTriggerSession",
1416 ALLOCSET_DEFAULT_MINSIZE,
1417 ALLOCSET_DEFAULT_INITSIZE,
1418 ALLOCSET_DEFAULT_MAXSIZE);
1425 * DeferredTriggerBeginXact()
1427 * Called at transaction start (either BEGIN or implicit for single
1428 * statement outside of transaction block).
1432 DeferredTriggerBeginXact(void)
1434 MemoryContext oldcxt;
1436 DeferredTriggerStatus dflstat;
1437 DeferredTriggerStatus stat;
1439 if (deftrig_cxt != NULL)
1441 "DeferredTriggerBeginXact() called while inside transaction");
1444 * Create the per transaction memory context and copy all states
1445 * from the per session context to here.
1448 deftrig_cxt = AllocSetContextCreate(TopTransactionContext,
1449 "DeferredTriggerXact",
1450 ALLOCSET_DEFAULT_MINSIZE,
1451 ALLOCSET_DEFAULT_INITSIZE,
1452 ALLOCSET_DEFAULT_MAXSIZE);
1453 oldcxt = MemoryContextSwitchTo(deftrig_cxt);
1455 deftrig_all_isset = deftrig_dfl_all_isset;
1456 deftrig_all_isdeferred = deftrig_dfl_all_isdeferred;
1458 deftrig_trigstates = NIL;
1459 foreach(l, deftrig_dfl_trigstates)
1461 dflstat = (DeferredTriggerStatus) lfirst(l);
1462 stat = (DeferredTriggerStatus)
1463 palloc(sizeof(DeferredTriggerStatusData));
1465 stat->dts_tgoid = dflstat->dts_tgoid;
1466 stat->dts_tgisdeferred = dflstat->dts_tgisdeferred;
1468 deftrig_trigstates = lappend(deftrig_trigstates, stat);
1471 MemoryContextSwitchTo(oldcxt);
1473 deftrig_n_events = 0;
1474 deftrig_events = NIL;
1479 * DeferredTriggerEndQuery()
1481 * Called after one query sent down by the user has completely been
1482 * processed. At this time we invoke all outstanding IMMEDIATE triggers.
1486 DeferredTriggerEndQuery(void)
1489 * Ignore call if we aren't in a transaction.
1492 if (deftrig_cxt == NULL)
1495 deferredTriggerInvokeEvents(true);
1500 * DeferredTriggerEndXact()
1502 * Called just before the current transaction is committed. At this
1503 * time we invoke all DEFERRED triggers and tidy up.
1507 DeferredTriggerEndXact(void)
1510 * Ignore call if we aren't in a transaction.
1513 if (deftrig_cxt == NULL)
1516 deferredTriggerInvokeEvents(false);
1518 MemoryContextDelete(deftrig_cxt);
1524 * DeferredTriggerAbortXact()
1526 * The current transaction has entered the abort state.
1527 * All outstanding triggers are canceled so we simply throw
1528 * away anything we know.
1532 DeferredTriggerAbortXact(void)
1535 * Ignore call if we aren't in a transaction.
1538 if (deftrig_cxt == NULL)
1541 MemoryContextDelete(deftrig_cxt);
1547 * DeferredTriggerSetState()
1549 * Called for the users SET CONSTRAINTS ... utility command.
1553 DeferredTriggerSetState(ConstraintsSetStmt *stmt)
1556 Relation irel = (Relation) NULL;
1560 MemoryContext oldcxt;
1562 DeferredTriggerStatus state;
1566 * Handle SET CONSTRAINTS ALL ...
1569 if (stmt->constraints == NIL)
1571 if (!IsTransactionBlock())
1574 * ... outside of a transaction block
1576 * Drop all information about individual trigger states per
1580 l = deftrig_dfl_trigstates;
1583 List *next = lnext(l);
1589 deftrig_dfl_trigstates = NIL;
1592 * Set the session ALL state to known.
1595 deftrig_dfl_all_isset = true;
1596 deftrig_dfl_all_isdeferred = stmt->deferred;
1603 * ... inside of a transaction block
1605 * Drop all information about individual trigger states per
1609 l = deftrig_trigstates;
1612 List *next = lnext(l);
1618 deftrig_trigstates = NIL;
1621 * Set the per transaction ALL state to known.
1624 deftrig_all_isset = true;
1625 deftrig_all_isdeferred = stmt->deferred;
1632 * Handle SET CONSTRAINTS constraint-name [, ...]
1633 * First lookup all trigger Oid's for the constraint names.
1636 tgrel = heap_openr(TriggerRelationName, AccessShareLock);
1637 hasindex = (tgrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
1639 irel = index_openr(TriggerConstrNameIndex);
1641 foreach(l, stmt->constraints)
1644 HeapTupleData tuple;
1645 IndexScanDesc sd = (IndexScanDesc) NULL;
1646 HeapScanDesc tgscan = (HeapScanDesc) NULL;
1648 RetrieveIndexResult indexRes;
1650 Form_pg_trigger pg_trigger;
1654 * Check that only named constraints are set explicitly
1657 if (strcmp((char *) lfirst(l), "") == 0)
1658 elog(ERROR, "unnamed constraints cannot be set explicitly");
1661 * Setup to scan pg_trigger by tgconstrname ...
1664 ScanKeyEntryInitialize(&skey,
1667 (RegProcedure) F_NAMEEQ,
1668 PointerGetDatum((char *) lfirst(l)));
1671 sd = index_beginscan(irel, false, 1, &skey);
1673 tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &skey);
1676 * ... and search for the constraint trigger row
1684 indexRes = index_getnext(sd, ForwardScanDirection);
1688 tuple.t_self = indexRes->heap_iptr;
1689 heap_fetch(tgrel, SnapshotNow, &tuple, &buffer);
1697 htup = heap_getnext(tgscan, 0);
1698 if (!HeapTupleIsValid(htup))
1703 * If we found some, check that they fit the deferrability
1704 * but skip ON <event> RESTRICT ones, since they are silently
1708 pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
1709 if (stmt->deferred && !pg_trigger->tgdeferrable &&
1710 pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_UPD &&
1711 pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_DEL)
1712 elog(ERROR, "Constraint '%s' is not deferrable",
1713 (char *) lfirst(l));
1715 constr_oid = htup->t_data->t_oid;
1716 loid = lappendi(loid, constr_oid);
1720 ReleaseBuffer(buffer);
1728 elog(ERROR, "Constraint '%s' does not exist", (char *) lfirst(l));
1733 heap_endscan(tgscan);
1737 heap_close(tgrel, AccessShareLock);
1739 if (!IsTransactionBlock())
1742 * Outside of a transaction block set the trigger
1743 * states of individual triggers on session level.
1746 oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
1751 foreach(ls, deftrig_dfl_trigstates)
1753 state = (DeferredTriggerStatus) lfirst(ls);
1754 if (state->dts_tgoid == (Oid) lfirsti(l))
1756 state->dts_tgisdeferred = stmt->deferred;
1763 state = (DeferredTriggerStatus)
1764 palloc(sizeof(DeferredTriggerStatusData));
1765 state->dts_tgoid = (Oid) lfirsti(l);
1766 state->dts_tgisdeferred = stmt->deferred;
1768 deftrig_dfl_trigstates =
1769 lappend(deftrig_dfl_trigstates, state);
1773 MemoryContextSwitchTo(oldcxt);
1780 * Inside of a transaction block set the trigger
1781 * states of individual triggers on transaction level.
1784 oldcxt = MemoryContextSwitchTo(deftrig_cxt);
1789 foreach(ls, deftrig_trigstates)
1791 state = (DeferredTriggerStatus) lfirst(ls);
1792 if (state->dts_tgoid == (Oid) lfirsti(l))
1794 state->dts_tgisdeferred = stmt->deferred;
1801 state = (DeferredTriggerStatus)
1802 palloc(sizeof(DeferredTriggerStatusData));
1803 state->dts_tgoid = (Oid) lfirsti(l);
1804 state->dts_tgisdeferred = stmt->deferred;
1806 deftrig_trigstates =
1807 lappend(deftrig_trigstates, state);
1811 MemoryContextSwitchTo(oldcxt);
1819 * DeferredTriggerSaveEvent()
1821 * Called by ExecAR...Triggers() to add the event to the queue.
1825 DeferredTriggerSaveEvent(Relation rel, int event,
1826 HeapTuple oldtup, HeapTuple newtup)
1828 MemoryContext oldcxt;
1829 DeferredTriggerEvent new_event;
1830 DeferredTriggerEvent prev_event;
1835 ItemPointerData oldctid;
1836 ItemPointerData newctid;
1837 TriggerData LocTriggerData;
1839 if (deftrig_cxt == NULL)
1841 "DeferredTriggerSaveEvent() called outside of transaction");
1844 * Check if we're interested in this row at all
1847 if (rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] == 0 &&
1848 rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] == 0 &&
1849 rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] == 0 &&
1850 rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] == 0 &&
1851 rel->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE] == 0 &&
1852 rel->trigdesc->n_before_row[TRIGGER_EVENT_DELETE] == 0)
1856 * Get the CTID's of OLD and NEW
1860 ItemPointerCopy(&(oldtup->t_self), &(oldctid));
1862 ItemPointerSetInvalid(&(oldctid));
1864 ItemPointerCopy(&(newtup->t_self), &(newctid));
1866 ItemPointerSetInvalid(&(newctid));
1869 * Create a new event
1872 oldcxt = MemoryContextSwitchTo(deftrig_cxt);
1874 ntriggers = rel->trigdesc->n_after_row[event];
1875 triggers = rel->trigdesc->tg_after_row[event];
1877 new_size = sizeof(DeferredTriggerEventData) +
1878 ntriggers * sizeof(DeferredTriggerEventItem);
1880 new_event = (DeferredTriggerEvent) palloc(new_size);
1881 new_event->dte_event = event & TRIGGER_EVENT_OPMASK;
1882 new_event->dte_relid = rel->rd_id;
1883 ItemPointerCopy(&oldctid, &(new_event->dte_oldctid));
1884 ItemPointerCopy(&newctid, &(new_event->dte_newctid));
1885 new_event->dte_n_items = ntriggers;
1886 new_event->dte_item[ntriggers].dti_state = new_size;
1887 for (i = 0; i < ntriggers; i++)
1889 new_event->dte_item[i].dti_tgoid = triggers[i]->tgoid;
1890 new_event->dte_item[i].dti_state =
1891 ((triggers[i]->tgdeferrable) ?
1892 TRIGGER_DEFERRED_DEFERRABLE : 0) |
1893 ((triggers[i]->tginitdeferred) ?
1894 TRIGGER_DEFERRED_INITDEFERRED : 0) |
1895 ((rel->trigdesc->n_before_row[event] > 0) ?
1896 TRIGGER_DEFERRED_HAS_BEFORE : 0);
1898 MemoryContextSwitchTo(oldcxt);
1900 switch (event & TRIGGER_EVENT_OPMASK)
1902 case TRIGGER_EVENT_INSERT:
1903 new_event->dte_event |= TRIGGER_DEFERRED_ROW_INSERTED;
1904 new_event->dte_event |= TRIGGER_DEFERRED_KEY_CHANGED;
1907 case TRIGGER_EVENT_UPDATE:
1909 * On UPDATE check if the tuple updated has been inserted
1910 * or a foreign referenced key value that's changing now
1911 * has been updated once before in this transaction.
1914 if (oldtup->t_data->t_xmin != GetCurrentTransactionId())
1918 deferredTriggerGetPreviousEvent(rel->rd_id, &oldctid);
1921 * Now check if one of the referenced keys is changed.
1924 for (i = 0; i < ntriggers; i++)
1930 * We are interested in RI_FKEY triggers only.
1933 switch (triggers[i]->tgfoid)
1935 case F_RI_FKEY_NOACTION_UPD:
1936 case F_RI_FKEY_CASCADE_UPD:
1937 case F_RI_FKEY_RESTRICT_UPD:
1938 case F_RI_FKEY_SETNULL_UPD:
1939 case F_RI_FKEY_SETDEFAULT_UPD:
1940 is_ri_trigger = true;
1944 is_ri_trigger = false;
1950 LocTriggerData.type = T_TriggerData;
1951 LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE;
1952 LocTriggerData.tg_relation = rel;
1953 LocTriggerData.tg_trigtuple = oldtup;
1954 LocTriggerData.tg_newtuple = newtup;
1955 LocTriggerData.tg_trigger = triggers[i];
1957 key_unchanged = RI_FKey_keyequal_upd(&LocTriggerData);
1962 * The key hasn't changed, so no need later to invoke
1963 * the trigger at all. But remember other states from
1964 * the possible earlier event.
1967 new_event->dte_item[i].dti_state |= TRIGGER_DEFERRED_DONE;
1971 if (prev_event->dte_event &
1972 TRIGGER_DEFERRED_ROW_INSERTED)
1975 * This is a row inserted during our transaction.
1976 * So any key value is considered changed.
1979 new_event->dte_event |=
1980 TRIGGER_DEFERRED_ROW_INSERTED;
1981 new_event->dte_event |=
1982 TRIGGER_DEFERRED_KEY_CHANGED;
1983 new_event->dte_item[i].dti_state |=
1984 TRIGGER_DEFERRED_KEY_CHANGED;
1989 * This is a row, previously updated. So
1990 * if this key has been changed before, we
1991 * still remember that it happened.
1994 if (prev_event->dte_item[i].dti_state &
1995 TRIGGER_DEFERRED_KEY_CHANGED)
1997 new_event->dte_item[i].dti_state |=
1998 TRIGGER_DEFERRED_KEY_CHANGED;
1999 new_event->dte_event |=
2000 TRIGGER_DEFERRED_KEY_CHANGED;
2008 * Bomb out if this key has been changed before.
2009 * Otherwise remember that we do so.
2014 if (prev_event->dte_event &
2015 TRIGGER_DEFERRED_ROW_INSERTED)
2016 elog(ERROR, "triggered data change violation "
2017 "on relation \"%s\"",
2018 DatumGetCString(DirectFunctionCall1(nameout,
2019 NameGetDatum(&(rel->rd_rel->relname)))));
2021 if (prev_event->dte_item[i].dti_state &
2022 TRIGGER_DEFERRED_KEY_CHANGED)
2023 elog(ERROR, "triggered data change violation "
2024 "on relation \"%s\"",
2025 DatumGetCString(DirectFunctionCall1(nameout,
2026 NameGetDatum(&(rel->rd_rel->relname)))));
2030 * This is the first change to this key, so let
2034 new_event->dte_item[i].dti_state |=
2035 TRIGGER_DEFERRED_KEY_CHANGED;
2036 new_event->dte_event |= TRIGGER_DEFERRED_KEY_CHANGED;
2042 case TRIGGER_EVENT_DELETE:
2044 * On DELETE check if the tuple deleted has been inserted
2045 * or a possibly referenced key value has changed in this
2049 if (oldtup->t_data->t_xmin != GetCurrentTransactionId())
2053 * Look at the previous event to the same tuple.
2056 prev_event = deferredTriggerGetPreviousEvent(rel->rd_id, &oldctid);
2057 if (prev_event->dte_event & TRIGGER_DEFERRED_KEY_CHANGED)
2058 elog(ERROR, "triggered data change violation "
2059 "on relation \"%s\"",
2060 DatumGetCString(DirectFunctionCall1(nameout,
2061 NameGetDatum(&(rel->rd_rel->relname)))));
2067 * Anything's fine up to here. Add the new event to the queue.
2070 oldcxt = MemoryContextSwitchTo(deftrig_cxt);
2071 deferredTriggerAddEvent(new_event);
2072 MemoryContextSwitchTo(oldcxt);