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

📄 dependency.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
/*------------------------------------------------------------------------- * * dependency.c *	  Routines to support inter-object dependencies. * * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.47.2.1 2005/11/22 18:23:06 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/genam.h"#include "access/heapam.h"#include "catalog/dependency.h"#include "catalog/heap.h"#include "catalog/index.h"#include "catalog/indexing.h"#include "catalog/namespace.h"#include "catalog/pg_attrdef.h"#include "catalog/pg_authid.h"#include "catalog/pg_cast.h"#include "catalog/pg_constraint.h"#include "catalog/pg_conversion.h"#include "catalog/pg_database.h"#include "catalog/pg_depend.h"#include "catalog/pg_language.h"#include "catalog/pg_namespace.h"#include "catalog/pg_opclass.h"#include "catalog/pg_operator.h"#include "catalog/pg_proc.h"#include "catalog/pg_rewrite.h"#include "catalog/pg_tablespace.h"#include "catalog/pg_trigger.h"#include "catalog/pg_type.h"#include "commands/comment.h"#include "commands/dbcommands.h"#include "commands/defrem.h"#include "commands/proclang.h"#include "commands/schemacmds.h"#include "commands/tablespace.h"#include "commands/trigger.h"#include "commands/typecmds.h"#include "lib/stringinfo.h"#include "miscadmin.h"#include "optimizer/clauses.h"#include "parser/parsetree.h"#include "rewrite/rewriteRemove.h"#include "utils/builtins.h"#include "utils/fmgroids.h"#include "utils/lsyscache.h"#include "utils/syscache.h"/* expansible list of ObjectAddresses */typedef struct{	ObjectAddress *refs;		/* => palloc'd array */	int			numrefs;		/* current number of references */	int			maxrefs;		/* current size of palloc'd array */} ObjectAddresses;/* for find_expr_references_walker */typedef struct{	ObjectAddresses addrs;		/* addresses being accumulated */	List	   *rtables;		/* list of rangetables to resolve Vars */} find_expr_references_context;/* * This constant table maps ObjectClasses to the corresponding catalog OIDs. * See also getObjectClass(). */static const Oid object_classes[MAX_OCLASS] = {	RelationRelationId,			/* OCLASS_CLASS */	ProcedureRelationId,		/* OCLASS_PROC */	TypeRelationId,				/* OCLASS_TYPE */	CastRelationId,				/* OCLASS_CAST */	ConstraintRelationId,		/* OCLASS_CONSTRAINT */	ConversionRelationId,		/* OCLASS_CONVERSION */	AttrDefaultRelationId,		/* OCLASS_DEFAULT */	LanguageRelationId,			/* OCLASS_LANGUAGE */	OperatorRelationId,			/* OCLASS_OPERATOR */	OperatorClassRelationId,	/* OCLASS_OPCLASS */	RewriteRelationId,			/* OCLASS_REWRITE */	TriggerRelationId,			/* OCLASS_TRIGGER */	NamespaceRelationId			/* OCLASS_SCHEMA */};static void findAutoDeletableObjects(const ObjectAddress *object,						 ObjectAddresses *oktodelete,						 Relation depRel);static bool recursiveDeletion(const ObjectAddress *object,				  DropBehavior behavior,				  int msglevel,				  const ObjectAddress *callingObject,				  ObjectAddresses *oktodelete,				  Relation depRel);static bool deleteDependentObjects(const ObjectAddress *object,					   const char *objDescription,					   DropBehavior behavior,					   int msglevel,					   ObjectAddresses *oktodelete,					   Relation depRel);static void doDeletion(const ObjectAddress *object);static bool find_expr_references_walker(Node *node,							find_expr_references_context *context);static void eliminate_duplicate_dependencies(ObjectAddresses *addrs);static int	object_address_comparator(const void *a, const void *b);static void init_object_addresses(ObjectAddresses *addrs);static void add_object_address(ObjectClass oclass, Oid objectId, int32 subId,				   ObjectAddresses *addrs);static void add_exact_object_address(const ObjectAddress *object,						 ObjectAddresses *addrs);static bool object_address_present(const ObjectAddress *object,					   ObjectAddresses *addrs);static void term_object_addresses(ObjectAddresses *addrs);static void getRelationDescription(StringInfo buffer, Oid relid);/* * performDeletion: attempt to drop the specified object.  If CASCADE * behavior is specified, also drop any dependent objects (recursively). * If RESTRICT behavior is specified, error out if there are any dependent * objects, except for those that should be implicitly dropped anyway * according to the dependency type. * * This is the outer control routine for all forms of DROP that drop objects * that can participate in dependencies. */voidperformDeletion(const ObjectAddress *object,				DropBehavior behavior){	char	   *objDescription;	Relation	depRel;	ObjectAddresses oktodelete;	/*	 * Get object description for possible use in failure message. Must do	 * this before deleting it ...	 */	objDescription = getObjectDescription(object);	/*	 * We save some cycles by opening pg_depend just once and passing the	 * Relation pointer down to all the recursive deletion steps.	 */	depRel = heap_open(DependRelationId, RowExclusiveLock);	/*	 * Construct a list of objects that are reachable by AUTO or INTERNAL	 * dependencies from the target object.  These should be deleted silently,	 * even if the actual deletion pass first reaches one of them via a	 * non-auto dependency.	 */	init_object_addresses(&oktodelete);	findAutoDeletableObjects(object, &oktodelete, depRel);	if (!recursiveDeletion(object, behavior, NOTICE,						   NULL, &oktodelete, depRel))		ereport(ERROR,				(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),				 errmsg("cannot drop %s because other objects depend on it",						objDescription),		errhint("Use DROP ... CASCADE to drop the dependent objects too.")));	term_object_addresses(&oktodelete);	heap_close(depRel, RowExclusiveLock);	pfree(objDescription);}/* * deleteWhatDependsOn: attempt to drop everything that depends on the * specified object, though not the object itself.	Behavior is always * CASCADE. * * This is currently used only to clean out the contents of a schema * (namespace): the passed object is a namespace.  We normally want this * to be done silently, so there's an option to suppress NOTICE messages. */voiddeleteWhatDependsOn(const ObjectAddress *object,					bool showNotices){	char	   *objDescription;	Relation	depRel;	ObjectAddresses oktodelete;	/*	 * Get object description for possible use in failure messages	 */	objDescription = getObjectDescription(object);	/*	 * We save some cycles by opening pg_depend just once and passing the	 * Relation pointer down to all the recursive deletion steps.	 */	depRel = heap_open(DependRelationId, RowExclusiveLock);	/*	 * Construct a list of objects that are reachable by AUTO or INTERNAL	 * dependencies from the target object.  These should be deleted silently,	 * even if the actual deletion pass first reaches one of them via a	 * non-auto dependency.	 */	init_object_addresses(&oktodelete);	findAutoDeletableObjects(object, &oktodelete, depRel);	/*	 * Now invoke only step 2 of recursiveDeletion: just recurse to the stuff	 * dependent on the given object.	 */	if (!deleteDependentObjects(object, objDescription,								DROP_CASCADE,								showNotices ? NOTICE : DEBUG2,								&oktodelete, depRel))		ereport(ERROR,				(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),				 errmsg("failed to drop all objects depending on %s",						objDescription)));	/*	 * We do not need CommandCounterIncrement here, since if step 2 did	 * anything then each recursive call will have ended with one.	 */	term_object_addresses(&oktodelete);	heap_close(depRel, RowExclusiveLock);	pfree(objDescription);}/* * findAutoDeletableObjects: find all objects that are reachable by AUTO or * INTERNAL dependency paths from the given object.  Add them all to the * oktodelete list.  Note that the originally given object will also be * added to the list. * * depRel is the already-open pg_depend relation. */static voidfindAutoDeletableObjects(const ObjectAddress *object,						 ObjectAddresses *oktodelete,						 Relation depRel){	ScanKeyData key[3];	int			nkeys;	SysScanDesc scan;	HeapTuple	tup;	ObjectAddress otherObject;	/*	 * If this object is already in oktodelete, then we already visited it;	 * don't do so again (this prevents infinite recursion if there's a loop	 * in pg_depend).  Otherwise, add it.	 */	if (object_address_present(object, oktodelete))		return;	add_exact_object_address(object, oktodelete);	/*	 * Scan pg_depend records that link to this object, showing the things	 * that depend on it.  For each one that is AUTO or INTERNAL, visit the	 * referencing object.	 *	 * When dropping a whole object (subId = 0), find pg_depend records for	 * its sub-objects too.	 */	ScanKeyInit(&key[0],				Anum_pg_depend_refclassid,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(object->classId));	ScanKeyInit(&key[1],				Anum_pg_depend_refobjid,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(object->objectId));	if (object->objectSubId != 0)	{		ScanKeyInit(&key[2],					Anum_pg_depend_refobjsubid,					BTEqualStrategyNumber, F_INT4EQ,					Int32GetDatum(object->objectSubId));		nkeys = 3;	}	else		nkeys = 2;	scan = systable_beginscan(depRel, DependReferenceIndexId, true,							  SnapshotNow, nkeys, key);	while (HeapTupleIsValid(tup = systable_getnext(scan)))	{		Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);		switch (foundDep->deptype)		{			case DEPENDENCY_NORMAL:				/* ignore */				break;			case DEPENDENCY_AUTO:			case DEPENDENCY_INTERNAL:				/* recurse */				otherObject.classId = foundDep->classid;				otherObject.objectId = foundDep->objid;				otherObject.objectSubId = foundDep->objsubid;				findAutoDeletableObjects(&otherObject, oktodelete, depRel);				break;			case DEPENDENCY_PIN:				/*				 * For a PIN dependency we just ereport immediately; there				 * won't be any others to examine, and we aren't ever going to				 * let the user delete it.				 */				ereport(ERROR,						(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),						 errmsg("cannot drop %s because it is required by the database system",								getObjectDescription(object))));				break;			default:				elog(ERROR, "unrecognized dependency type '%c' for %s",					 foundDep->deptype, getObjectDescription(object));				break;		}	}	systable_endscan(scan);}/* * recursiveDeletion: delete a single object for performDeletion, plus * (recursively) anything that depends on it. * * Returns TRUE if successful, FALSE if not. * * callingObject is NULL at the outer level, else identifies the object that * we recursed from (the reference object that someone else needs to delete). * * oktodelete is a list of objects verified deletable (ie, reachable by one * or more AUTO or INTERNAL dependencies from the original target). * * depRel is the already-open pg_depend relation. * * * In RESTRICT mode, we perform all the deletions anyway, but ereport a message * and return FALSE if we find a restriction violation.  performDeletion * will then abort the transaction to nullify the deletions.  We have to * do it this way to (a) report all the direct and indirect dependencies * while (b) not going into infinite recursion if there's a cycle. * * This is even more complex than one could wish, because it is possible for * the same pair of objects to be related by both NORMAL and AUTO/INTERNAL * dependencies.  Also, we might have a situation where we've been asked to * delete object A, and objects B and C both have AUTO dependencies on A, * but B also has a NORMAL dependency on C.  (Since any of these paths might * be indirect, we can't prevent these scenarios, but must cope instead.) * If we visit C before B then we would mistakenly decide that the B->C link * should prevent the restricted drop from occurring.  To handle this, we make * a pre-scan to find all the objects that are auto-deletable from A.  If we * visit C first, but B is present in the oktodelete list, then we make no * complaint but recurse to delete B anyway.  (Note that in general we must * delete B before deleting C; the drop routine for B may try to access C.) * * Note: in the case where the path to B is traversed first, we will not * see the NORMAL dependency when we reach C, because of the pg_depend * removals done in step 1.  The oktodelete list is necessary just * to make the behavior independent of the order in which pg_depend * entries are visited. */static boolrecursiveDeletion(const ObjectAddress *object,				  DropBehavior behavior,				  int msglevel,				  const ObjectAddress *callingObject,				  ObjectAddresses *oktodelete,				  Relation depRel){	bool		ok = true;	char	   *objDescription;	ScanKeyData key[3];	int			nkeys;	SysScanDesc scan;	HeapTuple	tup;	ObjectAddress otherObject;	ObjectAddress owningObject;	bool		amOwned = false;	/*	 * Get object description for possible use in messages.  Must do this	 * before deleting it ...	 */	objDescription = getObjectDescription(object);	/*	 * Step 1: find and remove pg_depend records that link from this object to	 * others.	We have to do this anyway, and doing it first ensures that we	 * avoid infinite recursion in the case of cycles. Also, some dependency	 * types require extra processing here.	 *	 * When dropping a whole object (subId = 0), remove all pg_depend records	 * for its sub-objects too.	 */	ScanKeyInit(&key[0],				Anum_pg_depend_classid,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(object->classId));	ScanKeyInit(&key[1],				Anum_pg_depend_objid,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(object->objectId));	if (object->objectSubId != 0)	{		ScanKeyInit(&key[2],					Anum_pg_depend_objsubid,					BTEqualStrategyNumber, F_INT4EQ,					Int32GetDatum(object->objectSubId));		nkeys = 3;	}	else		nkeys = 2;	scan = systable_beginscan(depRel, DependDependerIndexId, true,							  SnapshotNow, nkeys, key);	while (HeapTupleIsValid(tup = systable_getnext(scan)))	{		Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);		otherObject.classId = foundDep->refclassid;		otherObject.objectId = foundDep->refobjid;		otherObject.objectSubId = foundDep->refobjsubid;		switch (foundDep->deptype)		{			case DEPENDENCY_NORMAL:			case DEPENDENCY_AUTO:				/* no problem */				break;			case DEPENDENCY_INTERNAL:				/*				 * This object is part of the internal implementation of				 * another object.	We have three cases:				 *				 * 1. At the outermost recursion level, disallow the DROP. (We				 * just ereport here, rather than proceeding, since no other				 * dependencies are likely to be interesting.)				 */				if (callingObject == NULL)				{					char	   *otherObjDesc = getObjectDescription(&otherObject);					ereport(ERROR,							(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),

⌨️ 快捷键说明

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