⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 trigger.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
							  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 + -