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