1 /*-------------------------------------------------------------------------
4 * PostgreSQL TRIGGERs support code.
6 *-------------------------------------------------------------------------
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/trigger.h"
20 #include "executor/executor.h"
21 #include "miscadmin.h"
22 #include "utils/acl.h"
23 #include "utils/builtins.h"
24 #include "utils/inval.h"
25 #include "utils/syscache.h"
27 DLLIMPORT TriggerData *CurrentTriggerData = NULL;
29 void RelationBuildTriggers(Relation relation);
30 void FreeTriggerDesc(Relation relation);
32 static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger);
33 static HeapTuple GetTupleForTrigger(EState *estate, ItemPointer tid,
34 TupleTableSlot **newSlot);
36 extern GlobalMemory CacheCxt;
39 CreateTrigger(CreateTrigStmt *stmt)
42 int16 tgattr[8] = {0};
43 Datum values[Natts_pg_trigger];
44 char nulls[Natts_pg_trigger];
51 Relation idescs[Num_pg_trigger_indices];
52 Relation ridescs[Num_pg_class_indices];
58 if (!allowSystemTableMods && IsSystemRelationName(stmt->relname))
59 elog(ERROR, "CreateTrigger: can't create trigger for system relation %s", stmt->relname);
62 if (!pg_ownercheck(GetPgUserName(), stmt->relname, RELNAME))
63 elog(ERROR, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
66 rel = heap_openr(stmt->relname, AccessExclusiveLock);
68 TRIGGER_CLEAR_TYPE(tgtype);
70 TRIGGER_SETT_BEFORE(tgtype);
72 TRIGGER_SETT_ROW(tgtype);
74 elog(ERROR, "CreateTrigger: STATEMENT triggers are unimplemented, yet");
76 for (i = 0; i < 3 && stmt->actions[i]; i++)
78 switch (stmt->actions[i])
81 if (TRIGGER_FOR_INSERT(tgtype))
82 elog(ERROR, "CreateTrigger: double INSERT event specified");
83 TRIGGER_SETT_INSERT(tgtype);
86 if (TRIGGER_FOR_DELETE(tgtype))
87 elog(ERROR, "CreateTrigger: double DELETE event specified");
88 TRIGGER_SETT_DELETE(tgtype);
91 if (TRIGGER_FOR_UPDATE(tgtype))
92 elog(ERROR, "CreateTrigger: double UPDATE event specified");
93 TRIGGER_SETT_UPDATE(tgtype);
96 elog(ERROR, "CreateTrigger: unknown event specified");
101 /* Scan pg_trigger */
102 tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
103 ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
104 F_OIDEQ, RelationGetRelid(rel));
105 tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
106 while (HeapTupleIsValid(tuple = heap_getnext(tgscan, 0)))
108 Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
110 if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
111 elog(ERROR, "CreateTrigger: trigger %s already defined on relation %s",
112 stmt->trigname, stmt->relname);
116 heap_endscan(tgscan);
118 MemSet(fargtypes, 0, 8 * sizeof(Oid));
119 tuple = SearchSysCacheTuple(PRONAME,
120 PointerGetDatum(stmt->funcname),
122 PointerGetDatum(fargtypes),
124 if (!HeapTupleIsValid(tuple) ||
125 ((Form_pg_proc) GETSTRUCT(tuple))->pronargs != 0)
126 elog(ERROR, "CreateTrigger: function %s() does not exist",
128 if (((Form_pg_proc) GETSTRUCT(tuple))->prorettype != 0)
129 elog(ERROR, "CreateTrigger: function %s() must return OPAQUE",
131 if (((Form_pg_proc) GETSTRUCT(tuple))->prolang != ClanguageId)
135 langTup = SearchSysCacheTuple(LANOID,
136 ObjectIdGetDatum(((Form_pg_proc) GETSTRUCT(tuple))->prolang),
138 if (!HeapTupleIsValid(langTup))
139 elog(ERROR, "CreateTrigger: cache lookup for PL failed");
141 if (((Form_pg_language) GETSTRUCT(langTup))->lanispl == false)
142 elog(ERROR, "CreateTrigger: only C and PL functions are supported");
145 MemSet(nulls, ' ', Natts_pg_trigger * sizeof(char));
147 values[Anum_pg_trigger_tgrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
148 values[Anum_pg_trigger_tgname - 1] = NameGetDatum(namein(stmt->trigname));
149 values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(tuple->t_data->t_oid);
150 values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
155 int16 nargs = length(stmt->args);
158 foreach(le, stmt->args)
160 char *ar = (char *) lfirst(le);
162 len += strlen(ar) + VARHDRSZ;
169 args = (char *) palloc(len + 1);
171 foreach(le, stmt->args)
173 char *s = (char *) lfirst(le);
174 char *d = args + strlen(args);
183 strcat(args, "\\000");
185 values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
186 values[Anum_pg_trigger_tgargs - 1] = PointerGetDatum(byteain(args));
190 values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
191 values[Anum_pg_trigger_tgargs - 1] = PointerGetDatum(byteain(""));
193 values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
195 tuple = heap_formtuple(tgrel->rd_att, values, nulls);
196 heap_insert(tgrel, tuple);
197 CatalogOpenIndices(Num_pg_trigger_indices, Name_pg_trigger_indices, idescs);
198 CatalogIndexInsert(idescs, Num_pg_trigger_indices, tgrel, tuple);
199 CatalogCloseIndices(Num_pg_trigger_indices, idescs);
201 heap_close(tgrel, RowExclusiveLock);
203 pfree(DatumGetPointer(values[Anum_pg_trigger_tgname - 1]));
204 pfree(DatumGetPointer(values[Anum_pg_trigger_tgargs - 1]));
206 /* update pg_class */
207 pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
208 tuple = SearchSysCacheTupleCopy(RELNAME,
209 PointerGetDatum(stmt->relname),
211 if (!HeapTupleIsValid(tuple))
212 elog(ERROR, "CreateTrigger: relation %s not found in pg_class", stmt->relname);
214 ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found + 1;
215 RelationInvalidateHeapTuple(pgrel, tuple);
216 heap_replace(pgrel, &tuple->t_self, tuple, NULL);
217 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
218 CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
219 CatalogCloseIndices(Num_pg_class_indices, ridescs);
221 heap_close(pgrel, RowExclusiveLock);
223 CommandCounterIncrement();
224 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
225 FreeTriggerDesc(rel);
226 rel->rd_rel->reltriggers = found + 1;
227 RelationBuildTriggers(rel);
228 MemoryContextSwitchTo(oldcxt);
229 /* Keep lock on target rel until end of xact */
230 heap_close(rel, NoLock);
234 DropTrigger(DropTrigStmt *stmt)
242 Relation ridescs[Num_pg_class_indices];
243 MemoryContext oldcxt;
248 if (!pg_ownercheck(GetPgUserName(), stmt->relname, RELNAME))
249 elog(ERROR, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
252 rel = heap_openr(stmt->relname, AccessExclusiveLock);
254 tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
255 ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
256 F_OIDEQ, RelationGetRelid(rel));
257 tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
258 while (HeapTupleIsValid(tuple = heap_getnext(tgscan, 0)))
260 Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
262 if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
264 heap_delete(tgrel, &tuple->t_self, NULL);
271 elog(ERROR, "DropTrigger: there is no trigger %s on relation %s",
272 stmt->trigname, stmt->relname);
274 elog(NOTICE, "DropTrigger: found (and deleted) %d triggers %s on relation %s",
275 tgfound, stmt->trigname, stmt->relname);
276 heap_endscan(tgscan);
277 heap_close(tgrel, RowExclusiveLock);
279 /* update pg_class */
280 pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
281 tuple = SearchSysCacheTupleCopy(RELNAME,
282 PointerGetDatum(stmt->relname),
284 if (!HeapTupleIsValid(tuple))
285 elog(ERROR, "DropTrigger: relation %s not found in pg_class", stmt->relname);
287 ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found;
288 RelationInvalidateHeapTuple(pgrel, tuple);
289 heap_replace(pgrel, &tuple->t_self, tuple, NULL);
290 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
291 CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
292 CatalogCloseIndices(Num_pg_class_indices, ridescs);
294 heap_close(pgrel, RowExclusiveLock);
296 CommandCounterIncrement();
297 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
298 FreeTriggerDesc(rel);
299 rel->rd_rel->reltriggers = found;
301 RelationBuildTriggers(rel);
302 MemoryContextSwitchTo(oldcxt);
303 /* Keep lock on target rel until end of xact */
304 heap_close(rel, NoLock);
308 RelationRemoveTriggers(Relation rel)
315 tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
316 ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
317 F_OIDEQ, RelationGetRelid(rel));
319 tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
321 while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0)))
322 heap_delete(tgrel, &tup->t_self, NULL);
324 heap_endscan(tgscan);
325 heap_close(tgrel, RowExclusiveLock);
329 RelationBuildTriggers(Relation relation)
331 TriggerDesc *trigdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
332 int ntrigs = relation->rd_rel->reltriggers;
333 Trigger *triggers = NULL;
336 Form_pg_trigger pg_trigger;
341 RetrieveIndexResult indexRes;
347 MemSet(trigdesc, 0, sizeof(TriggerDesc));
349 ScanKeyEntryInitialize(&skey,
352 (RegProcedure) F_OIDEQ,
353 ObjectIdGetDatum(RelationGetRelid(relation)));
355 tgrel = heap_openr(TriggerRelationName, AccessShareLock);
356 irel = index_openr(TriggerRelidIndex);
357 sd = index_beginscan(irel, false, 1, &skey);
361 indexRes = index_getnext(sd, ForwardScanDirection);
365 tuple.t_self = indexRes->heap_iptr;
366 heap_fetch(tgrel, SnapshotNow, &tuple, &buffer);
371 elog(ERROR, "RelationBuildTriggers: unexpected record found for rel %.*s",
372 NAMEDATALEN, relation->rd_rel->relname.data);
374 pg_trigger = (Form_pg_trigger) GETSTRUCT(&tuple);
376 if (triggers == NULL)
377 triggers = (Trigger *) palloc(sizeof(Trigger));
379 triggers = (Trigger *) repalloc(triggers, (found + 1) * sizeof(Trigger));
380 build = &(triggers[found]);
382 build->tgname = nameout(&(pg_trigger->tgname));
383 build->tgfoid = pg_trigger->tgfoid;
384 build->tgfunc.fn_addr = NULL;
385 build->tgtype = pg_trigger->tgtype;
386 build->tgnargs = pg_trigger->tgnargs;
387 memcpy(build->tgattr, &(pg_trigger->tgattr), 8 * sizeof(int16));
388 val = (struct varlena *) fastgetattr(&tuple,
389 Anum_pg_trigger_tgargs,
390 tgrel->rd_att, &isnull);
392 elog(ERROR, "RelationBuildTriggers: tgargs IS NULL for rel %.*s",
393 NAMEDATALEN, relation->rd_rel->relname.data);
394 if (build->tgnargs > 0)
399 val = (struct varlena *) fastgetattr(&tuple,
400 Anum_pg_trigger_tgargs,
401 tgrel->rd_att, &isnull);
403 elog(ERROR, "RelationBuildTriggers: tgargs IS NULL for rel %.*s",
404 NAMEDATALEN, relation->rd_rel->relname.data);
405 p = (char *) VARDATA(val);
406 build->tgargs = (char **) palloc(build->tgnargs * sizeof(char *));
407 for (i = 0; i < build->tgnargs; i++)
409 build->tgargs[i] = (char *) palloc(strlen(p) + 1);
410 strcpy(build->tgargs[i], p);
415 build->tgargs = NULL;
418 ReleaseBuffer(buffer);
422 elog(ERROR, "RelationBuildTriggers: %d record not found for rel %.*s",
424 NAMEDATALEN, relation->rd_rel->relname.data);
429 heap_close(tgrel, AccessShareLock);
432 trigdesc->triggers = triggers;
433 for (found = 0; found < ntrigs; found++)
435 build = &(triggers[found]);
436 DescribeTrigger(trigdesc, build);
439 relation->trigdesc = trigdesc;
444 FreeTriggerDesc(Relation relation)
446 TriggerDesc *trigdesc = relation->trigdesc;
451 if (trigdesc == NULL)
454 t = trigdesc->tg_before_statement;
455 for (i = 0; i < 3; i++)
458 t = trigdesc->tg_before_row;
459 for (i = 0; i < 3; i++)
462 t = trigdesc->tg_after_row;
463 for (i = 0; i < 3; i++)
466 t = trigdesc->tg_after_statement;
467 for (i = 0; i < 3; i++)
471 trigger = trigdesc->triggers;
472 for (i = 0; i < relation->rd_rel->reltriggers; i++)
474 pfree(trigger->tgname);
475 if (trigger->tgnargs > 0)
477 while (--(trigger->tgnargs) >= 0)
478 pfree(trigger->tgargs[trigger->tgnargs]);
479 pfree(trigger->tgargs);
483 pfree(trigdesc->triggers);
485 relation->trigdesc = NULL;
490 DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
496 if (TRIGGER_FOR_ROW(trigger->tgtype)) /* Is ROW/STATEMENT
499 if (TRIGGER_FOR_BEFORE(trigger->tgtype))
501 n = trigdesc->n_before_row;
502 t = trigdesc->tg_before_row;
506 n = trigdesc->n_after_row;
507 t = trigdesc->tg_after_row;
513 if (TRIGGER_FOR_BEFORE(trigger->tgtype))
515 n = trigdesc->n_before_statement;
516 t = trigdesc->tg_before_statement;
520 n = trigdesc->n_after_statement;
521 t = trigdesc->tg_after_statement;
525 if (TRIGGER_FOR_INSERT(trigger->tgtype))
527 tp = &(t[TRIGGER_EVENT_INSERT]);
529 *tp = (Trigger **) palloc(sizeof(Trigger *));
531 *tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
533 (*tp)[n[TRIGGER_EVENT_INSERT]] = trigger;
534 (n[TRIGGER_EVENT_INSERT])++;
537 if (TRIGGER_FOR_DELETE(trigger->tgtype))
539 tp = &(t[TRIGGER_EVENT_DELETE]);
541 *tp = (Trigger **) palloc(sizeof(Trigger *));
543 *tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
545 (*tp)[n[TRIGGER_EVENT_DELETE]] = trigger;
546 (n[TRIGGER_EVENT_DELETE])++;
549 if (TRIGGER_FOR_UPDATE(trigger->tgtype))
551 tp = &(t[TRIGGER_EVENT_UPDATE]);
553 *tp = (Trigger **) palloc(sizeof(Trigger *));
555 *tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
557 (*tp)[n[TRIGGER_EVENT_UPDATE]] = trigger;
558 (n[TRIGGER_EVENT_UPDATE])++;
564 ExecCallTriggerFunc(Trigger *trigger)
567 if (trigger->tgfunc.fn_addr == NULL)
568 fmgr_info(trigger->tgfoid, &trigger->tgfunc);
570 if (trigger->tgfunc.fn_plhandler != NULL)
572 return (HeapTuple) (*(trigger->tgfunc.fn_plhandler))
576 return (HeapTuple) ((*fmgr_faddr(&trigger->tgfunc)) ());
580 ExecBRInsertTriggers(Relation rel, HeapTuple trigtuple)
582 TriggerData *SaveTriggerData;
583 int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
584 Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
585 HeapTuple newtuple = trigtuple;
589 SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
590 SaveTriggerData->tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
591 SaveTriggerData->tg_relation = rel;
592 SaveTriggerData->tg_newtuple = NULL;
593 for (i = 0; i < ntrigs; i++)
595 CurrentTriggerData = SaveTriggerData;
596 CurrentTriggerData->tg_trigtuple = oldtuple = newtuple;
597 CurrentTriggerData->tg_trigger = trigger[i];
598 newtuple = ExecCallTriggerFunc(trigger[i]);
599 if (newtuple == NULL)
601 else if (oldtuple != newtuple && oldtuple != trigtuple)
604 CurrentTriggerData = NULL;
605 pfree(SaveTriggerData);
610 ExecARInsertTriggers(Relation rel, HeapTuple trigtuple)
612 TriggerData *SaveTriggerData;
613 int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT];
614 Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_INSERT];
617 SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
618 SaveTriggerData->tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
619 SaveTriggerData->tg_relation = rel;
620 SaveTriggerData->tg_newtuple = NULL;
621 for (i = 0; i < ntrigs; i++)
623 CurrentTriggerData = SaveTriggerData;
624 CurrentTriggerData->tg_trigtuple = trigtuple;
625 CurrentTriggerData->tg_trigger = trigger[i];
626 ExecCallTriggerFunc(trigger[i]);
628 CurrentTriggerData = NULL;
629 pfree(SaveTriggerData);
634 ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
636 Relation rel = estate->es_result_relation_info->ri_RelationDesc;
637 TriggerData *SaveTriggerData;
638 int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
639 Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
641 HeapTuple newtuple = NULL;
642 TupleTableSlot *newSlot;
645 trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot);
646 if (trigtuple == NULL)
649 SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
650 SaveTriggerData->tg_event = TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
651 SaveTriggerData->tg_relation = rel;
652 SaveTriggerData->tg_newtuple = NULL;
653 for (i = 0; i < ntrigs; i++)
655 CurrentTriggerData = SaveTriggerData;
656 CurrentTriggerData->tg_trigtuple = trigtuple;
657 CurrentTriggerData->tg_trigger = trigger[i];
658 newtuple = ExecCallTriggerFunc(trigger[i]);
659 if (newtuple == NULL)
661 if (newtuple != trigtuple)
664 CurrentTriggerData = NULL;
665 pfree(SaveTriggerData);
668 return (newtuple == NULL) ? false : true;
672 ExecARDeleteTriggers(EState *estate, ItemPointer tupleid)
674 Relation rel = estate->es_result_relation_info->ri_RelationDesc;
675 TriggerData *SaveTriggerData;
676 int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE];
677 Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_DELETE];
681 trigtuple = GetTupleForTrigger(estate, tupleid, NULL);
682 Assert(trigtuple != NULL);
684 SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
685 SaveTriggerData->tg_event = TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW;
686 SaveTriggerData->tg_relation = rel;
687 SaveTriggerData->tg_newtuple = NULL;
688 for (i = 0; i < ntrigs; i++)
690 CurrentTriggerData = SaveTriggerData;
691 CurrentTriggerData->tg_trigtuple = trigtuple;
692 CurrentTriggerData->tg_trigger = trigger[i];
693 ExecCallTriggerFunc(trigger[i]);
695 CurrentTriggerData = NULL;
696 pfree(SaveTriggerData);
702 ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
704 Relation rel = estate->es_result_relation_info->ri_RelationDesc;
705 TriggerData *SaveTriggerData;
706 int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
707 Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
710 HeapTuple intuple = newtuple;
711 TupleTableSlot *newSlot;
714 trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot);
715 if (trigtuple == NULL)
719 * In READ COMMITTED isolevel it's possible that newtuple was changed
720 * due to concurrent update.
723 intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot);
725 SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
726 SaveTriggerData->tg_event = TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
727 SaveTriggerData->tg_relation = rel;
728 for (i = 0; i < ntrigs; i++)
730 CurrentTriggerData = SaveTriggerData;
731 CurrentTriggerData->tg_trigtuple = trigtuple;
732 CurrentTriggerData->tg_newtuple = oldtuple = newtuple;
733 CurrentTriggerData->tg_trigger = trigger[i];
734 newtuple = ExecCallTriggerFunc(trigger[i]);
735 if (newtuple == NULL)
737 else if (oldtuple != newtuple && oldtuple != intuple)
740 CurrentTriggerData = NULL;
741 pfree(SaveTriggerData);
747 ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
749 Relation rel = estate->es_result_relation_info->ri_RelationDesc;
750 TriggerData *SaveTriggerData;
751 int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE];
752 Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_UPDATE];
756 trigtuple = GetTupleForTrigger(estate, tupleid, NULL);
757 Assert(trigtuple != NULL);
759 SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
760 SaveTriggerData->tg_event = TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW;
761 SaveTriggerData->tg_relation = rel;
762 for (i = 0; i < ntrigs; i++)
764 CurrentTriggerData = SaveTriggerData;
765 CurrentTriggerData->tg_trigtuple = trigtuple;
766 CurrentTriggerData->tg_newtuple = newtuple;
767 CurrentTriggerData->tg_trigger = trigger[i];
768 ExecCallTriggerFunc(trigger[i]);
770 CurrentTriggerData = NULL;
771 pfree(SaveTriggerData);
776 extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid);
779 GetTupleForTrigger(EState *estate, ItemPointer tid, TupleTableSlot **newSlot)
781 Relation relation = estate->es_result_relation_info->ri_RelationDesc;
791 * mark tuple for update
796 test = heap_mark4update(relation, &tuple, &buffer);
799 case HeapTupleSelfUpdated:
800 ReleaseBuffer(buffer);
803 case HeapTupleMayBeUpdated:
806 case HeapTupleUpdated:
807 ReleaseBuffer(buffer);
808 if (XactIsoLevel == XACT_SERIALIZABLE)
809 elog(ERROR, "Can't serialize access due to concurrent update");
810 else if (!(ItemPointerEquals(&(tuple.t_self), tid)))
812 TupleTableSlot *epqslot = EvalPlanQual(estate,
813 estate->es_result_relation_info->ri_RangeTableIndex,
816 if (!(TupIsNull(epqslot)))
825 * if tuple was deleted or PlanQual failed for updated
826 * tuple - we have not process this tuple!
831 ReleaseBuffer(buffer);
832 elog(ERROR, "Unknown status %u from heap_mark4update", test);
841 buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
843 if (!BufferIsValid(buffer))
844 elog(ERROR, "GetTupleForTrigger: failed ReadBuffer");
846 dp = (PageHeader) BufferGetPage(buffer);
847 lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
849 Assert(ItemIdIsUsed(lp));
851 tuple.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
852 tuple.t_len = ItemIdGetLength(lp);
856 result = heap_copytuple(&tuple);
857 ReleaseBuffer(buffer);