📄 trigger.c
字号:
true, NULL, trigtuple);}voidExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo){ TriggerDesc *trigdesc; int ntrigs; int *tgindx; int i; TriggerData LocTriggerData; trigdesc = relinfo->ri_TrigDesc; if (trigdesc == NULL) return; ntrigs = trigdesc->n_before_statement[TRIGGER_EVENT_DELETE]; tgindx = trigdesc->tg_before_statement[TRIGGER_EVENT_DELETE]; if (ntrigs == 0) return; LocTriggerData.type = T_TriggerData; LocTriggerData.tg_event = TRIGGER_EVENT_DELETE | TRIGGER_EVENT_BEFORE; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; LocTriggerData.tg_trigtuple = NULL; LocTriggerData.tg_newtuple = NULL; LocTriggerData.tg_trigtuplebuf = InvalidBuffer; LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < ntrigs; i++) { Trigger *trigger = &trigdesc->triggers[tgindx[i]]; HeapTuple newtuple; if (!trigger->tgenabled) continue; LocTriggerData.tg_trigger = trigger; newtuple = ExecCallTriggerFunc(&LocTriggerData, tgindx[i], relinfo->ri_TrigFunctions, relinfo->ri_TrigInstrument, GetPerTupleMemoryContext(estate)); if (newtuple) ereport(ERROR, (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), errmsg("BEFORE STATEMENT trigger cannot return a value"))); }}voidExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo){ TriggerDesc *trigdesc = relinfo->ri_TrigDesc; if (trigdesc && trigdesc->n_after_statement[TRIGGER_EVENT_DELETE] > 0) AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_DELETE, false, NULL, NULL);}boolExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, CommandId cid){ TriggerDesc *trigdesc = relinfo->ri_TrigDesc; int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_DELETE]; int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_DELETE]; bool result = true; TriggerData LocTriggerData; HeapTuple trigtuple; HeapTuple newtuple; TupleTableSlot *newSlot; int i; trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, cid, &newSlot); if (trigtuple == NULL) return false; LocTriggerData.type = T_TriggerData; LocTriggerData.tg_event = TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; LocTriggerData.tg_newtuple = NULL; LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < ntrigs; i++) { Trigger *trigger = &trigdesc->triggers[tgindx[i]]; if (!trigger->tgenabled) continue; LocTriggerData.tg_trigtuple = trigtuple; LocTriggerData.tg_trigtuplebuf = InvalidBuffer; LocTriggerData.tg_trigger = trigger; newtuple = ExecCallTriggerFunc(&LocTriggerData, tgindx[i], relinfo->ri_TrigFunctions, relinfo->ri_TrigInstrument, GetPerTupleMemoryContext(estate)); if (newtuple == NULL) { result = false; /* tell caller to suppress delete */ break; } if (newtuple != trigtuple) heap_freetuple(newtuple); } heap_freetuple(trigtuple); return result;}voidExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid){ TriggerDesc *trigdesc = relinfo->ri_TrigDesc; if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0) { HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, (CommandId) 0, NULL); AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_DELETE, true, trigtuple, NULL); heap_freetuple(trigtuple); }}voidExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo){ TriggerDesc *trigdesc; int ntrigs; int *tgindx; int i; TriggerData LocTriggerData; trigdesc = relinfo->ri_TrigDesc; if (trigdesc == NULL) return; ntrigs = trigdesc->n_before_statement[TRIGGER_EVENT_UPDATE]; tgindx = trigdesc->tg_before_statement[TRIGGER_EVENT_UPDATE]; if (ntrigs == 0) return; LocTriggerData.type = T_TriggerData; LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_BEFORE; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; LocTriggerData.tg_trigtuple = NULL; LocTriggerData.tg_newtuple = NULL; LocTriggerData.tg_trigtuplebuf = InvalidBuffer; LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < ntrigs; i++) { Trigger *trigger = &trigdesc->triggers[tgindx[i]]; HeapTuple newtuple; if (!trigger->tgenabled) continue; LocTriggerData.tg_trigger = trigger; newtuple = ExecCallTriggerFunc(&LocTriggerData, tgindx[i], relinfo->ri_TrigFunctions, relinfo->ri_TrigInstrument, GetPerTupleMemoryContext(estate)); if (newtuple) ereport(ERROR, (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), errmsg("BEFORE STATEMENT trigger cannot return a value"))); }}voidExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo){ TriggerDesc *trigdesc = relinfo->ri_TrigDesc; if (trigdesc && trigdesc->n_after_statement[TRIGGER_EVENT_UPDATE] > 0) AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_UPDATE, false, NULL, NULL);}HeapTupleExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple newtuple, CommandId cid){ TriggerDesc *trigdesc = relinfo->ri_TrigDesc; int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_UPDATE]; int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE]; TriggerData LocTriggerData; HeapTuple trigtuple; HeapTuple oldtuple; HeapTuple intuple = newtuple; TupleTableSlot *newSlot; int i; trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, cid, &newSlot); if (trigtuple == NULL) return NULL; /* * In READ COMMITTED isolation level it's possible that newtuple was * changed due to concurrent update. */ if (newSlot != NULL) intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot); LocTriggerData.type = T_TriggerData; LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; for (i = 0; i < ntrigs; i++) { Trigger *trigger = &trigdesc->triggers[tgindx[i]]; if (!trigger->tgenabled) continue; LocTriggerData.tg_trigtuple = trigtuple; LocTriggerData.tg_newtuple = oldtuple = newtuple; LocTriggerData.tg_trigtuplebuf = InvalidBuffer; LocTriggerData.tg_newtuplebuf = InvalidBuffer; LocTriggerData.tg_trigger = trigger; newtuple = ExecCallTriggerFunc(&LocTriggerData, tgindx[i], relinfo->ri_TrigFunctions, relinfo->ri_TrigInstrument, GetPerTupleMemoryContext(estate)); if (oldtuple != newtuple && oldtuple != intuple) heap_freetuple(oldtuple); if (newtuple == NULL) break; } heap_freetuple(trigtuple); return newtuple;}voidExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple newtuple){ TriggerDesc *trigdesc = relinfo->ri_TrigDesc; if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0) { HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, (CommandId) 0, NULL); AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_UPDATE, true, trigtuple, newtuple); heap_freetuple(trigtuple); }}static HeapTupleGetTupleForTrigger(EState *estate, ResultRelInfo *relinfo, ItemPointer tid, CommandId cid, TupleTableSlot **newSlot){ Relation relation = relinfo->ri_RelationDesc; HeapTupleData tuple; HeapTuple result; Buffer buffer; if (newSlot != NULL) { HTSU_Result test; ItemPointerData update_ctid; TransactionId update_xmax; *newSlot = NULL; /* * lock tuple for update */ltrmark:; tuple.t_self = *tid; test = heap_lock_tuple(relation, &tuple, &buffer, &update_ctid, &update_xmax, cid, LockTupleExclusive, false); switch (test) { case HeapTupleSelfUpdated: /* treat it as deleted; do not process */ ReleaseBuffer(buffer); return NULL; case HeapTupleMayBeUpdated: break; case HeapTupleUpdated: ReleaseBuffer(buffer); if (IsXactIsoLevelSerializable) ereport(ERROR, (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), errmsg("could not serialize access due to concurrent update"))); else if (!ItemPointerEquals(&update_ctid, &tuple.t_self)) { /* it was updated, so look at the updated version */ TupleTableSlot *epqslot; epqslot = EvalPlanQual(estate, relinfo->ri_RangeTableIndex, &update_ctid, update_xmax, cid); if (!TupIsNull(epqslot)) { *tid = update_ctid; *newSlot = epqslot; goto ltrmark; } } /* * if tuple was deleted or PlanQual failed for updated tuple - * we have not process this tuple! */ return NULL; default: ReleaseBuffer(buffer); elog(ERROR, "unrecognized heap_lock_tuple status: %u", test); return NULL; /* keep compiler quiet */ } } else { PageHeader dp; ItemId lp; buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid)); dp = (PageHeader) BufferGetPage(buffer); lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid)); Assert(ItemIdIsUsed(lp)); tuple.t_datamcxt = NULL; tuple.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp); tuple.t_len = ItemIdGetLength(lp); tuple.t_self = *tid; tuple.t_tableOid = RelationGetRelid(relation); } result = heap_copytuple(&tuple); ReleaseBuffer(buffer); return result;}/* ---------- * After-trigger stuff * * The AfterTriggersData struct holds data about pending AFTER trigger events * during the current transaction tree. (BEFORE triggers are fired * immediately so we don't need any persistent state about them.) The struct * and most of its subsidiary data are kept in TopTransactionContext; however * the individual event records are kept in CurTransactionContext, so that * they will easily go away during subtransaction abort. * * Because the list of pending events can grow large, we go to some effort * to minimize memory consumption. We do not use the generic List mechanism * but thread the events manually. * * XXX We need to be able to save the per-event data in a file if it grows too * large. * ---------- *//* Per-trigger SET CONSTRAINT status */typedef struct SetConstraintTriggerData{ Oid sct_tgoid; bool sct_tgisdeferred;} SetConstraintTriggerData;typedef struct SetConstraintTriggerData *SetConstraintTrigger;/* * SET CONSTRAINT intra-transaction status. * * We make this a single palloc'd object so it can be copied and freed easily. * * all_isset and all_isdeferred are used to keep track * of SET CONSTRAINTS ALL {DEFERRED, IMMEDIATE}. * * trigstates[] stores per-trigger tgisdeferred settings. */typedef struct SetConstraintStateData{ bool all_isset; bool all_isdeferred; int numstates; /* number of trigstates[] entries in use */ int numalloc; /* allocated size of trigstates[] */ SetConstraintTriggerData trigstates[1]; /* VARIABLE LENGTH ARRAY */} SetConstraintStateData;typedef SetConstraintStateData *SetConstraintState;/* * Per-trigger-event data * * Note: ate_firing_id is meaningful when either AFTER_TRIGGER_DONE * or AFTER_TRIGGER_IN_PROGRESS is set. It indicates which trigger firing * cycle the trigger was or will be fired in. */typedef struct AfterTriggerEventData *AfterTriggerEvent;typedef struct AfterTriggerEventData{ AfterTriggerEvent ate_next; /* list link */ TriggerEvent ate_event; /* event type and status bits */ CommandId ate_firing_id; /* ID for firing cycle */ Oid ate_tgoid; /* the trigger's ID */ Oid ate_relid; /* the relation it's on */ ItemPointerData ate_oldctid; /* specific tuple(s) involved */ ItemPointerData ate_newctid;} AfterTriggerEventData;/* A list of events */typedef struct AfterTriggerEventList{ AfterTriggerEvent head; AfterTriggerEvent tail;} AfterTriggerEventList;/* * All per-transaction data for the AFTER TRIGGERS module. * * AfterTriggersData has the following fields: * * firing_counter is incremented for each call of afterTriggerInvokeEvents. * We mark firable events with the current firing cycle's ID so that we can * tell which ones to work on. This ensures sane behavior if a trigger * function chooses to do SET CONSTRAINTS: the inner SET CONSTRAINTS will * only fire those events that weren't already scheduled for firing. * * state keeps track of the transaction-local effects of SET CONSTRAINTS. * This is saved and restored across failed subtransactions. * * events is the current list of deferred events. This is global across * all subtransactions of the current transaction. In a subtransaction * abort, we know that the events added by the subtransaction are at the * end of the list, so it is relatively easy to discard them. * * query_depth is the current depth of nested AfterTriggerBeginQuery calls * (-1 when the stack is empty). * * query_stack[query_depth] is a list of AFTER trigger events queued by the * current query (and the query_stack entries below it are lists of trigger * events queued by calling queries). None of these are valid until the * matching AfterTriggerEndQuery call occurs. At that point we fire * immediate-mode triggers, and append any deferred events to the main events * list.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -