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