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

📄 trigger.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
				CStringGetDatum(trigname));	tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,								SnapshotNow, 2, skey);	tup = systable_getnext(tgscan);	if (!HeapTupleIsValid(tup))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("trigger \"%s\" for table \"%s\" does not exist",						trigname, get_rel_name(relid))));	if (!pg_class_ownercheck(relid, GetUserId()))		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,					   get_rel_name(relid));	object.classId = TriggerRelationId;	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_open(TriggerRelationId, RowExclusiveLock);	/*	 * Find the trigger to delete.	 */	ScanKeyInit(&skey[0],				ObjectIdAttributeNumber,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(trigOid));	tgscan = systable_beginscan(tgrel, TriggerOidIndexId, 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_open(RelationRelationId, 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_open(TriggerRelationId, RowExclusiveLock);	/*	 * First pass -- look for name conflict	 */	ScanKeyInit(&key[0],				Anum_pg_trigger_tgrelid,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(relid));	ScanKeyInit(&key[1],				Anum_pg_trigger_tgname,				BTEqualStrategyNumber, F_NAMEEQ,				PointerGetDatum(newname));	tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, 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	 */	ScanKeyInit(&key[0],				Anum_pg_trigger_tgrelid,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(relid));	ScanKeyInit(&key[1],				Anum_pg_trigger_tgname,				BTEqualStrategyNumber, F_NAMEEQ,				PointerGetDatum(oldname));	tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, 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(targetrel);	}	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);}/* * EnableDisableTrigger() * *	Called by ALTER TABLE ENABLE/DISABLE TRIGGER *	to change 'tgenabled' flag for the specified trigger(s) * * rel: relation to process (caller must hold suitable lock on it) * tgname: trigger to process, or NULL to scan all triggers * enable: new value for tgenabled flag * skip_system: if true, skip "system" triggers (constraint triggers) * * Caller should have checked permissions for the table; here we also * enforce that superuser privilege is required to alter the state of * system triggers */voidEnableDisableTrigger(Relation rel, const char *tgname,					 bool enable, bool skip_system){	Relation	tgrel;	int			nkeys;	ScanKeyData keys[2];	SysScanDesc tgscan;	HeapTuple	tuple;	bool		found;	bool		changed;	/* Scan the relevant entries in pg_triggers */	tgrel = heap_open(TriggerRelationId, RowExclusiveLock);	ScanKeyInit(&keys[0],				Anum_pg_trigger_tgrelid,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(RelationGetRelid(rel)));	if (tgname)	{		ScanKeyInit(&keys[1],					Anum_pg_trigger_tgname,					BTEqualStrategyNumber, F_NAMEEQ,					CStringGetDatum(tgname));		nkeys = 2;	}	else		nkeys = 1;	tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,								SnapshotNow, nkeys, keys);	found = changed = false;	while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))	{		Form_pg_trigger oldtrig = (Form_pg_trigger) GETSTRUCT(tuple);		if (oldtrig->tgisconstraint)		{			/* system trigger ... ok to process? */			if (skip_system)				continue;			if (!superuser())				ereport(ERROR,						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),					  errmsg("permission denied: \"%s\" is a system trigger",							 NameStr(oldtrig->tgname))));		}		found = true;		if (oldtrig->tgenabled != enable)		{			/* need to change this one ... make a copy to scribble on */			HeapTuple	newtup = heap_copytuple(tuple);			Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup);			newtrig->tgenabled = enable;			simple_heap_update(tgrel, &newtup->t_self, newtup);			/* Keep catalog indexes current */			CatalogUpdateIndexes(tgrel, newtup);			heap_freetuple(newtup);			changed = true;		}	}	systable_endscan(tgscan);	heap_close(tgrel, RowExclusiveLock);	if (tgname && !found)		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("trigger \"%s\" for table \"%s\" does not exist",						tgname, RelationGetRelationName(rel))));	/*	 * If we changed anything, broadcast a SI inval message to force each	 * backend (including our own!) to rebuild relation's relcache entry.	 * Otherwise they will fail to apply the change promptly.	 */	if (changed)		CacheInvalidateRelcache(rel);}/* * 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 TriggerRelidNameIndexId, 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.	 */	ScanKeyInit(&skey,				Anum_pg_trigger_tgrelid,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(RelationGetRelid(relation)));	tgrel = heap_open(TriggerRelationId, AccessShareLock);	tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, 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;		/* tgattr is first var-width field, so OK to access directly */		build->tgnattr = pg_trigger->tgattr.dim1;		if (build->tgnattr > 0)		{			build->tgattr = (int2 *) palloc(build->tgnattr * sizeof(int2));			memcpy(build->tgattr, &(pg_trigger->tgattr.values),				   build->tgnattr * sizeof(int2));		}		else			build->tgattr = NULL;		if (build->tgnargs > 0)		{			bytea	   *val;			bool		isnull;			char	   *p;			int			i;			val = (bytea *)				DatumGetPointer(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

⌨️ 快捷键说明

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