]> granicus.if.org Git - postgresql/blob - src/backend/commands/trigger.c
Add tgconstrrelid to stored Trigger structures, make RI trigger functions
[postgresql] / src / backend / commands / trigger.c
1 /*-------------------------------------------------------------------------
2  *
3  * trigger.c
4  *        PostgreSQL TRIGGERs support code.
5  *
6  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.111 2002/04/01 22:36:10 tgl Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15
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/namespace.h"
22 #include "catalog/pg_language.h"
23 #include "catalog/pg_proc.h"
24 #include "catalog/pg_trigger.h"
25 #include "commands/comment.h"
26 #include "commands/trigger.h"
27 #include "executor/executor.h"
28 #include "miscadmin.h"
29 #include "utils/acl.h"
30 #include "utils/builtins.h"
31 #include "utils/fmgroids.h"
32 #include "utils/inval.h"
33 #include "utils/lsyscache.h"
34 #include "utils/syscache.h"
35
36
37 static void InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx);
38 static HeapTuple GetTupleForTrigger(EState *estate,
39                                    ResultRelInfo *relinfo,
40                                    ItemPointer tid,
41                                    TupleTableSlot **newSlot);
42 static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
43                                         FmgrInfo *finfo,
44                                         MemoryContext per_tuple_context);
45 static void DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
46                                                  HeapTuple oldtup, HeapTuple newtup);
47 static void DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
48                                            Relation rel, FmgrInfo *finfo,
49                                            MemoryContext per_tuple_context);
50
51
52 void
53 CreateTrigger(CreateTrigStmt *stmt)
54 {
55         int16           tgtype;
56         int16           tgattr[FUNC_MAX_ARGS];
57         Datum           values[Natts_pg_trigger];
58         char            nulls[Natts_pg_trigger];
59         Relation        rel;
60         Relation        tgrel;
61         SysScanDesc     tgscan;
62         ScanKeyData key;
63         Relation        pgrel;
64         HeapTuple       tuple;
65         Relation        idescs[Num_pg_trigger_indices];
66         Relation        ridescs[Num_pg_class_indices];
67         Oid                     fargtypes[FUNC_MAX_ARGS];
68         Oid                     funcoid;
69         Oid                     funclang;
70         int                     found = 0;
71         int                     i;
72         char            constrtrigname[NAMEDATALEN];
73         char       *constrname = "";
74         Oid                     constrrelid = InvalidOid;
75
76         rel = heap_openrv(stmt->relation, AccessExclusiveLock);
77
78         if (rel->rd_rel->relkind != RELKIND_RELATION)
79                 elog(ERROR, "CreateTrigger: relation \"%s\" is not a table",
80                          stmt->relation->relname);
81
82         if (!allowSystemTableMods && IsSystemRelationName(stmt->relation->relname))
83                 elog(ERROR, "CreateTrigger: can't create trigger for system relation %s",
84                         stmt->relation->relname);
85
86         if (pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
87                                                   stmt->isconstraint ? ACL_REFERENCES : ACL_TRIGGER)
88                 != ACLCHECK_OK)
89                 elog(ERROR, "permission denied");
90
91         /*
92          * If trigger is a constraint, user trigger name as constraint name
93          * and build a unique trigger name instead.
94          */
95         if (stmt->isconstraint)
96         {
97                 constrname = stmt->trigname;
98                 stmt->trigname = constrtrigname;
99                 sprintf(constrtrigname, "RI_ConstraintTrigger_%u", newoid());
100
101                 if (stmt->constrrel != NULL)
102                         constrrelid = RangeVarGetRelid(stmt->constrrel, false);
103                 else
104                         constrrelid = InvalidOid;
105         }
106
107         TRIGGER_CLEAR_TYPE(tgtype);
108         if (stmt->before)
109                 TRIGGER_SETT_BEFORE(tgtype);
110         if (stmt->row)
111                 TRIGGER_SETT_ROW(tgtype);
112         else
113                 elog(ERROR, "CreateTrigger: STATEMENT triggers are unimplemented, yet");
114
115         for (i = 0; i < 3 && stmt->actions[i]; i++)
116         {
117                 switch (stmt->actions[i])
118                 {
119                         case 'i':
120                                 if (TRIGGER_FOR_INSERT(tgtype))
121                                         elog(ERROR, "CreateTrigger: double INSERT event specified");
122                                 TRIGGER_SETT_INSERT(tgtype);
123                                 break;
124                         case 'd':
125                                 if (TRIGGER_FOR_DELETE(tgtype))
126                                         elog(ERROR, "CreateTrigger: double DELETE event specified");
127                                 TRIGGER_SETT_DELETE(tgtype);
128                                 break;
129                         case 'u':
130                                 if (TRIGGER_FOR_UPDATE(tgtype))
131                                         elog(ERROR, "CreateTrigger: double UPDATE event specified");
132                                 TRIGGER_SETT_UPDATE(tgtype);
133                                 break;
134                         default:
135                                 elog(ERROR, "CreateTrigger: unknown event specified");
136                                 break;
137                 }
138         }
139
140         /*
141          * Scan pg_trigger for existing triggers on relation.  NOTE that this
142          * is cool only because we have AccessExclusiveLock on the relation,
143          * so the trigger set won't be changing underneath us.
144          */
145         tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
146         ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
147                                                    F_OIDEQ,
148                                                    ObjectIdGetDatum(RelationGetRelid(rel)));
149         tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true,
150                                                                 SnapshotNow, 1, &key);
151         while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
152         {
153                 Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
154
155                 if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
156                         elog(ERROR, "CreateTrigger: trigger %s already defined on relation %s",
157                                  stmt->trigname, stmt->relation->relname);
158                 found++;
159         }
160         systable_endscan(tgscan);
161
162         /*
163          * Find and validate the trigger function.
164          */
165         MemSet(fargtypes, 0, FUNC_MAX_ARGS * sizeof(Oid));
166         tuple = SearchSysCache(PROCNAME,
167                                                    PointerGetDatum(stmt->funcname),
168                                                    Int32GetDatum(0),
169                                                    PointerGetDatum(fargtypes),
170                                                    0);
171         if (!HeapTupleIsValid(tuple))
172                 elog(ERROR, "CreateTrigger: function %s() does not exist",
173                          stmt->funcname);
174         if (((Form_pg_proc) GETSTRUCT(tuple))->prorettype != 0)
175                 elog(ERROR, "CreateTrigger: function %s() must return OPAQUE",
176                          stmt->funcname);
177         funcoid = tuple->t_data->t_oid;
178         funclang = ((Form_pg_proc) GETSTRUCT(tuple))->prolang;
179         ReleaseSysCache(tuple);
180
181         if (funclang != ClanguageId && funclang != INTERNALlanguageId)
182         {
183                 HeapTuple       langTup;
184
185                 langTup = SearchSysCache(LANGOID,
186                                                                  ObjectIdGetDatum(funclang),
187                                                                  0, 0, 0);
188                 if (!HeapTupleIsValid(langTup))
189                         elog(ERROR, "CreateTrigger: cache lookup for language %u failed",
190                                  funclang);
191                 if (((Form_pg_language) GETSTRUCT(langTup))->lanispl == false)
192                         elog(ERROR, "CreateTrigger: only internal, C and PL functions are supported");
193                 ReleaseSysCache(langTup);
194         }
195
196         /*
197          * Build the new pg_trigger tuple.
198          */
199         MemSet(nulls, ' ', Natts_pg_trigger * sizeof(char));
200
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);
212
213         if (stmt->args)
214         {
215                 List       *le;
216                 char       *args;
217                 int16           nargs = length(stmt->args);
218                 int                     len = 0;
219
220                 foreach(le, stmt->args)
221                 {
222                         char       *ar = ((Value *) lfirst(le))->val.str;
223
224                         len += strlen(ar) + 4;
225                         for (; *ar; ar++)
226                         {
227                                 if (*ar == '\\')
228                                         len++;
229                         }
230                 }
231                 args = (char *) palloc(len + 1);
232                 args[0] = '\0';
233                 foreach(le, stmt->args)
234                 {
235                         char       *s = ((Value *) lfirst(le))->val.str;
236                         char       *d = args + strlen(args);
237
238                         while (*s)
239                         {
240                                 if (*s == '\\')
241                                         *d++ = '\\';
242                                 *d++ = *s++;
243                         }
244                         strcpy(d, "\\000");
245                 }
246                 values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
247                 values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain,
248                                                                                                   CStringGetDatum(args));
249         }
250         else
251         {
252                 values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
253                 values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain,
254                                                                                                         CStringGetDatum(""));
255         }
256         MemSet(tgattr, 0, FUNC_MAX_ARGS * sizeof(int16));
257         values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
258
259         tuple = heap_formtuple(tgrel->rd_att, values, nulls);
260
261         /*
262          * Insert tuple into pg_trigger.
263          */
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);
270
271         pfree(DatumGetPointer(values[Anum_pg_trigger_tgname - 1]));
272         pfree(DatumGetPointer(values[Anum_pg_trigger_tgargs - 1]));
273
274         /*
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.
278          */
279         pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
280         tuple = SearchSysCacheCopy(RELOID,
281                                                            ObjectIdGetDatum(RelationGetRelid(rel)),
282                                                            0, 0, 0);
283         if (!HeapTupleIsValid(tuple))
284                 elog(ERROR, "CreateTrigger: relation %s not found in pg_class",
285                          stmt->relation->relname);
286
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);
294
295         /*
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...
299          */
300
301         /* Keep lock on target rel until end of xact */
302         heap_close(rel, NoLock);
303 }
304
305 /*
306  * DropTrigger - drop an individual trigger by name
307  */
308 void
309 DropTrigger(Oid relid, const char *trigname)
310 {
311         Relation        rel;
312         Relation        tgrel;
313         SysScanDesc     tgscan;
314         ScanKeyData key;
315         Relation        pgrel;
316         HeapTuple       tuple;
317         Relation        ridescs[Num_pg_class_indices];
318         int                     remaining = 0;
319         int                     found = 0;
320
321         rel = heap_open(relid, AccessExclusiveLock);
322
323         if (rel->rd_rel->relkind != RELKIND_RELATION)
324                 elog(ERROR, "DropTrigger: relation \"%s\" is not a table",
325                          RelationGetRelationName(rel));
326
327         if (!allowSystemTableMods && IsSystemRelationName(RelationGetRelationName(rel)))
328                 elog(ERROR, "DropTrigger: can't drop trigger for system relation %s",
329                          RelationGetRelationName(rel));
330
331         if (!pg_class_ownercheck(relid, GetUserId()))
332                 elog(ERROR, "%s: %s", RelationGetRelationName(rel),
333                          aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
334
335         /*
336          * Search pg_trigger, delete target trigger, count remaining triggers
337          * for relation.  Note this is OK only because we have
338          * AccessExclusiveLock on the rel, so no one else is creating/deleting
339          * triggers on this rel at the same time.
340          */
341         tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
342         ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
343                                                    F_OIDEQ,
344                                                    ObjectIdGetDatum(relid));
345         tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true,
346                                                                 SnapshotNow, 1, &key);
347         while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
348         {
349                 Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
350
351                 if (namestrcmp(&(pg_trigger->tgname), trigname) == 0)
352                 {
353                         /* Delete any comments associated with this trigger */
354                         DeleteComments(tuple->t_data->t_oid, RelationGetRelid(tgrel));
355
356                         simple_heap_delete(tgrel, &tuple->t_self);
357                         found++;
358                 }
359                 else
360                         remaining++;
361         }
362         systable_endscan(tgscan);
363         heap_close(tgrel, RowExclusiveLock);
364
365         if (found == 0)
366                 elog(ERROR, "DropTrigger: there is no trigger %s on relation %s",
367                          trigname, RelationGetRelationName(rel));
368         if (found > 1)                          /* shouldn't happen */
369                 elog(NOTICE, "DropTrigger: found (and deleted) %d triggers %s on relation %s",
370                          found, trigname, RelationGetRelationName(rel));
371
372         /*
373          * Update relation's pg_class entry.  Crucial side-effect: other
374          * backends (and this one too!) are sent SI message to make them
375          * rebuild relcache entries.
376          */
377         pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
378         tuple = SearchSysCacheCopy(RELOID,
379                                                            ObjectIdGetDatum(relid),
380                                                            0, 0, 0);
381         if (!HeapTupleIsValid(tuple))
382                 elog(ERROR, "DropTrigger: relation %s not found in pg_class",
383                          RelationGetRelationName(rel));
384
385         ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = remaining;
386         simple_heap_update(pgrel, &tuple->t_self, tuple);
387         CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
388         CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
389         CatalogCloseIndices(Num_pg_class_indices, ridescs);
390         heap_freetuple(tuple);
391         heap_close(pgrel, RowExclusiveLock);
392
393         /* Keep lock on target rel until end of xact */
394         heap_close(rel, NoLock);
395 }
396
397 /*
398  * Remove all triggers for a relation that's being deleted.
399  */
400 void
401 RelationRemoveTriggers(Relation rel)
402 {
403         Relation        tgrel;
404         SysScanDesc     tgscan;
405         ScanKeyData key;
406         HeapTuple       tup;
407         bool            found = false;
408
409         tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
410         ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
411                                                    F_OIDEQ,
412                                                    ObjectIdGetDatum(RelationGetRelid(rel)));
413         tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true,
414                                                                 SnapshotNow, 1, &key);
415
416         while (HeapTupleIsValid(tup = systable_getnext(tgscan)))
417         {
418                 /* Delete any comments associated with this trigger */
419                 DeleteComments(tup->t_data->t_oid, RelationGetRelid(tgrel));
420
421                 simple_heap_delete(tgrel, &tup->t_self);
422
423                 found = true;
424         }
425
426         systable_endscan(tgscan);
427
428         /*
429          * If we deleted any triggers, must update pg_class entry and advance
430          * command counter to make the updated entry visible. This is fairly
431          * annoying, since we'e just going to drop the durn thing later, but
432          * it's necessary to have a consistent state in case we do
433          * CommandCounterIncrement() below --- if RelationBuildTriggers()
434          * runs, it will complain otherwise. Perhaps RelationBuildTriggers()
435          * shouldn't be so picky...
436          */
437         if (found)
438         {
439                 Relation        pgrel;
440                 Relation        ridescs[Num_pg_class_indices];
441
442                 pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
443                 tup = SearchSysCacheCopy(RELOID,
444                                                                  ObjectIdGetDatum(RelationGetRelid(rel)),
445                                                                  0, 0, 0);
446                 if (!HeapTupleIsValid(tup))
447                         elog(ERROR, "RelationRemoveTriggers: relation %u not found in pg_class",
448                                  RelationGetRelid(rel));
449
450                 ((Form_pg_class) GETSTRUCT(tup))->reltriggers = 0;
451                 simple_heap_update(pgrel, &tup->t_self, tup);
452                 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
453                 CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tup);
454                 CatalogCloseIndices(Num_pg_class_indices, ridescs);
455                 heap_freetuple(tup);
456                 heap_close(pgrel, RowExclusiveLock);
457                 CommandCounterIncrement();
458         }
459
460         /*
461          * Also drop all constraint triggers referencing this relation
462          */
463         ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgconstrrelid,
464                                                    F_OIDEQ,
465                                                    ObjectIdGetDatum(RelationGetRelid(rel)));
466         tgscan = systable_beginscan(tgrel, TriggerConstrRelidIndex, true,
467                                                                 SnapshotNow, 1, &key);
468
469         while (HeapTupleIsValid(tup = systable_getnext(tgscan)))
470         {
471                 Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tup);
472
473                 elog(NOTICE, "DROP TABLE implicitly drops referential integrity trigger from table \"%s\"",
474                          get_rel_name(pg_trigger->tgrelid));
475
476                 DropTrigger(pg_trigger->tgrelid, NameStr(pg_trigger->tgname));
477
478                 /*
479                  * Need to do a command counter increment here to show up new
480                  * pg_class.reltriggers in the next loop iteration (in case there
481                  * are multiple referential integrity action triggers for the same
482                  * FK table defined on the PK table).
483                  */
484                 CommandCounterIncrement();
485         }
486         systable_endscan(tgscan);
487
488         heap_close(tgrel, RowExclusiveLock);
489 }
490
491 /*
492  * Build trigger data to attach to the given relcache entry.
493  *
494  * Note that trigger data must be allocated in CacheMemoryContext
495  * to ensure it survives as long as the relcache entry.  But we
496  * are probably running in a less long-lived working context.
497  */
498 void
499 RelationBuildTriggers(Relation relation)
500 {
501         TriggerDesc *trigdesc;
502         int                     ntrigs = relation->rd_rel->reltriggers;
503         Trigger    *triggers = NULL;
504         int                     found = 0;
505         Relation        tgrel;
506         ScanKeyData skey;
507         SysScanDesc     tgscan;
508         HeapTuple       htup;
509         struct varlena *val;
510         bool            isnull;
511
512         ScanKeyEntryInitialize(&skey,
513                                                    (bits16) 0x0,
514                                                    (AttrNumber) Anum_pg_trigger_tgrelid,
515                                                    (RegProcedure) F_OIDEQ,
516                                                    ObjectIdGetDatum(RelationGetRelid(relation)));
517
518         tgrel = heap_openr(TriggerRelationName, AccessShareLock);
519         tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true,
520                                                                 SnapshotNow, 1, &skey);
521
522         while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
523         {
524                 Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
525                 Trigger    *build;
526
527                 if (found == ntrigs)
528                         elog(ERROR, "RelationBuildTriggers: unexpected record found for rel %s",
529                                  RelationGetRelationName(relation));
530
531                 if (triggers == NULL)
532                         triggers = (Trigger *) MemoryContextAlloc(CacheMemoryContext,
533                                                                                                           sizeof(Trigger));
534                 else
535                         triggers = (Trigger *) repalloc(triggers,
536                                                                                   (found + 1) * sizeof(Trigger));
537                 build = &(triggers[found]);
538
539                 build->tgoid = htup->t_data->t_oid;
540                 build->tgname = MemoryContextStrdup(CacheMemoryContext,
541                                                          DatumGetCString(DirectFunctionCall1(nameout,
542                                                                         NameGetDatum(&pg_trigger->tgname))));
543                 build->tgfoid = pg_trigger->tgfoid;
544                 build->tgtype = pg_trigger->tgtype;
545                 build->tgenabled = pg_trigger->tgenabled;
546                 build->tgisconstraint = pg_trigger->tgisconstraint;
547                 build->tgconstrrelid = pg_trigger->tgconstrrelid;
548                 build->tgdeferrable = pg_trigger->tgdeferrable;
549                 build->tginitdeferred = pg_trigger->tginitdeferred;
550                 build->tgnargs = pg_trigger->tgnargs;
551                 memcpy(build->tgattr, &(pg_trigger->tgattr),
552                            FUNC_MAX_ARGS * sizeof(int16));
553                 if (build->tgnargs > 0)
554                 {
555                         char       *p;
556                         int                     i;
557
558                         val = (struct varlena *) fastgetattr(htup,
559                                                                                                  Anum_pg_trigger_tgargs,
560                                                                                                  tgrel->rd_att, &isnull);
561                         if (isnull)
562                                 elog(ERROR, "RelationBuildTriggers: tgargs IS NULL for rel %s",
563                                          RelationGetRelationName(relation));
564                         p = (char *) VARDATA(val);
565                         build->tgargs = (char **)
566                                 MemoryContextAlloc(CacheMemoryContext,
567                                                                    build->tgnargs * sizeof(char *));
568                         for (i = 0; i < build->tgnargs; i++)
569                         {
570                                 build->tgargs[i] = MemoryContextStrdup(CacheMemoryContext,
571                                                                                                            p);
572                                 p += strlen(p) + 1;
573                         }
574                 }
575                 else
576                         build->tgargs = NULL;
577
578                 found++;
579         }
580
581         systable_endscan(tgscan);
582         heap_close(tgrel, AccessShareLock);
583
584         if (found != ntrigs)
585                 elog(ERROR, "RelationBuildTriggers: %d record(s) not found for rel %s",
586                          ntrigs - found,
587                          RelationGetRelationName(relation));
588
589         /* Build trigdesc */
590         trigdesc = (TriggerDesc *) MemoryContextAlloc(CacheMemoryContext,
591                                                                                                   sizeof(TriggerDesc));
592         MemSet(trigdesc, 0, sizeof(TriggerDesc));
593         trigdesc->triggers = triggers;
594         trigdesc->numtriggers = ntrigs;
595         for (found = 0; found < ntrigs; found++)
596                 InsertTrigger(trigdesc, &(triggers[found]), found);
597
598         relation->trigdesc = trigdesc;
599 }
600
601 /* Insert the given trigger into the appropriate index list(s) for it */
602 static void
603 InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx)
604 {
605         uint16     *n;
606         int               **t,
607                           **tp;
608
609         if (TRIGGER_FOR_ROW(trigger->tgtype))
610         {
611                 /* ROW trigger */
612                 if (TRIGGER_FOR_BEFORE(trigger->tgtype))
613                 {
614                         n = trigdesc->n_before_row;
615                         t = trigdesc->tg_before_row;
616                 }
617                 else
618                 {
619                         n = trigdesc->n_after_row;
620                         t = trigdesc->tg_after_row;
621                 }
622         }
623         else
624         {
625                 /* STATEMENT trigger */
626                 if (TRIGGER_FOR_BEFORE(trigger->tgtype))
627                 {
628                         n = trigdesc->n_before_statement;
629                         t = trigdesc->tg_before_statement;
630                 }
631                 else
632                 {
633                         n = trigdesc->n_after_statement;
634                         t = trigdesc->tg_after_statement;
635                 }
636         }
637
638         if (TRIGGER_FOR_INSERT(trigger->tgtype))
639         {
640                 tp = &(t[TRIGGER_EVENT_INSERT]);
641                 if (*tp == NULL)
642                         *tp = (int *) MemoryContextAlloc(CacheMemoryContext,
643                                                                                          sizeof(int));
644                 else
645                         *tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
646                                                                    sizeof(int));
647                 (*tp)[n[TRIGGER_EVENT_INSERT]] = indx;
648                 (n[TRIGGER_EVENT_INSERT])++;
649         }
650
651         if (TRIGGER_FOR_DELETE(trigger->tgtype))
652         {
653                 tp = &(t[TRIGGER_EVENT_DELETE]);
654                 if (*tp == NULL)
655                         *tp = (int *) MemoryContextAlloc(CacheMemoryContext,
656                                                                                          sizeof(int));
657                 else
658                         *tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
659                                                                    sizeof(int));
660                 (*tp)[n[TRIGGER_EVENT_DELETE]] = indx;
661                 (n[TRIGGER_EVENT_DELETE])++;
662         }
663
664         if (TRIGGER_FOR_UPDATE(trigger->tgtype))
665         {
666                 tp = &(t[TRIGGER_EVENT_UPDATE]);
667                 if (*tp == NULL)
668                         *tp = (int *) MemoryContextAlloc(CacheMemoryContext,
669                                                                                          sizeof(int));
670                 else
671                         *tp = (int *) repalloc(*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
672                                                                    sizeof(int));
673                 (*tp)[n[TRIGGER_EVENT_UPDATE]] = indx;
674                 (n[TRIGGER_EVENT_UPDATE])++;
675         }
676 }
677
678 void
679 FreeTriggerDesc(TriggerDesc *trigdesc)
680 {
681         int               **t;
682         Trigger    *trigger;
683         int                     i;
684
685         if (trigdesc == NULL)
686                 return;
687
688         t = trigdesc->tg_before_statement;
689         for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
690                 if (t[i] != NULL)
691                         pfree(t[i]);
692         t = trigdesc->tg_before_row;
693         for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
694                 if (t[i] != NULL)
695                         pfree(t[i]);
696         t = trigdesc->tg_after_row;
697         for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
698                 if (t[i] != NULL)
699                         pfree(t[i]);
700         t = trigdesc->tg_after_statement;
701         for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
702                 if (t[i] != NULL)
703                         pfree(t[i]);
704
705         trigger = trigdesc->triggers;
706         for (i = 0; i < trigdesc->numtriggers; i++)
707         {
708                 pfree(trigger->tgname);
709                 if (trigger->tgnargs > 0)
710                 {
711                         while (--(trigger->tgnargs) >= 0)
712                                 pfree(trigger->tgargs[trigger->tgnargs]);
713                         pfree(trigger->tgargs);
714                 }
715                 trigger++;
716         }
717         pfree(trigdesc->triggers);
718         pfree(trigdesc);
719 }
720
721 bool
722 equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
723 {
724         int                     i,
725                                 j;
726
727         /*
728          * We need not examine the "index" data, just the trigger array
729          * itself; if we have the same triggers with the same types, the
730          * derived index data should match.
731          */
732         if (trigdesc1 != NULL)
733         {
734                 if (trigdesc2 == NULL)
735                         return false;
736                 if (trigdesc1->numtriggers != trigdesc2->numtriggers)
737                         return false;
738                 for (i = 0; i < trigdesc1->numtriggers; i++)
739                 {
740                         Trigger    *trig1 = trigdesc1->triggers + i;
741                         Trigger    *trig2 = NULL;
742
743                         /*
744                          * We can't assume that the triggers are always read from
745                          * pg_trigger in the same order; so use the trigger OIDs to
746                          * identify the triggers to compare.  (We assume here that the
747                          * same OID won't appear twice in either trigger set.)
748                          */
749                         for (j = 0; j < trigdesc2->numtriggers; j++)
750                         {
751                                 trig2 = trigdesc2->triggers + j;
752                                 if (trig1->tgoid == trig2->tgoid)
753                                         break;
754                         }
755                         if (j >= trigdesc2->numtriggers)
756                                 return false;
757                         if (strcmp(trig1->tgname, trig2->tgname) != 0)
758                                 return false;
759                         if (trig1->tgfoid != trig2->tgfoid)
760                                 return false;
761                         if (trig1->tgtype != trig2->tgtype)
762                                 return false;
763                         if (trig1->tgenabled != trig2->tgenabled)
764                                 return false;
765                         if (trig1->tgisconstraint != trig2->tgisconstraint)
766                                 return false;
767                         if (trig1->tgconstrrelid != trig2->tgconstrrelid)
768                                 return false;
769                         if (trig1->tgdeferrable != trig2->tgdeferrable)
770                                 return false;
771                         if (trig1->tginitdeferred != trig2->tginitdeferred)
772                                 return false;
773                         if (trig1->tgnargs != trig2->tgnargs)
774                                 return false;
775                         if (memcmp(trig1->tgattr, trig2->tgattr,
776                                            sizeof(trig1->tgattr)) != 0)
777                                 return false;
778                         for (j = 0; j < trig1->tgnargs; j++)
779                                 if (strcmp(trig1->tgargs[j], trig2->tgargs[j]) != 0)
780                                         return false;
781                 }
782         }
783         else if (trigdesc2 != NULL)
784                 return false;
785         return true;
786 }
787
788 /*
789  * Call a trigger function.
790  *
791  *              trigdata: trigger descriptor.
792  *              finfo: possibly-cached call info for the function.
793  *              per_tuple_context: memory context to execute the function in.
794  *
795  * Returns the tuple (or NULL) as returned by the function.
796  */
797 static HeapTuple
798 ExecCallTriggerFunc(TriggerData *trigdata,
799                                         FmgrInfo *finfo,
800                                         MemoryContext per_tuple_context)
801 {
802         FunctionCallInfoData fcinfo;
803         Datum           result;
804         MemoryContext oldContext;
805
806         /*
807          * We cache fmgr lookup info, to avoid making the lookup again on each
808          * call.
809          */
810         if (finfo->fn_oid == InvalidOid)
811                 fmgr_info(trigdata->tg_trigger->tgfoid, finfo);
812
813         Assert(finfo->fn_oid == trigdata->tg_trigger->tgfoid);
814
815         /*
816          * Do the function evaluation in the per-tuple memory context, so that
817          * leaked memory will be reclaimed once per tuple. Note in particular
818          * that any new tuple created by the trigger function will live till
819          * the end of the tuple cycle.
820          */
821         oldContext = MemoryContextSwitchTo(per_tuple_context);
822
823         /*
824          * Call the function, passing no arguments but setting a context.
825          */
826         MemSet(&fcinfo, 0, sizeof(fcinfo));
827
828         fcinfo.flinfo = finfo;
829         fcinfo.context = (Node *) trigdata;
830
831         result = FunctionCallInvoke(&fcinfo);
832
833         MemoryContextSwitchTo(oldContext);
834
835         /*
836          * Trigger protocol allows function to return a null pointer, but NOT
837          * to set the isnull result flag.
838          */
839         if (fcinfo.isnull)
840                 elog(ERROR, "ExecCallTriggerFunc: function %u returned NULL",
841                          fcinfo.flinfo->fn_oid);
842
843         return (HeapTuple) DatumGetPointer(result);
844 }
845
846 HeapTuple
847 ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
848                                          HeapTuple trigtuple)
849 {
850         TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
851         int                     ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
852         int                *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
853         HeapTuple       newtuple = trigtuple;
854         HeapTuple       oldtuple;
855         TriggerData LocTriggerData;
856         int                     i;
857
858         /* Allocate cache space for fmgr lookup info, if not done yet */
859         if (relinfo->ri_TrigFunctions == NULL)
860         {
861                 relinfo->ri_TrigFunctions = (FmgrInfo *)
862                         palloc(trigdesc->numtriggers * sizeof(FmgrInfo));
863                 MemSet(relinfo->ri_TrigFunctions, 0,
864                            trigdesc->numtriggers * sizeof(FmgrInfo));
865         }
866
867         LocTriggerData.type = T_TriggerData;
868         LocTriggerData.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
869         LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
870         LocTriggerData.tg_newtuple = NULL;
871         for (i = 0; i < ntrigs; i++)
872         {
873                 Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
874
875                 if (!trigger->tgenabled)
876                         continue;
877                 LocTriggerData.tg_trigtuple = oldtuple = newtuple;
878                 LocTriggerData.tg_trigger = trigger;
879                 newtuple = ExecCallTriggerFunc(&LocTriggerData,
880                                                                    relinfo->ri_TrigFunctions + tgindx[i],
881                                                                            GetPerTupleMemoryContext(estate));
882                 if (oldtuple != newtuple && oldtuple != trigtuple)
883                         heap_freetuple(oldtuple);
884                 if (newtuple == NULL)
885                         break;
886         }
887         return newtuple;
888 }
889
890 void
891 ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo,
892                                          HeapTuple trigtuple)
893 {
894         TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
895
896         if (trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0)
897                 DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_INSERT,
898                                                                  NULL, trigtuple);
899 }
900
901 bool
902 ExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
903                                          ItemPointer tupleid)
904 {
905         TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
906         int                     ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
907         int                *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
908         TriggerData LocTriggerData;
909         HeapTuple       trigtuple;
910         HeapTuple       newtuple = NULL;
911         TupleTableSlot *newSlot;
912         int                     i;
913
914         trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
915         if (trigtuple == NULL)
916                 return false;
917
918         /* Allocate cache space for fmgr lookup info, if not done yet */
919         if (relinfo->ri_TrigFunctions == NULL)
920         {
921                 relinfo->ri_TrigFunctions = (FmgrInfo *)
922                         palloc(trigdesc->numtriggers * sizeof(FmgrInfo));
923                 MemSet(relinfo->ri_TrigFunctions, 0,
924                            trigdesc->numtriggers * sizeof(FmgrInfo));
925         }
926
927         LocTriggerData.type = T_TriggerData;
928         LocTriggerData.tg_event = TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
929         LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
930         LocTriggerData.tg_newtuple = NULL;
931         for (i = 0; i < ntrigs; i++)
932         {
933                 Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
934
935                 if (!trigger->tgenabled)
936                         continue;
937                 LocTriggerData.tg_trigtuple = trigtuple;
938                 LocTriggerData.tg_trigger = trigger;
939                 newtuple = ExecCallTriggerFunc(&LocTriggerData,
940                                                                    relinfo->ri_TrigFunctions + tgindx[i],
941                                                                            GetPerTupleMemoryContext(estate));
942                 if (newtuple == NULL)
943                         break;
944                 if (newtuple != trigtuple)
945                         heap_freetuple(newtuple);
946         }
947         heap_freetuple(trigtuple);
948
949         return (newtuple == NULL) ? false : true;
950 }
951
952 void
953 ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
954                                          ItemPointer tupleid)
955 {
956         TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
957
958         if (trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
959         {
960                 HeapTuple       trigtuple = GetTupleForTrigger(estate, relinfo,
961                                                                                                    tupleid, NULL);
962
963                 DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_DELETE,
964                                                                  trigtuple, NULL);
965                 heap_freetuple(trigtuple);
966         }
967 }
968
969 HeapTuple
970 ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
971                                          ItemPointer tupleid, HeapTuple newtuple)
972 {
973         TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
974         int                     ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
975         int                *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
976         TriggerData LocTriggerData;
977         HeapTuple       trigtuple;
978         HeapTuple       oldtuple;
979         HeapTuple       intuple = newtuple;
980         TupleTableSlot *newSlot;
981         int                     i;
982
983         trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
984         if (trigtuple == NULL)
985                 return NULL;
986
987         /*
988          * In READ COMMITTED isolevel it's possible that newtuple was changed
989          * due to concurrent update.
990          */
991         if (newSlot != NULL)
992                 intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot);
993
994         /* Allocate cache space for fmgr lookup info, if not done yet */
995         if (relinfo->ri_TrigFunctions == NULL)
996         {
997                 relinfo->ri_TrigFunctions = (FmgrInfo *)
998                         palloc(trigdesc->numtriggers * sizeof(FmgrInfo));
999                 MemSet(relinfo->ri_TrigFunctions, 0,
1000                            trigdesc->numtriggers * sizeof(FmgrInfo));
1001         }
1002
1003         LocTriggerData.type = T_TriggerData;
1004         LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
1005         LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
1006         for (i = 0; i < ntrigs; i++)
1007         {
1008                 Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
1009
1010                 if (!trigger->tgenabled)
1011                         continue;
1012                 LocTriggerData.tg_trigtuple = trigtuple;
1013                 LocTriggerData.tg_newtuple = oldtuple = newtuple;
1014                 LocTriggerData.tg_trigger = trigger;
1015                 newtuple = ExecCallTriggerFunc(&LocTriggerData,
1016                                                                    relinfo->ri_TrigFunctions + tgindx[i],
1017                                                                            GetPerTupleMemoryContext(estate));
1018                 if (oldtuple != newtuple && oldtuple != intuple)
1019                         heap_freetuple(oldtuple);
1020                 if (newtuple == NULL)
1021                         break;
1022         }
1023         heap_freetuple(trigtuple);
1024         return newtuple;
1025 }
1026
1027 void
1028 ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
1029                                          ItemPointer tupleid, HeapTuple newtuple)
1030 {
1031         TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
1032
1033         if (trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0)
1034         {
1035                 HeapTuple       trigtuple = GetTupleForTrigger(estate, relinfo,
1036                                                                                                    tupleid, NULL);
1037
1038                 DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_UPDATE,
1039                                                                  trigtuple, newtuple);
1040                 heap_freetuple(trigtuple);
1041         }
1042 }
1043
1044
1045 static HeapTuple
1046 GetTupleForTrigger(EState *estate, ResultRelInfo *relinfo,
1047                                    ItemPointer tid, TupleTableSlot **newSlot)
1048 {
1049         Relation        relation = relinfo->ri_RelationDesc;
1050         HeapTupleData tuple;
1051         HeapTuple       result;
1052         Buffer          buffer;
1053
1054         if (newSlot != NULL)
1055         {
1056                 int                     test;
1057
1058                 /*
1059                  * mark tuple for update
1060                  */
1061                 *newSlot = NULL;
1062                 tuple.t_self = *tid;
1063 ltrmark:;
1064                 test = heap_mark4update(relation, &tuple, &buffer);
1065                 switch (test)
1066                 {
1067                         case HeapTupleSelfUpdated:
1068                                 ReleaseBuffer(buffer);
1069                                 return (NULL);
1070
1071                         case HeapTupleMayBeUpdated:
1072                                 break;
1073
1074                         case HeapTupleUpdated:
1075                                 ReleaseBuffer(buffer);
1076                                 if (XactIsoLevel == XACT_SERIALIZABLE)
1077                                         elog(ERROR, "Can't serialize access due to concurrent update");
1078                                 else if (!(ItemPointerEquals(&(tuple.t_self), tid)))
1079                                 {
1080                                         TupleTableSlot *epqslot = EvalPlanQual(estate,
1081                                                                                          relinfo->ri_RangeTableIndex,
1082                                                                                                                 &(tuple.t_self));
1083
1084                                         if (!(TupIsNull(epqslot)))
1085                                         {
1086                                                 *tid = tuple.t_self;
1087                                                 *newSlot = epqslot;
1088                                                 goto ltrmark;
1089                                         }
1090                                 }
1091
1092                                 /*
1093                                  * if tuple was deleted or PlanQual failed for updated
1094                                  * tuple - we have not process this tuple!
1095                                  */
1096                                 return (NULL);
1097
1098                         default:
1099                                 ReleaseBuffer(buffer);
1100                                 elog(ERROR, "Unknown status %u from heap_mark4update", test);
1101                                 return (NULL);
1102                 }
1103         }
1104         else
1105         {
1106                 PageHeader      dp;
1107                 ItemId          lp;
1108
1109                 buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
1110
1111                 if (!BufferIsValid(buffer))
1112                         elog(ERROR, "GetTupleForTrigger: failed ReadBuffer");
1113
1114                 dp = (PageHeader) BufferGetPage(buffer);
1115                 lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
1116
1117                 Assert(ItemIdIsUsed(lp));
1118
1119                 tuple.t_datamcxt = NULL;
1120                 tuple.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
1121                 tuple.t_len = ItemIdGetLength(lp);
1122                 tuple.t_self = *tid;
1123         }
1124
1125         result = heap_copytuple(&tuple);
1126         ReleaseBuffer(buffer);
1127
1128         return result;
1129 }
1130
1131
1132 /* ----------
1133  * Deferred trigger stuff
1134  * ----------
1135  */
1136
1137
1138 /* ----------
1139  * Internal data to the deferred trigger mechanism is held
1140  * during entire session in a global context created at startup and
1141  * over statements/commands in a separate context which
1142  * is created at transaction start and destroyed at transaction end.
1143  * ----------
1144  */
1145 static MemoryContext deftrig_gcxt = NULL;
1146 static MemoryContext deftrig_cxt = NULL;
1147
1148 /* ----------
1149  * Global data that tells which triggers are actually in
1150  * state IMMEDIATE or DEFERRED.
1151  * ----------
1152  */
1153 static bool deftrig_dfl_all_isset = false;
1154 static bool deftrig_dfl_all_isdeferred = false;
1155 static List *deftrig_dfl_trigstates = NIL;
1156
1157 static bool deftrig_all_isset;
1158 static bool deftrig_all_isdeferred;
1159 static List *deftrig_trigstates;
1160
1161 /* ----------
1162  * The list of pending deferred trigger events during the current transaction.
1163  *
1164  * deftrig_events is the head, deftrig_event_tail is the last entry.
1165  * Because this can grow pretty large, we don't use separate List nodes,
1166  * but instead thread the list through the dte_next fields of the member
1167  * nodes.  Saves just a few bytes per entry, but that adds up.
1168  *
1169  * XXX Need to be able to shove this data out to a file if it grows too
1170  *         large...
1171  * ----------
1172  */
1173 static DeferredTriggerEvent deftrig_events;
1174 static DeferredTriggerEvent deftrig_event_tail;
1175
1176
1177 /* ----------
1178  * deferredTriggerCheckState()
1179  *
1180  *      Returns true if the trigger identified by tgoid is actually
1181  *      in state DEFERRED.
1182  * ----------
1183  */
1184 static bool
1185 deferredTriggerCheckState(Oid tgoid, int32 itemstate)
1186 {
1187         MemoryContext oldcxt;
1188         List       *sl;
1189         DeferredTriggerStatus trigstate;
1190
1191         /*
1192          * Not deferrable triggers (i.e. normal AFTER ROW triggers and
1193          * constraints declared NOT DEFERRABLE, the state is allways false.
1194          */
1195         if ((itemstate & TRIGGER_DEFERRED_DEFERRABLE) == 0)
1196                 return false;
1197
1198         /*
1199          * Lookup if we know an individual state for this trigger
1200          */
1201         foreach(sl, deftrig_trigstates)
1202         {
1203                 trigstate = (DeferredTriggerStatus) lfirst(sl);
1204                 if (trigstate->dts_tgoid == tgoid)
1205                         return trigstate->dts_tgisdeferred;
1206         }
1207
1208         /*
1209          * No individual state known - so if the user issued a SET CONSTRAINT
1210          * ALL ..., we return that instead of the triggers default state.
1211          */
1212         if (deftrig_all_isset)
1213                 return deftrig_all_isdeferred;
1214
1215         /*
1216          * No ALL state known either, remember the default state as the
1217          * current and return that.
1218          */
1219         oldcxt = MemoryContextSwitchTo(deftrig_cxt);
1220
1221         trigstate = (DeferredTriggerStatus)
1222                 palloc(sizeof(DeferredTriggerStatusData));
1223         trigstate->dts_tgoid = tgoid;
1224         trigstate->dts_tgisdeferred =
1225                 ((itemstate & TRIGGER_DEFERRED_INITDEFERRED) != 0);
1226         deftrig_trigstates = lappend(deftrig_trigstates, trigstate);
1227
1228         MemoryContextSwitchTo(oldcxt);
1229
1230         return trigstate->dts_tgisdeferred;
1231 }
1232
1233
1234 /* ----------
1235  * deferredTriggerAddEvent()
1236  *
1237  *      Add a new trigger event to the queue.
1238  * ----------
1239  */
1240 static void
1241 deferredTriggerAddEvent(DeferredTriggerEvent event)
1242 {
1243         /*
1244          * Since the event list could grow quite long, we keep track of the
1245          * list tail and append there, rather than just doing a stupid
1246          * "lappend". This avoids O(N^2) behavior for large numbers of events.
1247          */
1248         event->dte_next = NULL;
1249         if (deftrig_event_tail == NULL)
1250         {
1251                 /* first list entry */
1252                 deftrig_events = event;
1253                 deftrig_event_tail = event;
1254         }
1255         else
1256         {
1257                 deftrig_event_tail->dte_next = event;
1258                 deftrig_event_tail = event;
1259         }
1260 }
1261
1262
1263 /* ----------
1264  * DeferredTriggerExecute()
1265  *
1266  *      Fetch the required tuples back from the heap and fire one
1267  *      single trigger function.
1268  *
1269  *      Frequently, this will be fired many times in a row for triggers of
1270  *      a single relation.      Therefore, we cache the open relation and provide
1271  *      fmgr lookup cache space at the caller level.
1272  *
1273  *      event: event currently being fired.
1274  *      itemno: item within event currently being fired.
1275  *      rel: open relation for event.
1276  *      finfo: array of fmgr lookup cache entries (one per trigger of relation).
1277  *      per_tuple_context: memory context to call trigger function in.
1278  * ----------
1279  */
1280 static void
1281 DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
1282                                            Relation rel, FmgrInfo *finfo,
1283                                            MemoryContext per_tuple_context)
1284 {
1285         Oid                     tgoid = event->dte_item[itemno].dti_tgoid;
1286         TriggerDesc *trigdesc = rel->trigdesc;
1287         TriggerData LocTriggerData;
1288         HeapTupleData oldtuple;
1289         HeapTupleData newtuple;
1290         HeapTuple       rettuple;
1291         Buffer          oldbuffer;
1292         Buffer          newbuffer;
1293         int                     tgindx;
1294
1295         /*
1296          * Fetch the required OLD and NEW tuples.
1297          */
1298         if (ItemPointerIsValid(&(event->dte_oldctid)))
1299         {
1300                 ItemPointerCopy(&(event->dte_oldctid), &(oldtuple.t_self));
1301                 heap_fetch(rel, SnapshotAny, &oldtuple, &oldbuffer, NULL);
1302                 if (!oldtuple.t_data)
1303                         elog(ERROR, "DeferredTriggerExecute: failed to fetch old tuple");
1304         }
1305
1306         if (ItemPointerIsValid(&(event->dte_newctid)))
1307         {
1308                 ItemPointerCopy(&(event->dte_newctid), &(newtuple.t_self));
1309                 heap_fetch(rel, SnapshotAny, &newtuple, &newbuffer, NULL);
1310                 if (!newtuple.t_data)
1311                         elog(ERROR, "DeferredTriggerExecute: failed to fetch new tuple");
1312         }
1313
1314         /*
1315          * Setup the trigger information
1316          */
1317         LocTriggerData.type = T_TriggerData;
1318         LocTriggerData.tg_event = (event->dte_event & TRIGGER_EVENT_OPMASK) |
1319                 TRIGGER_EVENT_ROW;
1320         LocTriggerData.tg_relation = rel;
1321
1322         LocTriggerData.tg_trigger = NULL;
1323         for (tgindx = 0; tgindx < trigdesc->numtriggers; tgindx++)
1324         {
1325                 if (trigdesc->triggers[tgindx].tgoid == tgoid)
1326                 {
1327                         LocTriggerData.tg_trigger = &(trigdesc->triggers[tgindx]);
1328                         break;
1329                 }
1330         }
1331         if (LocTriggerData.tg_trigger == NULL)
1332                 elog(ERROR, "DeferredTriggerExecute: can't find trigger %u", tgoid);
1333
1334         switch (event->dte_event & TRIGGER_EVENT_OPMASK)
1335         {
1336                 case TRIGGER_EVENT_INSERT:
1337                         LocTriggerData.tg_trigtuple = &newtuple;
1338                         LocTriggerData.tg_newtuple = NULL;
1339                         break;
1340
1341                 case TRIGGER_EVENT_UPDATE:
1342                         LocTriggerData.tg_trigtuple = &oldtuple;
1343                         LocTriggerData.tg_newtuple = &newtuple;
1344                         break;
1345
1346                 case TRIGGER_EVENT_DELETE:
1347                         LocTriggerData.tg_trigtuple = &oldtuple;
1348                         LocTriggerData.tg_newtuple = NULL;
1349                         break;
1350         }
1351
1352         /*
1353          * Call the trigger and throw away an eventually returned updated
1354          * tuple.
1355          */
1356         rettuple = ExecCallTriggerFunc(&LocTriggerData,
1357                                                                    finfo + tgindx,
1358                                                                    per_tuple_context);
1359         if (rettuple != NULL && rettuple != &oldtuple && rettuple != &newtuple)
1360                 heap_freetuple(rettuple);
1361
1362         /*
1363          * Might have been a referential integrity constraint trigger. Reset
1364          * the snapshot overriding flag.
1365          */
1366         ReferentialIntegritySnapshotOverride = false;
1367
1368         /*
1369          * Release buffers
1370          */
1371         if (ItemPointerIsValid(&(event->dte_oldctid)))
1372                 ReleaseBuffer(oldbuffer);
1373         if (ItemPointerIsValid(&(event->dte_newctid)))
1374                 ReleaseBuffer(newbuffer);
1375 }
1376
1377
1378 /* ----------
1379  * deferredTriggerInvokeEvents()
1380  *
1381  *      Scan the event queue for not yet invoked triggers. Check if they
1382  *      should be invoked now and do so.
1383  * ----------
1384  */
1385 static void
1386 deferredTriggerInvokeEvents(bool immediate_only)
1387 {
1388         DeferredTriggerEvent event,
1389                                 prev_event = NULL;
1390         MemoryContext per_tuple_context;
1391         Relation        rel = NULL;
1392         FmgrInfo   *finfo = NULL;
1393
1394         /*
1395          * If immediate_only is true, we remove fully-processed events from
1396          * the event queue to recycle space.  If immediate_only is false,
1397          * we are going to discard the whole event queue on return anyway,
1398          * so no need to bother with "retail" pfree's.
1399          *
1400          * In a scenario with many commands in a transaction and many
1401          * deferred-to-end-of-transaction triggers, it could get annoying
1402          * to rescan all the deferred triggers at each command end.
1403          * To speed this up, we could remember the actual end of the queue at
1404          * EndQuery and examine only events that are newer. On state changes
1405          * we simply reset the saved position to the beginning of the queue
1406          * and process all events once with the new states.
1407          */
1408
1409         /* Make a per-tuple memory context for trigger function calls */
1410         per_tuple_context =
1411                 AllocSetContextCreate(CurrentMemoryContext,
1412                                                           "DeferredTriggerTupleContext",
1413                                                           ALLOCSET_DEFAULT_MINSIZE,
1414                                                           ALLOCSET_DEFAULT_INITSIZE,
1415                                                           ALLOCSET_DEFAULT_MAXSIZE);
1416
1417         event = deftrig_events;
1418         while (event != NULL)
1419         {
1420                 bool            still_deferred_ones = false;
1421                 DeferredTriggerEvent next_event;
1422                 int                     i;
1423
1424                 /*
1425                  * Check if event is already completely done.
1426                  */
1427                 if (! (event->dte_event & (TRIGGER_DEFERRED_DONE |
1428                                                                    TRIGGER_DEFERRED_CANCELED)))
1429                 {
1430                         MemoryContextReset(per_tuple_context);
1431
1432                         /*
1433                          * Check each trigger item in the event.
1434                          */
1435                         for (i = 0; i < event->dte_n_items; i++)
1436                         {
1437                                 if (event->dte_item[i].dti_state & TRIGGER_DEFERRED_DONE)
1438                                         continue;
1439
1440                                 /*
1441                                  * This trigger item hasn't been called yet. Check if we
1442                                  * should call it now.
1443                                  */
1444                                 if (immediate_only &&
1445                                         deferredTriggerCheckState(event->dte_item[i].dti_tgoid,
1446                                                                                           event->dte_item[i].dti_state))
1447                                 {
1448                                         still_deferred_ones = true;
1449                                         continue;
1450                                 }
1451
1452                                 /*
1453                                  * So let's fire it... but first, open the correct relation
1454                                  * if this is not the same relation as before.
1455                                  */
1456                                 if (rel == NULL || rel->rd_id != event->dte_relid)
1457                                 {
1458                                         if (rel)
1459                                                 heap_close(rel, NoLock);
1460                                         if (finfo)
1461                                                 pfree(finfo);
1462
1463                                         /*
1464                                          * We assume that an appropriate lock is still held by the
1465                                          * executor, so grab no new lock here.
1466                                          */
1467                                         rel = heap_open(event->dte_relid, NoLock);
1468
1469                                         /*
1470                                          * Allocate space to cache fmgr lookup info for triggers
1471                                          * of this relation.
1472                                          */
1473                                         finfo = (FmgrInfo *)
1474                                                 palloc(rel->trigdesc->numtriggers * sizeof(FmgrInfo));
1475                                         MemSet(finfo, 0,
1476                                                    rel->trigdesc->numtriggers * sizeof(FmgrInfo));
1477                                 }
1478
1479                                 DeferredTriggerExecute(event, i, rel, finfo,
1480                                                                            per_tuple_context);
1481
1482                                 event->dte_item[i].dti_state |= TRIGGER_DEFERRED_DONE;
1483                         } /* end loop over items within event */
1484                 }
1485
1486                 /*
1487                  * If it's now completely done, throw it away.
1488                  *
1489                  * NB: it's possible the trigger calls above added more events to the
1490                  * queue, or that calls we will do later will want to add more,
1491                  * so we have to be careful about maintaining list validity here.
1492                  */
1493                 next_event = event->dte_next;
1494
1495                 if (still_deferred_ones)
1496                 {
1497                         /* Not done, keep in list */
1498                         prev_event = event;
1499                 }
1500                 else
1501                 {
1502                         /* Done */
1503                         if (immediate_only)
1504                         {
1505                                 /* delink it from list and free it */
1506                                 if (prev_event)
1507                                         prev_event->dte_next = next_event;
1508                                 else
1509                                         deftrig_events = next_event;
1510                                 pfree(event);
1511                         }
1512                         else
1513                         {
1514                                 /*
1515                                  * We will clean up later, but just for paranoia's sake,
1516                                  * mark the event done.
1517                                  */
1518                                 event->dte_event |= TRIGGER_DEFERRED_DONE;
1519                         }
1520                 }
1521
1522                 event = next_event;
1523         }
1524
1525         /* Update list tail pointer in case we just deleted tail event */
1526         deftrig_event_tail = prev_event;
1527
1528         /* Release working resources */
1529         if (rel)
1530                 heap_close(rel, NoLock);
1531         if (finfo)
1532                 pfree(finfo);
1533         MemoryContextDelete(per_tuple_context);
1534 }
1535
1536
1537 /* ----------
1538  * DeferredTriggerInit()
1539  *
1540  *      Initialize the deferred trigger mechanism. This is called during
1541  *      backend startup and is guaranteed to be before the first of all
1542  *      transactions.
1543  * ----------
1544  */
1545 void
1546 DeferredTriggerInit(void)
1547 {
1548         /*
1549          * Since this context will never be reset, give it a minsize of 0.
1550          * This avoids using any memory if the session never stores anything.
1551          */
1552         deftrig_gcxt = AllocSetContextCreate(TopMemoryContext,
1553                                                                                  "DeferredTriggerSession",
1554                                                                                  0,
1555                                                                                  ALLOCSET_DEFAULT_INITSIZE,
1556                                                                                  ALLOCSET_DEFAULT_MAXSIZE);
1557 }
1558
1559
1560 /* ----------
1561  * DeferredTriggerBeginXact()
1562  *
1563  *      Called at transaction start (either BEGIN or implicit for single
1564  *      statement outside of transaction block).
1565  * ----------
1566  */
1567 void
1568 DeferredTriggerBeginXact(void)
1569 {
1570         MemoryContext oldcxt;
1571         List       *l;
1572         DeferredTriggerStatus dflstat;
1573         DeferredTriggerStatus stat;
1574
1575         if (deftrig_cxt != NULL)
1576                 elog(ERROR,
1577                    "DeferredTriggerBeginXact() called while inside transaction");
1578
1579         /*
1580          * Create the per transaction memory context and copy all states from
1581          * the per session context to here.  Set the minsize to 0 to avoid
1582          * wasting memory if there is no deferred trigger data.
1583          */
1584         deftrig_cxt = AllocSetContextCreate(TopTransactionContext,
1585                                                                                 "DeferredTriggerXact",
1586                                                                                 0,
1587                                                                                 ALLOCSET_DEFAULT_INITSIZE,
1588                                                                                 ALLOCSET_DEFAULT_MAXSIZE);
1589         oldcxt = MemoryContextSwitchTo(deftrig_cxt);
1590
1591         deftrig_all_isset = deftrig_dfl_all_isset;
1592         deftrig_all_isdeferred = deftrig_dfl_all_isdeferred;
1593
1594         deftrig_trigstates = NIL;
1595         foreach(l, deftrig_dfl_trigstates)
1596         {
1597                 dflstat = (DeferredTriggerStatus) lfirst(l);
1598                 stat = (DeferredTriggerStatus)
1599                         palloc(sizeof(DeferredTriggerStatusData));
1600
1601                 stat->dts_tgoid = dflstat->dts_tgoid;
1602                 stat->dts_tgisdeferred = dflstat->dts_tgisdeferred;
1603
1604                 deftrig_trigstates = lappend(deftrig_trigstates, stat);
1605         }
1606
1607         MemoryContextSwitchTo(oldcxt);
1608
1609         deftrig_events = NULL;
1610         deftrig_event_tail = NULL;
1611 }
1612
1613
1614 /* ----------
1615  * DeferredTriggerEndQuery()
1616  *
1617  *      Called after one query sent down by the user has completely been
1618  *      processed. At this time we invoke all outstanding IMMEDIATE triggers.
1619  * ----------
1620  */
1621 void
1622 DeferredTriggerEndQuery(void)
1623 {
1624         /*
1625          * Ignore call if we aren't in a transaction.
1626          */
1627         if (deftrig_cxt == NULL)
1628                 return;
1629
1630         deferredTriggerInvokeEvents(true);
1631 }
1632
1633
1634 /* ----------
1635  * DeferredTriggerEndXact()
1636  *
1637  *      Called just before the current transaction is committed. At this
1638  *      time we invoke all DEFERRED triggers and tidy up.
1639  * ----------
1640  */
1641 void
1642 DeferredTriggerEndXact(void)
1643 {
1644         /*
1645          * Ignore call if we aren't in a transaction.
1646          */
1647         if (deftrig_cxt == NULL)
1648                 return;
1649
1650         deferredTriggerInvokeEvents(false);
1651
1652         MemoryContextDelete(deftrig_cxt);
1653         deftrig_cxt = NULL;
1654 }
1655
1656
1657 /* ----------
1658  * DeferredTriggerAbortXact()
1659  *
1660  *      The current transaction has entered the abort state.
1661  *      All outstanding triggers are canceled so we simply throw
1662  *      away anything we know.
1663  * ----------
1664  */
1665 void
1666 DeferredTriggerAbortXact(void)
1667 {
1668         /*
1669          * Ignore call if we aren't in a transaction.
1670          */
1671         if (deftrig_cxt == NULL)
1672                 return;
1673
1674         MemoryContextDelete(deftrig_cxt);
1675         deftrig_cxt = NULL;
1676 }
1677
1678
1679 /* ----------
1680  * DeferredTriggerSetState()
1681  *
1682  *      Called for the users SET CONSTRAINTS ... utility command.
1683  * ----------
1684  */
1685 void
1686 DeferredTriggerSetState(ConstraintsSetStmt *stmt)
1687 {
1688         Relation        tgrel;
1689         List       *l;
1690         List       *ls;
1691         List       *loid = NIL;
1692         MemoryContext oldcxt;
1693         bool            found;
1694         DeferredTriggerStatus state;
1695
1696         /*
1697          * Handle SET CONSTRAINTS ALL ...
1698          */
1699         if (stmt->constraints == NIL)
1700         {
1701                 if (!IsTransactionBlock())
1702                 {
1703                         /*
1704                          * ... outside of a transaction block
1705                          *
1706                          * Drop all information about individual trigger states per
1707                          * session.
1708                          */
1709                         l = deftrig_dfl_trigstates;
1710                         while (l != NIL)
1711                         {
1712                                 List       *next = lnext(l);
1713
1714                                 pfree(lfirst(l));
1715                                 pfree(l);
1716                                 l = next;
1717                         }
1718                         deftrig_dfl_trigstates = NIL;
1719
1720                         /*
1721                          * Set the session ALL state to known.
1722                          */
1723                         deftrig_dfl_all_isset = true;
1724                         deftrig_dfl_all_isdeferred = stmt->deferred;
1725
1726                         return;
1727                 }
1728                 else
1729                 {
1730                         /*
1731                          * ... inside of a transaction block
1732                          *
1733                          * Drop all information about individual trigger states per
1734                          * transaction.
1735                          */
1736                         l = deftrig_trigstates;
1737                         while (l != NIL)
1738                         {
1739                                 List       *next = lnext(l);
1740
1741                                 pfree(lfirst(l));
1742                                 pfree(l);
1743                                 l = next;
1744                         }
1745                         deftrig_trigstates = NIL;
1746
1747                         /*
1748                          * Set the per transaction ALL state to known.
1749                          */
1750                         deftrig_all_isset = true;
1751                         deftrig_all_isdeferred = stmt->deferred;
1752
1753                         return;
1754                 }
1755         }
1756
1757         /* ----------
1758          * Handle SET CONSTRAINTS constraint-name [, ...]
1759          * First lookup all trigger Oid's for the constraint names.
1760          * ----------
1761          */
1762         tgrel = heap_openr(TriggerRelationName, AccessShareLock);
1763
1764         foreach(l, stmt->constraints)
1765         {
1766                 char       *cname = strVal(lfirst(l));
1767                 ScanKeyData skey;
1768                 SysScanDesc     tgscan;
1769                 HeapTuple       htup;
1770
1771                 /*
1772                  * Check that only named constraints are set explicitly
1773                  */
1774                 if (strlen(cname) == 0)
1775                         elog(ERROR, "unnamed constraints cannot be set explicitly");
1776
1777                 /*
1778                  * Setup to scan pg_trigger by tgconstrname ...
1779                  */
1780                 ScanKeyEntryInitialize(&skey,
1781                                                            (bits16) 0x0,
1782                                                            (AttrNumber) Anum_pg_trigger_tgconstrname,
1783                                                            (RegProcedure) F_NAMEEQ,
1784                                                            PointerGetDatum(cname));
1785
1786                 tgscan = systable_beginscan(tgrel, TriggerConstrNameIndex, true,
1787                                                                         SnapshotNow, 1, &skey);
1788
1789                 /*
1790                  * ... and search for the constraint trigger row
1791                  */
1792                 found = false;
1793
1794                 while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
1795                 {
1796                         Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
1797                         Oid                     constr_oid;
1798
1799                         /*
1800                          * If we found some, check that they fit the deferrability but
1801                          * skip ON <event> RESTRICT ones, since they are silently
1802                          * never deferrable.
1803                          */
1804                         if (stmt->deferred && !pg_trigger->tgdeferrable &&
1805                                 pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_UPD &&
1806                                 pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_DEL)
1807                                 elog(ERROR, "Constraint '%s' is not deferrable",
1808                                          cname);
1809
1810                         constr_oid = htup->t_data->t_oid;
1811                         loid = lappendi(loid, constr_oid);
1812                         found = true;
1813                 }
1814
1815                 systable_endscan(tgscan);
1816
1817                 /*
1818                  * Not found ?
1819                  */
1820                 if (!found)
1821                         elog(ERROR, "Constraint '%s' does not exist", cname);
1822         }
1823         heap_close(tgrel, AccessShareLock);
1824
1825         if (!IsTransactionBlock())
1826         {
1827                 /*
1828                  * Outside of a transaction block set the trigger states of
1829                  * individual triggers on session level.
1830                  */
1831                 oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
1832
1833                 foreach(l, loid)
1834                 {
1835                         found = false;
1836                         foreach(ls, deftrig_dfl_trigstates)
1837                         {
1838                                 state = (DeferredTriggerStatus) lfirst(ls);
1839                                 if (state->dts_tgoid == (Oid) lfirsti(l))
1840                                 {
1841                                         state->dts_tgisdeferred = stmt->deferred;
1842                                         found = true;
1843                                         break;
1844                                 }
1845                         }
1846                         if (!found)
1847                         {
1848                                 state = (DeferredTriggerStatus)
1849                                         palloc(sizeof(DeferredTriggerStatusData));
1850                                 state->dts_tgoid = (Oid) lfirsti(l);
1851                                 state->dts_tgisdeferred = stmt->deferred;
1852
1853                                 deftrig_dfl_trigstates =
1854                                         lappend(deftrig_dfl_trigstates, state);
1855                         }
1856                 }
1857
1858                 MemoryContextSwitchTo(oldcxt);
1859
1860                 return;
1861         }
1862         else
1863         {
1864                 /*
1865                  * Inside of a transaction block set the trigger states of
1866                  * individual triggers on transaction level.
1867                  */
1868                 oldcxt = MemoryContextSwitchTo(deftrig_cxt);
1869
1870                 foreach(l, loid)
1871                 {
1872                         found = false;
1873                         foreach(ls, deftrig_trigstates)
1874                         {
1875                                 state = (DeferredTriggerStatus) lfirst(ls);
1876                                 if (state->dts_tgoid == (Oid) lfirsti(l))
1877                                 {
1878                                         state->dts_tgisdeferred = stmt->deferred;
1879                                         found = true;
1880                                         break;
1881                                 }
1882                         }
1883                         if (!found)
1884                         {
1885                                 state = (DeferredTriggerStatus)
1886                                         palloc(sizeof(DeferredTriggerStatusData));
1887                                 state->dts_tgoid = (Oid) lfirsti(l);
1888                                 state->dts_tgisdeferred = stmt->deferred;
1889
1890                                 deftrig_trigstates =
1891                                         lappend(deftrig_trigstates, state);
1892                         }
1893                 }
1894
1895                 MemoryContextSwitchTo(oldcxt);
1896
1897                 return;
1898         }
1899 }
1900
1901
1902 /* ----------
1903  * DeferredTriggerSaveEvent()
1904  *
1905  *      Called by ExecAR...Triggers() to add the event to the queue.
1906  *
1907  *      NOTE: should be called only if we've determined that an event must
1908  *      be added to the queue.
1909  * ----------
1910  */
1911 static void
1912 DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
1913                                                  HeapTuple oldtup, HeapTuple newtup)
1914 {
1915         Relation        rel = relinfo->ri_RelationDesc;
1916         TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
1917         MemoryContext oldcxt;
1918         DeferredTriggerEvent new_event;
1919         int                     new_size;
1920         int                     i;
1921         int                     ntriggers;
1922         int                *tgindx;
1923         ItemPointerData oldctid;
1924         ItemPointerData newctid;
1925         TriggerData LocTriggerData;
1926
1927         if (deftrig_cxt == NULL)
1928                 elog(ERROR,
1929                          "DeferredTriggerSaveEvent() called outside of transaction");
1930
1931         /*
1932          * Get the CTID's of OLD and NEW
1933          */
1934         if (oldtup != NULL)
1935                 ItemPointerCopy(&(oldtup->t_self), &(oldctid));
1936         else
1937                 ItemPointerSetInvalid(&(oldctid));
1938         if (newtup != NULL)
1939                 ItemPointerCopy(&(newtup->t_self), &(newctid));
1940         else
1941                 ItemPointerSetInvalid(&(newctid));
1942
1943         /*
1944          * Create a new event
1945          */
1946         oldcxt = MemoryContextSwitchTo(deftrig_cxt);
1947
1948         ntriggers = trigdesc->n_after_row[event];
1949         tgindx = trigdesc->tg_after_row[event];
1950         new_size = offsetof(DeferredTriggerEventData, dte_item[0]) +
1951                 ntriggers * sizeof(DeferredTriggerEventItem);
1952
1953         new_event = (DeferredTriggerEvent) palloc(new_size);
1954         new_event->dte_next = NULL;
1955         new_event->dte_event = event & TRIGGER_EVENT_OPMASK;
1956         new_event->dte_relid = rel->rd_id;
1957         ItemPointerCopy(&oldctid, &(new_event->dte_oldctid));
1958         ItemPointerCopy(&newctid, &(new_event->dte_newctid));
1959         new_event->dte_n_items = ntriggers;
1960         for (i = 0; i < ntriggers; i++)
1961         {
1962                 Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
1963
1964                 new_event->dte_item[i].dti_tgoid = trigger->tgoid;
1965                 new_event->dte_item[i].dti_state =
1966                         ((trigger->tgdeferrable) ?
1967                          TRIGGER_DEFERRED_DEFERRABLE : 0) |
1968                         ((trigger->tginitdeferred) ?
1969                          TRIGGER_DEFERRED_INITDEFERRED : 0) |
1970                         ((trigdesc->n_before_row[event] > 0) ?
1971                          TRIGGER_DEFERRED_HAS_BEFORE : 0);
1972         }
1973
1974         MemoryContextSwitchTo(oldcxt);
1975
1976         switch (event & TRIGGER_EVENT_OPMASK)
1977         {
1978                 case TRIGGER_EVENT_INSERT:
1979                         /* nothing to do */
1980                         break;
1981
1982                 case TRIGGER_EVENT_UPDATE:
1983                         /*
1984                          * Check if one of the referenced keys is changed.
1985                          */
1986                         for (i = 0; i < ntriggers; i++)
1987                         {
1988                                 Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
1989                                 bool            is_ri_trigger;
1990                                 bool            key_unchanged;
1991
1992                                 /*
1993                                  * We are interested in RI_FKEY triggers only.
1994                                  */
1995                                 switch (trigger->tgfoid)
1996                                 {
1997                                         case F_RI_FKEY_NOACTION_UPD:
1998                                         case F_RI_FKEY_CASCADE_UPD:
1999                                         case F_RI_FKEY_RESTRICT_UPD:
2000                                         case F_RI_FKEY_SETNULL_UPD:
2001                                         case F_RI_FKEY_SETDEFAULT_UPD:
2002                                                 is_ri_trigger = true;
2003                                                 break;
2004
2005                                         default:
2006                                                 is_ri_trigger = false;
2007                                                 break;
2008                                 }
2009                                 if (!is_ri_trigger)
2010                                         continue;
2011
2012                                 LocTriggerData.type = T_TriggerData;
2013                                 LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE;
2014                                 LocTriggerData.tg_relation = rel;
2015                                 LocTriggerData.tg_trigtuple = oldtup;
2016                                 LocTriggerData.tg_newtuple = newtup;
2017                                 LocTriggerData.tg_trigger = trigger;
2018
2019                                 key_unchanged = RI_FKey_keyequal_upd(&LocTriggerData);
2020
2021                                 if (key_unchanged)
2022                                 {
2023                                         /*
2024                                          * The key hasn't changed, so no need later to invoke
2025                                          * the trigger at all.
2026                                          */
2027                                         new_event->dte_item[i].dti_state |= TRIGGER_DEFERRED_DONE;
2028                                 }
2029                         }
2030
2031                         break;
2032
2033                 case TRIGGER_EVENT_DELETE:
2034                         /* nothing to do */
2035                         break;
2036         }
2037
2038         /*
2039          * Add the new event to the queue.
2040          */
2041         deferredTriggerAddEvent(new_event);
2042 }