diff options
Diffstat (limited to 'src/backend/commands/trigger.c')
-rw-r--r-- | src/backend/commands/trigger.c | 225 |
1 files changed, 207 insertions, 18 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index cb5cc434f3f..58d93a07998 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -19,6 +19,7 @@ #include "catalog/pg_trigger.h" #include "access/genam.h" #include "access/heapam.h" +#include "access/valid.h" #include "access/xact.h" #include "storage/lmgr.h" #include "storage/bufmgr.h" @@ -37,13 +38,16 @@ TriggerData *CurrentTriggerData = NULL; void RelationBuildTriggers(Relation relation); void FreeTriggerDesc(Relation relation); -static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger); +static void DescribeTrigger(TriggerDesc * trigdesc, Trigger * trigger); +static HeapTuple +GetTupleForTrigger(Relation relation, ItemPointer tid, + bool before); -extern void fmgr_info(Oid procedureId, func_ptr *function, int *nargs); +extern void fmgr_info(Oid procedureId, func_ptr * function, int *nargs); extern GlobalMemory CacheCxt; void -CreateTrigger(CreateTrigStmt *stmt) +CreateTrigger(CreateTrigStmt * stmt) { int16 tgtype; int16 tgattr[8] = {0}; @@ -211,7 +215,7 @@ CreateTrigger(CreateTrigStmt *stmt) } void -DropTrigger(DropTrigStmt *stmt) +DropTrigger(DropTrigStmt * stmt) { Relation rel; Relation tgrel; @@ -481,7 +485,7 @@ FreeTriggerDesc(Relation relation) } static void -DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger) +DescribeTrigger(TriggerDesc * trigdesc, Trigger * trigger) { uint16 *n; Trigger ***t, @@ -555,64 +559,249 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger) } HeapTuple -ExecBRInsertTriggers(Relation rel, HeapTuple tuple) +ExecBRInsertTriggers(Relation rel, HeapTuple trigtuple) { + TriggerData *SaveTriggerData; int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT]; Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_INSERT]; - HeapTuple newtuple = tuple; + HeapTuple newtuple = trigtuple; + HeapTuple oldtuple; int nargs; int i; - CurrentTriggerData = (TriggerData *) palloc(sizeof(TriggerData)); - CurrentTriggerData->tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW; - CurrentTriggerData->tg_relation = rel; - CurrentTriggerData->tg_newtuple = NULL; + SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData)); + SaveTriggerData->tg_event = + TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE; + SaveTriggerData->tg_relation = rel; + SaveTriggerData->tg_newtuple = NULL; for (i = 0; i < ntrigs; i++) { - CurrentTriggerData->tg_trigtuple = newtuple; + CurrentTriggerData = SaveTriggerData; + CurrentTriggerData->tg_trigtuple = oldtuple = newtuple; CurrentTriggerData->tg_trigger = trigger[i]; if (trigger[i]->tgfunc == NULL) fmgr_info(trigger[i]->tgfoid, &(trigger[i]->tgfunc), &nargs); newtuple = (HeapTuple) ((*(trigger[i]->tgfunc)) ()); if (newtuple == NULL) break; + else if (oldtuple != newtuple && oldtuple != trigtuple) + pfree(oldtuple); } - pfree(CurrentTriggerData); CurrentTriggerData = NULL; + pfree(SaveTriggerData); return (newtuple); } void -ExecARInsertTriggers(Relation rel, HeapTuple tuple) +ExecARInsertTriggers(Relation rel, HeapTuple trigtuple) { + TriggerData *SaveTriggerData; + int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT]; + Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_INSERT]; + int nargs; + int i; + SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData)); + SaveTriggerData->tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW; + SaveTriggerData->tg_relation = rel; + SaveTriggerData->tg_newtuple = NULL; + for (i = 0; i < ntrigs; i++) + { + CurrentTriggerData = SaveTriggerData; + CurrentTriggerData->tg_trigtuple = trigtuple; + CurrentTriggerData->tg_trigger = trigger[i]; + if (trigger[i]->tgfunc == NULL) + fmgr_info(trigger[i]->tgfoid, &(trigger[i]->tgfunc), &nargs); + (void) ((*(trigger[i]->tgfunc)) ()); + } + CurrentTriggerData = NULL; + pfree(SaveTriggerData); return; } bool ExecBRDeleteTriggers(Relation rel, ItemPointer tupleid) { + TriggerData *SaveTriggerData; + int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_DELETE]; + Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE]; + HeapTuple trigtuple; + HeapTuple newtuple = NULL; + int nargs; + int i; + + trigtuple = GetTupleForTrigger(rel, tupleid, true); + if (trigtuple == NULL) + return (false); - return (true); + SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData)); + SaveTriggerData->tg_event = + TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE; + SaveTriggerData->tg_relation = rel; + SaveTriggerData->tg_newtuple = NULL; + for (i = 0; i < ntrigs; i++) + { + CurrentTriggerData = SaveTriggerData; + CurrentTriggerData->tg_trigtuple = trigtuple; + CurrentTriggerData->tg_trigger = trigger[i]; + if (trigger[i]->tgfunc == NULL) + fmgr_info(trigger[i]->tgfoid, &(trigger[i]->tgfunc), &nargs); + newtuple = (HeapTuple) ((*(trigger[i]->tgfunc)) ()); + if (newtuple == NULL) + break; + } + CurrentTriggerData = NULL; + pfree(SaveTriggerData); + pfree(trigtuple); + + return ((newtuple == NULL) ? false : true); } void ExecARDeleteTriggers(Relation rel, ItemPointer tupleid) { + TriggerData *SaveTriggerData; + int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE]; + Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_DELETE]; + HeapTuple trigtuple; + int nargs; + int i; + trigtuple = GetTupleForTrigger(rel, tupleid, false); + Assert(trigtuple != NULL); + + SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData)); + SaveTriggerData->tg_event = + TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW; + SaveTriggerData->tg_relation = rel; + SaveTriggerData->tg_newtuple = NULL; + for (i = 0; i < ntrigs; i++) + { + CurrentTriggerData = SaveTriggerData; + CurrentTriggerData->tg_trigtuple = trigtuple; + CurrentTriggerData->tg_trigger = trigger[i]; + if (trigger[i]->tgfunc == NULL) + fmgr_info(trigger[i]->tgfoid, &(trigger[i]->tgfunc), &nargs); + (void) ((*(trigger[i]->tgfunc)) ()); + } + CurrentTriggerData = NULL; + pfree(SaveTriggerData); + pfree(trigtuple); return; } HeapTuple -ExecBRUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple tuple) +ExecBRUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple newtuple) { + TriggerData *SaveTriggerData; + int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE]; + Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE]; + HeapTuple trigtuple; + HeapTuple oldtuple; + HeapTuple intuple = newtuple; + int nargs; + int i; - return (tuple); + trigtuple = GetTupleForTrigger(rel, tupleid, true); + if (trigtuple == NULL) + return (NULL); + + SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData)); + SaveTriggerData->tg_event = + TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE; + SaveTriggerData->tg_relation = rel; + for (i = 0; i < ntrigs; i++) + { + CurrentTriggerData = SaveTriggerData; + CurrentTriggerData->tg_trigtuple = trigtuple; + CurrentTriggerData->tg_newtuple = oldtuple = newtuple; + CurrentTriggerData->tg_trigger = trigger[i]; + if (trigger[i]->tgfunc == NULL) + fmgr_info(trigger[i]->tgfoid, &(trigger[i]->tgfunc), &nargs); + newtuple = (HeapTuple) ((*(trigger[i]->tgfunc)) ()); + if (newtuple == NULL) + break; + else if (oldtuple != newtuple && oldtuple != intuple) + pfree(oldtuple); + } + CurrentTriggerData = NULL; + pfree(SaveTriggerData); + pfree(trigtuple); + return (newtuple); } void -ExecARUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple tuple) +ExecARUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple newtuple) { + TriggerData *SaveTriggerData; + int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE]; + Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_UPDATE]; + HeapTuple trigtuple; + int nargs; + int i; + + trigtuple = GetTupleForTrigger(rel, tupleid, false); + Assert(trigtuple != NULL); + SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData)); + SaveTriggerData->tg_event = + TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW; + SaveTriggerData->tg_relation = rel; + for (i = 0; i < ntrigs; i++) + { + CurrentTriggerData = SaveTriggerData; + CurrentTriggerData->tg_trigtuple = trigtuple; + CurrentTriggerData->tg_newtuple = newtuple; + CurrentTriggerData->tg_trigger = trigger[i]; + if (trigger[i]->tgfunc == NULL) + fmgr_info(trigger[i]->tgfoid, &(trigger[i]->tgfunc), &nargs); + (void) ((*(trigger[i]->tgfunc)) ()); + } + CurrentTriggerData = NULL; + pfree(SaveTriggerData); + pfree(trigtuple); return; } + +static HeapTuple +GetTupleForTrigger(Relation relation, ItemPointer tid, bool before) +{ + ItemId lp; + HeapTuple tuple; + PageHeader dp; + Buffer b; + + b = ReadBuffer(relation, ItemPointerGetBlockNumber(tid)); + + if (!BufferIsValid(b)) + elog(WARN, "GetTupleForTrigger: failed ReadBuffer"); + + dp = (PageHeader) BufferGetPage(b); + lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid)); + + Assert(ItemIdIsUsed(lp)); + + tuple = (HeapTuple) PageGetItem((Page) dp, lp); + + if (before) + { + if (TupleUpdatedByCurXactAndCmd(tuple)) + { + elog(NOTICE, "GetTupleForTrigger: Non-functional delete/update"); + ReleaseBuffer(b); + return (NULL); + } + + if (!(tuple = heap_tuple_satisfies(lp, relation, b, dp, + NowTimeQual, 0, (ScanKey) NULL))) + { + ReleaseBuffer(b); + elog(WARN, "GetTupleForTrigger: (am)invalid tid"); + } + } + + tuple = heap_copytuple(tuple); + ReleaseBuffer(b); + + return (tuple); +} |