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

📄 trigger.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 5 页
字号:
				 * This trigger item hasn't been called yet. Check if we				 * should call it now.				 */				if (immediate_only &&				  deferredTriggerCheckState(event->dte_item[i].dti_tgoid,											event->dte_item[i].dti_state))				{					still_deferred_ones = true;					continue;				}				/*				 * So let's fire it... but first, open the correct				 * relation if this is not the same relation as before.				 */				if (rel == NULL || rel->rd_id != event->dte_relid)				{					if (rel)						heap_close(rel, NoLock);					FreeTriggerDesc(trigdesc);					if (finfo)						pfree(finfo);					/*					 * We assume that an appropriate lock is still held by					 * the executor, so grab no new lock here.					 */					rel = heap_open(event->dte_relid, NoLock);					/*					 * Copy relation's trigger info so that we have a					 * stable copy no matter what the called triggers do.					 */					trigdesc = CopyTriggerDesc(rel->trigdesc);					if (trigdesc == NULL)		/* should not happen */						elog(ERROR, "relation %u has no triggers",							 event->dte_relid);					/*					 * Allocate space to cache fmgr lookup info for					 * triggers.					 */					finfo = (FmgrInfo *)						palloc0(trigdesc->numtriggers * sizeof(FmgrInfo));				}				DeferredTriggerExecute(event, i, rel, trigdesc, finfo,									   per_tuple_context);				event->dte_item[i].dti_state |= TRIGGER_DEFERRED_DONE;			}					/* end loop over items within event */		}		/*		 * If it's now completely done, throw it away.		 *		 * NB: it's possible the trigger calls above added more events to the		 * queue, or that calls we will do later will want to add more, so		 * we have to be careful about maintaining list validity here.		 */		next_event = event->dte_next;		if (still_deferred_ones)		{			/* Not done, keep in list */			prev_event = event;		}		else		{			/* Done */			if (immediate_only)			{				/* delink it from list and free it */				if (prev_event)					prev_event->dte_next = next_event;				else					deferredTriggers->deftrig_events = next_event;				pfree(event);			}			else			{				/*				 * We will clean up later, but just for paranoia's sake,				 * mark the event done.				 */				event->dte_event |= TRIGGER_DEFERRED_DONE;			}		}		event = next_event;	}	/* Update list tail pointer in case we just deleted tail event */	deferredTriggers->deftrig_event_tail = prev_event;	/* Set the immediate event pointer for next time */	deferredTriggers->deftrig_events_imm = prev_event;	/* Release working resources */	if (rel)		heap_close(rel, NoLock);	FreeTriggerDesc(trigdesc);	if (finfo)		pfree(finfo);	MemoryContextDelete(per_tuple_context);}/* ---------- * DeferredTriggerInit() * *	Initialize the deferred trigger mechanism. This is called during *	backend startup and is guaranteed to be before the first of all *	transactions. * ---------- */voidDeferredTriggerInit(void){	/* Nothing to do */	;}/* ---------- * DeferredTriggerBeginXact() * *	Called at transaction start (either BEGIN or implicit for single *	statement outside of transaction block). * ---------- */voidDeferredTriggerBeginXact(void){	/*	 * This will be changed to a special context when the nested	 * transactions project moves forward.	 */	MemoryContext cxt = TopTransactionContext;	deferredTriggers = (DeferredTriggers) MemoryContextAlloc(TopTransactionContext,										   sizeof(DeferredTriggersData));	/*	 * Create the per transaction memory context	 */	deferredTriggers->deftrig_cxt = AllocSetContextCreate(cxt,												   "DeferredTriggerXact",												ALLOCSET_DEFAULT_MINSIZE,											   ALLOCSET_DEFAULT_INITSIZE,											   ALLOCSET_DEFAULT_MAXSIZE);	/*	 * If unspecified, constraints default to IMMEDIATE, per SQL	 */	deferredTriggers->deftrig_all_isdeferred = false;	deferredTriggers->deftrig_all_isset = false;	deferredTriggers->deftrig_trigstates = NIL;	deferredTriggers->deftrig_events = NULL;	deferredTriggers->deftrig_events_imm = NULL;	deferredTriggers->deftrig_event_tail = NULL;}/* ---------- * DeferredTriggerEndQuery() * *	Called after one query sent down by the user has completely been *	processed. At this time we invoke all outstanding IMMEDIATE triggers. * ---------- */voidDeferredTriggerEndQuery(void){	/*	 * Ignore call if we aren't in a transaction.	 */	if (deferredTriggers == NULL)		return;	deferredTriggerInvokeEvents(true);}/* ---------- * DeferredTriggerEndXact() * *	Called just before the current transaction is committed. At this *	time we invoke all DEFERRED triggers and tidy up. * ---------- */voidDeferredTriggerEndXact(void){	/*	 * Ignore call if we aren't in a transaction.	 */	if (deferredTriggers == NULL)		return;	deferredTriggerInvokeEvents(false);	deferredTriggers = NULL;}/* ---------- * DeferredTriggerAbortXact() * *	The current transaction has entered the abort state. *	All outstanding triggers are canceled so we simply throw *	away anything we know. * ---------- */voidDeferredTriggerAbortXact(void){	/*	 * Ignore call if we aren't in a transaction.	 */	if (deferredTriggers == NULL)		return;	/*	 * Forget everything we know about deferred triggers.	 */	deferredTriggers = NULL;}/* ---------- * DeferredTriggerSetState() * *	Called for the SET CONSTRAINTS ... utility command. * ---------- */voidDeferredTriggerSetState(ConstraintsSetStmt *stmt){	List	   *l;	/*	 * Ignore call if we aren't in a transaction.	 */	if (deferredTriggers == NULL)		return;	/*	 * Handle SET CONSTRAINTS ALL ...	 */	if (stmt->constraints == NIL)	{		/*		 * Drop all per-transaction information about individual trigger		 * states.		 */		l = deferredTriggers->deftrig_trigstates;		while (l != NIL)		{			List	   *next = lnext(l);			pfree(lfirst(l));			pfree(l);			l = next;		}		deferredTriggers->deftrig_trigstates = NIL;		/*		 * Set the per-transaction ALL state to known.		 */		deferredTriggers->deftrig_all_isset = true;		deferredTriggers->deftrig_all_isdeferred = stmt->deferred;	}	else	{		Relation	tgrel;		MemoryContext oldcxt;		bool		found;		DeferredTriggerStatus state;		List	   *ls;		List	   *loid = NIL;		/* ----------		 * Handle SET CONSTRAINTS constraint-name [, ...]		 * First lookup all trigger Oid's for the constraint names.		 * ----------		 */		tgrel = heap_openr(TriggerRelationName, AccessShareLock);		foreach(l, stmt->constraints)		{			char	   *cname = strVal(lfirst(l));			ScanKeyData skey;			SysScanDesc tgscan;			HeapTuple	htup;			/*			 * Check that only named constraints are set explicitly			 */			if (strlen(cname) == 0)				ereport(ERROR,						(errcode(ERRCODE_INVALID_NAME),				errmsg("unnamed constraints cannot be set explicitly")));			/*			 * Setup to scan pg_trigger by tgconstrname ...			 */			ScanKeyEntryInitialize(&skey, (bits16) 0x0,							   (AttrNumber) Anum_pg_trigger_tgconstrname,								   (RegProcedure) F_NAMEEQ,								   PointerGetDatum(cname));			tgscan = systable_beginscan(tgrel, TriggerConstrNameIndex, true,										SnapshotNow, 1, &skey);			/*			 * ... and search for the constraint trigger row			 */			found = false;			while (HeapTupleIsValid(htup = systable_getnext(tgscan)))			{				Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);				Oid			constr_oid;				/*				 * If we found some, check that they fit the deferrability				 * but skip ON <event> RESTRICT ones, since they are				 * silently never deferrable.				 */				if (stmt->deferred && !pg_trigger->tgdeferrable &&					pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_UPD &&					pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_DEL)					ereport(ERROR,							(errcode(ERRCODE_WRONG_OBJECT_TYPE),							 errmsg("constraint \"%s\" is not deferrable",									cname)));				constr_oid = HeapTupleGetOid(htup);				loid = lappendo(loid, constr_oid);				found = true;			}			systable_endscan(tgscan);			/*			 * Not found ?			 */			if (!found)				ereport(ERROR,						(errcode(ERRCODE_UNDEFINED_OBJECT),					 errmsg("constraint \"%s\" does not exist", cname)));		}		heap_close(tgrel, AccessShareLock);		/*		 * Inside of a transaction block set the trigger states of		 * individual triggers on transaction level.		 */		oldcxt = MemoryContextSwitchTo(deferredTriggers->deftrig_cxt);		foreach(l, loid)		{			found = false;			foreach(ls, deferredTriggers->deftrig_trigstates)			{				state = (DeferredTriggerStatus) lfirst(ls);				if (state->dts_tgoid == lfirsto(l))				{					state->dts_tgisdeferred = stmt->deferred;					found = true;					break;				}			}			if (!found)			{				state = (DeferredTriggerStatus)					palloc(sizeof(DeferredTriggerStatusData));				state->dts_tgoid = lfirsto(l);				state->dts_tgisdeferred = stmt->deferred;				deferredTriggers->deftrig_trigstates =					lappend(deferredTriggers->deftrig_trigstates, state);			}		}		MemoryContextSwitchTo(oldcxt);	}	/*	 * SQL99 requires that when a constraint is set to IMMEDIATE, any	 * deferred checks against that constraint must be made when the SET	 * CONSTRAINTS command is executed -- i.e. the effects of the SET	 * CONSTRAINTS command applies retroactively. This happens "for free"	 * since we have already made the necessary modifications to the	 * constraints, and deferredTriggerEndQuery() is called by	 * finish_xact_command().  But we must reset	 * deferredTriggerInvokeEvents' tail pointer to make it rescan the	 * entire list, in case some deferred events are now immediately	 * invokable.	 */	deferredTriggers->deftrig_events_imm = NULL;}/* ---------- * DeferredTriggerSaveEvent() * *	Called by ExecAR...Triggers() to add the event to the queue. * *	NOTE: should be called only if we've determined that an event must *	be added to the queue. * ---------- */static voidDeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event, bool row_trigger,						 HeapTuple oldtup, HeapTuple newtup){	Relation	rel = relinfo->ri_RelationDesc;	TriggerDesc *trigdesc = relinfo->ri_TrigDesc;	MemoryContext oldcxt;	DeferredTriggerEvent new_event;	int			new_size;	int			i;	int			ntriggers;	int			n_enabled_triggers = 0;	int		   *tgindx;	ItemPointerData oldctid;	ItemPointerData newctid;	if (deferredTriggers == NULL)		elog(ERROR, "DeferredTriggerSaveEvent() called outside of transaction");	/*	 * Get the CTID's of OLD and NEW	 */	if (oldtup != NULL)		ItemPointerCopy(&(oldtup->t_self), &(oldctid));	else		ItemPointerSetInvalid(&(oldctid));	if (newtup != NULL)		ItemPointerCopy(&(newtup->t_self), &(newctid));	else		ItemPointerSetInvalid(&(newctid));	if (row_trigger)	{		ntriggers = trigdesc->n_after_row[event];		tgindx = trigdesc->tg_after_row[event];	}	else	{		ntriggers = trigdesc->n_after_statement[event];		tgindx = trigdesc->tg_after_statement[event];	}	/*	 * Count the number of triggers that are actually enabled. Since we	 * only add enabled triggers to the queue, we only need allocate	 * enough space to hold them (and not any disabled triggers that may	 * be associated with the relation).	 */	for (i = 0; i < ntriggers; i++)	{		Trigger    *trigger = &trigdesc->triggers[tgindx[i]];		if (trigger->tgenabled)			n_enabled_triggers++;	}	/*	 * If all the triggers on this relation are disabled, we're done.	 */	if (n_enabled_triggers == 0)		return;	/*	 * Create a new event	 */	oldcxt = MemoryContextSwitchTo(deferredTriggers->deftrig_cxt);	new_size = offsetof(DeferredTriggerEventData, dte_item[0]) +		n_enabled_triggers * sizeof(DeferredTriggerEventItem);	new_event =

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -