tablecmds.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,338 行 · 第 1/5 页

C
2,338
字号
		recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL);		/*		 * Mark the parent as having subclasses.		 */		setRelhassubclassInRelation(parentOid, true);		seqNumber += 1;	}	heap_close(relation, RowExclusiveLock);}/* * Look for an existing schema entry with the given name. * * Returns the index (starting with 1) if attribute already exists in schema, * 0 if it doesn't. */static intfindAttrByName(const char *attributeName, List *schema){	List	   *s;	int			i = 0;	foreach(s, schema)	{		ColumnDef  *def = lfirst(s);		++i;		if (strcmp(attributeName, def->colname) == 0)			return i;	}	return 0;}/* * Update a relation's pg_class.relhassubclass entry to the given value */static voidsetRelhassubclassInRelation(Oid relationId, bool relhassubclass){	Relation	relationRelation;	HeapTuple	tuple;	Form_pg_class classtuple;	/*	 * Fetch a modifiable copy of the tuple, modify it, update pg_class.	 *	 * If the tuple already has the right relhassubclass setting, we	 * don't need to update it, but we still need to issue an SI inval	 * message.	 */	relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);	tuple = SearchSysCacheCopy(RELOID,							   ObjectIdGetDatum(relationId),							   0, 0, 0);	if (!HeapTupleIsValid(tuple))		elog(ERROR, "cache lookup failed for relation %u", relationId);	classtuple = (Form_pg_class) GETSTRUCT(tuple);	if (classtuple->relhassubclass != relhassubclass)	{		classtuple->relhassubclass = relhassubclass;		simple_heap_update(relationRelation, &tuple->t_self, tuple);		/* keep the catalog indexes up to date */		CatalogUpdateIndexes(relationRelation, tuple);	}	else	{		/* no need to change tuple, but force relcache rebuild anyway */		CacheInvalidateRelcache(relationId);	}	heap_freetuple(tuple);	heap_close(relationRelation, RowExclusiveLock);}/* *		renameatt		- changes the name of a attribute in a relation * *		Attname attribute is changed in attribute catalog. *		No record of the previous attname is kept (correct?). * *		get proper relrelation from relation catalog (if not arg) *		scan attribute catalog *				for name conflict (within rel) *				for original attribute (if not arg) *		modify attname in attribute tuple *		insert modified attribute in attribute catalog *		delete original attribute from attribute catalog */voidrenameatt(Oid myrelid,		  const char *oldattname,		  const char *newattname,		  bool recurse,		  bool recursing){	Relation	targetrelation;	Relation	attrelation;	HeapTuple	atttup;	Form_pg_attribute attform;	int			attnum;	List	   *indexoidlist;	List	   *indexoidscan;	/*	 * Grab an exclusive lock on the target table, which we will NOT	 * release until end of transaction.	 */	targetrelation = relation_open(myrelid, AccessExclusiveLock);	/*	 * permissions checking.  this would normally be done in utility.c,	 * but this particular routine is recursive.	 *	 * normally, only the owner of a class can change its schema.	 */	if (!pg_class_ownercheck(myrelid, GetUserId()))		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,					   RelationGetRelationName(targetrelation));	if (!allowSystemTableMods && IsSystemRelation(targetrelation))		ereport(ERROR,				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),				 errmsg("permission denied: \"%s\" is a system catalog",						RelationGetRelationName(targetrelation))));	/*	 * if the 'recurse' flag is set then we are supposed to rename this	 * attribute in all classes that inherit from 'relname' (as well as in	 * 'relname').	 *	 * any permissions or problems with duplicate attributes will cause the	 * whole transaction to abort, which is what we want -- all or	 * nothing.	 */	if (recurse)	{		List	   *child,				   *children;		/* this routine is actually in the planner */		children = find_all_inheritors(myrelid);		/*		 * find_all_inheritors does the recursive search of the		 * inheritance hierarchy, so all we have to do is process all of		 * the relids in the list that it returns.		 */		foreach(child, children)		{			Oid			childrelid = lfirsto(child);			if (childrelid == myrelid)				continue;			/* note we need not recurse again! */			renameatt(childrelid, oldattname, newattname, false, true);		}	}	else	{		/*		 * If we are told not to recurse, there had better not be any		 * child tables; else the rename would put them out of step.		 */		if (!recursing &&			find_inheritance_children(myrelid) != NIL)			ereport(ERROR,					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),					 errmsg("inherited column \"%s\" must be renamed in child tables too",							oldattname)));	}	attrelation = heap_openr(AttributeRelationName, RowExclusiveLock);	atttup = SearchSysCacheCopyAttName(myrelid, oldattname);	if (!HeapTupleIsValid(atttup))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_COLUMN),				 errmsg("column \"%s\" does not exist",						oldattname)));	attform = (Form_pg_attribute) GETSTRUCT(atttup);	attnum = attform->attnum;	if (attnum < 0)		ereport(ERROR,				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),				 errmsg("cannot rename system column \"%s\"",						oldattname)));	/*	 * if the attribute is inherited, forbid the renaming, unless we are	 * already inside a recursive rename.	 */	if (attform->attinhcount > 0 && !recursing)		ereport(ERROR,				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),				 errmsg("cannot rename inherited column \"%s\"",						oldattname)));	/* should not already exist */	/* this test is deliberately not attisdropped-aware */	if (SearchSysCacheExists(ATTNAME,							 ObjectIdGetDatum(myrelid),							 PointerGetDatum(newattname),							 0, 0))		ereport(ERROR,				(errcode(ERRCODE_DUPLICATE_COLUMN),			 errmsg("column \"%s\" of relation \"%s\" already exists",				  newattname, RelationGetRelationName(targetrelation))));	namestrcpy(&(attform->attname), newattname);	simple_heap_update(attrelation, &atttup->t_self, atttup);	/* keep system catalog indexes current */	CatalogUpdateIndexes(attrelation, atttup);	heap_freetuple(atttup);	/*	 * Update column names of indexes that refer to the column being	 * renamed.	 */	indexoidlist = RelationGetIndexList(targetrelation);	foreach(indexoidscan, indexoidlist)	{		Oid			indexoid = lfirsto(indexoidscan);		HeapTuple	indextup;		Form_pg_index indexform;		int			i;		/*		 * Scan through index columns to see if there's any simple index		 * entries for this attribute.	We ignore expressional entries.		 */		indextup = SearchSysCache(INDEXRELID,								  ObjectIdGetDatum(indexoid),								  0, 0, 0);		if (!HeapTupleIsValid(indextup))			elog(ERROR, "cache lookup failed for index %u", indexoid);		indexform = (Form_pg_index) GETSTRUCT(indextup);		for (i = 0; i < indexform->indnatts; i++)		{			if (attnum != indexform->indkey[i])				continue;			/*			 * Found one, rename it.			 */			atttup = SearchSysCacheCopy(ATTNUM,										ObjectIdGetDatum(indexoid),										Int16GetDatum(i + 1),										0, 0);			if (!HeapTupleIsValid(atttup))				continue;		/* should we raise an error? */			/*			 * Update the (copied) attribute tuple.			 */			namestrcpy(&(((Form_pg_attribute) GETSTRUCT(atttup))->attname),					   newattname);			simple_heap_update(attrelation, &atttup->t_self, atttup);			/* keep system catalog indexes current */			CatalogUpdateIndexes(attrelation, atttup);			heap_freetuple(atttup);		}		ReleaseSysCache(indextup);	}	freeList(indexoidlist);	heap_close(attrelation, RowExclusiveLock);	/*	 * Update att name in any RI triggers associated with the relation.	 */	if (targetrelation->rd_rel->reltriggers > 0)	{		/* update tgargs column reference where att is primary key */		update_ri_trigger_args(RelationGetRelid(targetrelation),							   oldattname, newattname,							   false, false);		/* update tgargs column reference where att is foreign key */		update_ri_trigger_args(RelationGetRelid(targetrelation),							   oldattname, newattname,							   true, false);	}	relation_close(targetrelation, NoLock);		/* close rel but keep												 * lock! */}/* *		renamerel		- change the name of a relation * *		XXX - When renaming sequences, we don't bother to modify the *			  sequence name that is stored within the sequence itself *			  (this would cause problems with MVCC). In the future, *			  the sequence name should probably be removed from the *			  sequence, AFAIK there's no need for it to be there. */voidrenamerel(Oid myrelid, const char *newrelname){	Relation	targetrelation;	Relation	relrelation;	/* for RELATION relation */	HeapTuple	reltup;	Oid			namespaceId;	char	   *oldrelname;	char		relkind;	bool		relhastriggers;	/*	 * Grab an exclusive lock on the target table or index, which we will	 * NOT release until end of transaction.	 */	targetrelation = relation_open(myrelid, AccessExclusiveLock);	oldrelname = pstrdup(RelationGetRelationName(targetrelation));	namespaceId = RelationGetNamespace(targetrelation);	if (!allowSystemTableMods && IsSystemRelation(targetrelation))		ereport(ERROR,				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),				 errmsg("permission denied: \"%s\" is a system catalog",						RelationGetRelationName(targetrelation))));	relkind = targetrelation->rd_rel->relkind;	relhastriggers = (targetrelation->rd_rel->reltriggers > 0);	/*	 * Find relation's pg_class tuple, and make sure newrelname isn't in	 * use.	 */	relrelation = heap_openr(RelationRelationName, RowExclusiveLock);	reltup = SearchSysCacheCopy(RELOID,								PointerGetDatum(myrelid),								0, 0, 0);	if (!HeapTupleIsValid(reltup))		/* shouldn't happen */		elog(ERROR, "cache lookup failed for relation %u", myrelid);	if (get_relname_relid(newrelname, namespaceId) != InvalidOid)		ereport(ERROR,				(errcode(ERRCODE_DUPLICATE_TABLE),				 errmsg("relation \"%s\" already exists",						newrelname)));	/*	 * Update pg_class tuple with new relname.	(Scribbling on reltup is	 * OK because it's a copy...)	 */	namestrcpy(&(((Form_pg_class) GETSTRUCT(reltup))->relname), newrelname);	simple_heap_update(relrelation, &reltup->t_self, reltup);	/* keep the system catalog indexes current */	CatalogUpdateIndexes(relrelation, reltup);	heap_freetuple(reltup);	heap_close(relrelation, RowExclusiveLock);	/*	 * Also rename the associated type, if any.	 */	if (relkind != RELKIND_INDEX)		TypeRename(oldrelname, namespaceId, newrelname);	/*	 * Update rel name in any RI triggers associated with the relation.	 */	if (relhastriggers)	{		/* update tgargs where relname is primary key */		update_ri_trigger_args(myrelid,							   oldrelname,							   newrelname,							   false, true);		/* update tgargs where relname is foreign key */		update_ri_trigger_args(myrelid,							   oldrelname,							   newrelname,							   true, true);	}	/*	 * Close rel, but keep exclusive lock!	 */	relation_close(targetrelation, NoLock);}/* * Given a trigger function OID, determine whether it is an RI trigger, * and if so whether it is attached to PK or FK relation. * * XXX this probably doesn't belong here; should be exported by * ri_triggers.c */static intri_trigger_type(Oid tgfoid){	switch (tgfoid)	{		case F_RI_FKEY_CASCADE_DEL:		case F_RI_FKEY_CASCADE_UPD:		case F_RI_FKEY_RESTRICT_DEL:		case F_RI_FKEY_RESTRICT_UPD:		case F_RI_FKEY_SETNULL_DEL:		case F_RI_FKEY_SETNULL_UPD:		case F_RI_FKEY_SETDEFAULT_DEL:		case F_RI_FKEY_SETDEFAULT_UPD:		case F_RI_FKEY_NOACTION_DEL:		case F_RI_FKEY_NOACTION_UPD:			return RI_TRIGGER_PK;		case F_RI_FKEY_CHECK_INS:		case F_RI_FKEY_CHECK_UPD:			return RI_TRIGGER_FK;	}	return RI_TRIGGER_NONE;}/* * Scan pg_trigger for RI triggers that are on the specified relation * (if fk_scan is false) or have it as the tgconstrrel (if fk_scan * is true).  Update RI trigger args fields matching oldname to contain * newname instead.  If update_relname is true, examine the relname * fields; otherwise examine the attname fields. */static voidupdate_ri_trigger_args(Oid relid,					   const char *oldname,					   const char *newname,					   bool fk_scan,					   bool update_relname){	Relation	tgrel;	ScanKeyData skey[1];	SysScanDesc trigscan;	HeapTuple	tuple;	Datum		values[Natts_pg_trigger];	char		nulls[Natts_pg_trigger];	char		replaces[Natts_pg_trigger];	tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);	if (fk_scan)	{		ScanKeyEntryInitialize(&skey[0], 0x0,							   Anum_pg_trigger_tgconstrrelid,							   F_OIDEQ,							   ObjectIdGetDatum(relid));		trigscan = systable_beginscan(tgrel, TriggerConstrRelidIndex,									  true, SnapshotNow,									  1, skey);	}	else

⌨️ 快捷键说明

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