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