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

📄 trigger.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 5 页
字号:
					   get_rel_name(relid));	object.classId = RelationGetRelid(tgrel);	object.objectId = HeapTupleGetOid(tup);	object.objectSubId = 0;	systable_endscan(tgscan);	heap_close(tgrel, AccessShareLock);	/*	 * Do the deletion	 */	performDeletion(&object, behavior);}/* * Guts of trigger deletion. */voidRemoveTriggerById(Oid trigOid){	Relation	tgrel;	SysScanDesc tgscan;	ScanKeyData skey[1];	HeapTuple	tup;	Oid			relid;	Relation	rel;	Relation	pgrel;	HeapTuple	tuple;	Form_pg_class classForm;	tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);	/*	 * Find the trigger to delete.	 */	ScanKeyEntryInitialize(&skey[0], 0x0,						   ObjectIdAttributeNumber, F_OIDEQ,						   ObjectIdGetDatum(trigOid));	tgscan = systable_beginscan(tgrel, TriggerOidIndex, true,								SnapshotNow, 1, skey);	tup = systable_getnext(tgscan);	if (!HeapTupleIsValid(tup))		elog(ERROR, "could not find tuple for trigger %u", trigOid);	/*	 * Open and exclusive-lock the relation the trigger belongs to.	 */	relid = ((Form_pg_trigger) GETSTRUCT(tup))->tgrelid;	rel = heap_open(relid, AccessExclusiveLock);	if (rel->rd_rel->relkind != RELKIND_RELATION)		ereport(ERROR,				(errcode(ERRCODE_WRONG_OBJECT_TYPE),				 errmsg("\"%s\" is not a table",						RelationGetRelationName(rel))));	if (!allowSystemTableMods && IsSystemRelation(rel))		ereport(ERROR,				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),				 errmsg("permission denied: \"%s\" is a system catalog",						RelationGetRelationName(rel))));	/*	 * Delete the pg_trigger tuple.	 */	simple_heap_delete(tgrel, &tup->t_self);	systable_endscan(tgscan);	heap_close(tgrel, RowExclusiveLock);	/*	 * Update relation's pg_class entry.  Crucial side-effect: other	 * backends (and this one too!) are sent SI message to make them	 * rebuild relcache entries.	 *	 * Note this is OK only because we have AccessExclusiveLock on the rel,	 * so no one else is creating/deleting triggers on this rel at the	 * same time.	 */	pgrel = heap_openr(RelationRelationName, RowExclusiveLock);	tuple = SearchSysCacheCopy(RELOID,							   ObjectIdGetDatum(relid),							   0, 0, 0);	if (!HeapTupleIsValid(tuple))		elog(ERROR, "cache lookup failed for relation %u", relid);	classForm = (Form_pg_class) GETSTRUCT(tuple);	if (classForm->reltriggers == 0)	/* should not happen */		elog(ERROR, "relation \"%s\" has reltriggers = 0",			 RelationGetRelationName(rel));	classForm->reltriggers--;	simple_heap_update(pgrel, &tuple->t_self, tuple);	CatalogUpdateIndexes(pgrel, tuple);	heap_freetuple(tuple);	heap_close(pgrel, RowExclusiveLock);	/* Keep lock on trigger's rel until end of xact */	heap_close(rel, NoLock);}/* *		renametrig		- changes the name of a trigger on a relation * *		trigger name is changed in trigger catalog. *		No record of the previous name is kept. * *		get proper relrelation from relation catalog (if not arg) *		scan trigger catalog *				for name conflict (within rel) *				for original trigger (if not arg) *		modify tgname in trigger tuple *		update row in catalog */voidrenametrig(Oid relid,		   const char *oldname,		   const char *newname){	Relation	targetrel;	Relation	tgrel;	HeapTuple	tuple;	SysScanDesc tgscan;	ScanKeyData key[2];	/*	 * Grab an exclusive lock on the target table, which we will NOT	 * release until end of transaction.	 */	targetrel = heap_open(relid, AccessExclusiveLock);	/*	 * Scan pg_trigger twice for existing triggers on relation.  We do	 * this in order to ensure a trigger does not exist with newname (The	 * unique index on tgrelid/tgname would complain anyway) and to ensure	 * a trigger does exist with oldname.	 *	 * NOTE that this is cool only because we have AccessExclusiveLock on the	 * relation, so the trigger set won't be changing underneath us.	 */	tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);	/*	 * First pass -- look for name conflict	 */	ScanKeyEntryInitialize(&key[0], 0,						   Anum_pg_trigger_tgrelid,						   F_OIDEQ,						   ObjectIdGetDatum(relid));	ScanKeyEntryInitialize(&key[1], 0,						   Anum_pg_trigger_tgname,						   F_NAMEEQ,						   PointerGetDatum(newname));	tgscan = systable_beginscan(tgrel, TriggerRelidNameIndex, true,								SnapshotNow, 2, key);	if (HeapTupleIsValid(tuple = systable_getnext(tgscan)))		ereport(ERROR,				(errcode(ERRCODE_DUPLICATE_OBJECT),			  errmsg("trigger \"%s\" for relation \"%s\" already exists",					 newname, RelationGetRelationName(targetrel))));	systable_endscan(tgscan);	/*	 * Second pass -- look for trigger existing with oldname and update	 */	ScanKeyEntryInitialize(&key[0], 0,						   Anum_pg_trigger_tgrelid,						   F_OIDEQ,						   ObjectIdGetDatum(relid));	ScanKeyEntryInitialize(&key[1], 0,						   Anum_pg_trigger_tgname,						   F_NAMEEQ,						   PointerGetDatum(oldname));	tgscan = systable_beginscan(tgrel, TriggerRelidNameIndex, true,								SnapshotNow, 2, key);	if (HeapTupleIsValid(tuple = systable_getnext(tgscan)))	{		/*		 * Update pg_trigger tuple with new tgname.		 */		tuple = heap_copytuple(tuple);	/* need a modifiable copy */		namestrcpy(&((Form_pg_trigger) GETSTRUCT(tuple))->tgname, newname);		simple_heap_update(tgrel, &tuple->t_self, tuple);		/* keep system catalog indexes current */		CatalogUpdateIndexes(tgrel, tuple);		/*		 * Invalidate relation's relcache entry so that other backends		 * (and this one too!) are sent SI message to make them rebuild		 * relcache entries.  (Ideally this should happen		 * automatically...)		 */		CacheInvalidateRelcache(relid);	}	else	{		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_OBJECT),			  errmsg("trigger \"%s\" for table \"%s\" does not exist",					 oldname, RelationGetRelationName(targetrel))));	}	systable_endscan(tgscan);	heap_close(tgrel, RowExclusiveLock);	/*	 * Close rel, but keep exclusive lock!	 */	heap_close(targetrel, NoLock);}/* * Build trigger data to attach to the given relcache entry. * * Note that trigger data attached to a relcache entry must be stored in * CacheMemoryContext to ensure it survives as long as the relcache entry. * But we should be running in a less long-lived working context.  To avoid * leaking cache memory if this routine fails partway through, we build a * temporary TriggerDesc in working memory and then copy the completed * structure into cache memory. */voidRelationBuildTriggers(Relation relation){	TriggerDesc *trigdesc;	int			ntrigs = relation->rd_rel->reltriggers;	Trigger    *triggers;	int			found = 0;	Relation	tgrel;	ScanKeyData skey;	SysScanDesc tgscan;	HeapTuple	htup;	MemoryContext oldContext;	Assert(ntrigs > 0);			/* else I should not have been called */	triggers = (Trigger *) palloc(ntrigs * sizeof(Trigger));	/*	 * Note: since we scan the triggers using TriggerRelidNameIndex, we	 * will be reading the triggers in name order, except possibly during	 * emergency-recovery operations (ie, IsIgnoringSystemIndexes). This	 * in turn ensures that triggers will be fired in name order.	 */	ScanKeyEntryInitialize(&skey,						   (bits16) 0x0,						   (AttrNumber) Anum_pg_trigger_tgrelid,						   (RegProcedure) F_OIDEQ,						   ObjectIdGetDatum(RelationGetRelid(relation)));	tgrel = heap_openr(TriggerRelationName, AccessShareLock);	tgscan = systable_beginscan(tgrel, TriggerRelidNameIndex, true,								SnapshotNow, 1, &skey);	while (HeapTupleIsValid(htup = systable_getnext(tgscan)))	{		Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);		Trigger    *build;		if (found >= ntrigs)			elog(ERROR, "too many trigger records found for relation \"%s\"",				 RelationGetRelationName(relation));		build = &(triggers[found]);		build->tgoid = HeapTupleGetOid(htup);		build->tgname = DatumGetCString(DirectFunctionCall1(nameout,									 NameGetDatum(&pg_trigger->tgname)));		build->tgfoid = pg_trigger->tgfoid;		build->tgtype = pg_trigger->tgtype;		build->tgenabled = pg_trigger->tgenabled;		build->tgisconstraint = pg_trigger->tgisconstraint;		build->tgconstrrelid = pg_trigger->tgconstrrelid;		build->tgdeferrable = pg_trigger->tgdeferrable;		build->tginitdeferred = pg_trigger->tginitdeferred;		build->tgnargs = pg_trigger->tgnargs;		memcpy(build->tgattr, &(pg_trigger->tgattr),			   FUNC_MAX_ARGS * sizeof(int16));		if (build->tgnargs > 0)		{			bytea	   *val;			bool		isnull;			char	   *p;			int			i;			val = (bytea *) fastgetattr(htup,										Anum_pg_trigger_tgargs,										tgrel->rd_att, &isnull);			if (isnull)				elog(ERROR, "tgargs is null in trigger for relation \"%s\"",					 RelationGetRelationName(relation));			p = (char *) VARDATA(val);			build->tgargs = (char **) palloc(build->tgnargs * sizeof(char *));			for (i = 0; i < build->tgnargs; i++)			{				build->tgargs[i] = pstrdup(p);				p += strlen(p) + 1;			}		}		else			build->tgargs = NULL;		found++;	}	systable_endscan(tgscan);	heap_close(tgrel, AccessShareLock);	if (found != ntrigs)		elog(ERROR, "%d trigger record(s) not found for relation \"%s\"",			 ntrigs - found,			 RelationGetRelationName(relation));	/* Build trigdesc */	trigdesc = (TriggerDesc *) palloc0(sizeof(TriggerDesc));	trigdesc->triggers = triggers;	trigdesc->numtriggers = ntrigs;	for (found = 0; found < ntrigs; found++)		InsertTrigger(trigdesc, &(triggers[found]), found);	/* Copy completed trigdesc into cache storage */	oldContext = MemoryContextSwitchTo(CacheMemoryContext);	relation->trigdesc = CopyTriggerDesc(trigdesc);	MemoryContextSwitchTo(oldContext);	/* Release working memory */	FreeTriggerDesc(trigdesc);}/* * Insert the given trigger into the appropriate index list(s) for it * * To simplify storage management, we allocate each index list at the max * possible size (trigdesc->numtriggers) if it's used at all.  This does * not waste space permanently since we're only building a temporary * trigdesc at this point. */static voidInsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx){	uint16	   *n;	int		  **t,			  **tp;	if (TRIGGER_FOR_ROW(trigger->tgtype))	{		/* ROW trigger */		if (TRIGGER_FOR_BEFORE(trigger->tgtype))		{			n = trigdesc->n_before_row;			t = trigdesc->tg_before_row;		}		else		{			n = trigdesc->n_after_row;			t = trigdesc->tg_after_row;		}	}	else	{		/* STATEMENT trigger */		if (TRIGGER_FOR_BEFORE(trigger->tgtype))		{			n = trigdesc->n_before_statement;			t = trigdesc->tg_before_statement;		}		else		{			n = trigdesc->n_after_statement;			t = trigdesc->tg_after_statement;		}	}	if (TRIGGER_FOR_INSERT(trigger->tgtype))	{		tp = &(t[TRIGGER_EVENT_INSERT]);		if (*tp == NULL)			*tp = (int *) palloc(trigdesc->numtriggers * sizeof(int));		(*tp)[n[TRIGGER_EVENT_INSERT]] = indx;		(n[TRIGGER_EVENT_INSERT])++;	}	if (TRIGGER_FOR_DELETE(trigger->tgtype))	{		tp = &(t[TRIGGER_EVENT_DELETE]);		if (*tp == NULL)			*tp = (int *) palloc(trigdesc->numtriggers * sizeof(int));		(*tp)[n[TRIGGER_EVENT_DELETE]] = indx;		(n[TRIGGER_EVENT_DELETE])++;	}	if (TRIGGER_FOR_UPDATE(trigger->tgtype))	{		tp = &(t[TRIGGER_EVENT_UPDATE]);		if (*tp == NULL)			*tp = (int *) palloc(trigdesc->numtriggers * sizeof(int));		(*tp)[n[TRIGGER_EVENT_UPDATE]] = indx;		(n[TRIGGER_EVENT_UPDATE])++;	}}/* * Copy a TriggerDesc data structure. * * The copy is allocated in the current memory context. */TriggerDesc *CopyTriggerDesc(TriggerDesc *trigdesc){	TriggerDesc *newdesc;	uint16	   *n;	int		  **t,			   *tnew;	Trigger    *trigger;	int			i;	if (trigdesc == NULL || trigdesc->numtriggers <= 0)		return NULL;	newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));	memcpy(newdesc, trigdesc, sizeof(TriggerDesc));	trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));	memcpy(trigger, trigdesc->triggers,		   trigdesc->numtriggers * sizeof(Trigger));	newdesc->triggers = trigger;	for (i = 0; i < trigdesc->numtriggers; i++)	{		trigger->tgname = pstrdup(trigger->tgname);		if (trigger->tgnargs > 0)		{			char	  **newargs;			int16		j;			newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));			for (j = 0; j < trigger->tgnargs; j++)				newargs[j] = pstrdup(trigger->tgargs[j]);			trigger->tgargs = newargs;		}		trigger++;	}	n = newdesc->n_before_statement;	t = newdesc->tg_before_statement;	for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)	{		if (n[i] > 0)		{			tnew = (int *) palloc(n[i] * sizeof(int));			memcpy(tnew, t[i], n[i] * sizeof(int));			t[i] = tnew;		}		else			t[i] = NULL;	}	n = newdesc->n_before_row;	t = newdesc->tg_before_row;	for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)	{		if (n[i] > 0)		{			tnew = (int *) palloc(n[i] * sizeof(int));			memcpy(tnew, t[i], n[i] * sizeof(int));			t[i] = tnew;		}		else			t[i] = NULL;	}	n = newdesc->n_after_row;	t = newdesc->tg_after_row;	for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)	{		if (n[i] > 0)		{			tnew = (int *) palloc(n[i] * sizeof(int));			memcpy(tnew, t[i], n[i] * sizeof(int));			t[i] = tnew;

⌨️ 快捷键说明

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