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

📄 namespace.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 4 页
字号:
/*------------------------------------------------------------------------- * * namespace.c *	  code to support accessing and searching namespaces * * This is separate from pg_namespace.c, which contains the routines that * directly manipulate the pg_namespace system catalog.  This module * provides routines associated with defining a "namespace search path" * and implementing search-path-controlled searches. * * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION *	  $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.58 2003/09/25 06:57:57 petere Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/xact.h"#include "catalog/catname.h"#include "catalog/dependency.h"#include "catalog/namespace.h"#include "catalog/pg_conversion.h"#include "catalog/pg_namespace.h"#include "catalog/pg_opclass.h"#include "catalog/pg_operator.h"#include "catalog/pg_proc.h"#include "catalog/pg_shadow.h"#include "catalog/pg_type.h"#include "commands/dbcommands.h"#include "lib/stringinfo.h"#include "miscadmin.h"#include "nodes/makefuncs.h"#include "storage/backendid.h"#include "storage/ipc.h"#include "utils/acl.h"#include "utils/builtins.h"#include "utils/catcache.h"#include "utils/inval.h"#include "utils/lsyscache.h"#include "utils/memutils.h"#include "utils/syscache.h"/* * The namespace search path is a possibly-empty list of namespace OIDs. * In addition to the explicit list, several implicitly-searched namespaces * may be included: * * 1. If a "special" namespace has been set by PushSpecialNamespace, it is * always searched first.  (This is a hack for CREATE SCHEMA.) * * 2. If a TEMP table namespace has been initialized in this session, it * is always searched just after any special namespace. * * 3. The system catalog namespace is always searched.	If the system * namespace is present in the explicit path then it will be searched in * the specified order; otherwise it will be searched after TEMP tables and * *before* the explicit list.	(It might seem that the system namespace * should be implicitly last, but this behavior appears to be required by * SQL99.  Also, this provides a way to search the system namespace first * without thereby making it the default creation target namespace.) * * The default creation target namespace is normally equal to the first * element of the explicit list, but is the "special" namespace when one * has been set.  If the explicit list is empty and there is no special * namespace, there is no default target. * * In bootstrap mode, the search path is set equal to 'pg_catalog', so that * the system namespace is the only one searched or inserted into. * The initdb script is also careful to set search_path to 'pg_catalog' for * its post-bootstrap standalone backend runs.	Otherwise the default search * path is determined by GUC.  The factory default path contains the PUBLIC * namespace (if it exists), preceded by the user's personal namespace * (if one exists). * * If namespaceSearchPathValid is false, then namespaceSearchPath (and other * derived variables) need to be recomputed from namespace_search_path. * We mark it invalid upon an assignment to namespace_search_path or receipt * of a syscache invalidation event for pg_namespace.  The recomputation * is done during the next lookup attempt. * * Any namespaces mentioned in namespace_search_path that are not readable * by the current user ID are simply left out of namespaceSearchPath; so * we have to be willing to recompute the path when current userid changes. * namespaceUser is the userid the path has been computed for. */static List *namespaceSearchPath = NIL;static Oid	namespaceUser = InvalidOid;/* default place to create stuff; if InvalidOid, no default */static Oid	defaultCreationNamespace = InvalidOid;/* first explicit member of list; usually same as defaultCreationNamespace */static Oid	firstExplicitNamespace = InvalidOid;/* The above four values are valid only if namespaceSearchPathValid */static bool namespaceSearchPathValid = true;/* * myTempNamespace is InvalidOid until and unless a TEMP namespace is set up * in a particular backend session (this happens when a CREATE TEMP TABLE * command is first executed).	Thereafter it's the OID of the temp namespace. * firstTempTransaction flags whether we've committed creation of the TEMP * namespace or not. */static Oid	myTempNamespace = InvalidOid;static bool firstTempTransaction = false;/* * "Special" namespace for CREATE SCHEMA.  If set, it's the first search * path element, and also the default creation namespace. */static Oid	mySpecialNamespace = InvalidOid;/* * This is the text equivalent of the search path --- it's the value * of the GUC variable 'search_path'. */char	   *namespace_search_path = NULL;/* Local functions */static void recomputeNamespacePath(void);static void InitTempTableNamespace(void);static void RemoveTempRelations(Oid tempNamespaceId);static void RemoveTempRelationsCallback(void);static void NamespaceCallback(Datum arg, Oid relid);/* These don't really need to appear in any header file */Datum		pg_table_is_visible(PG_FUNCTION_ARGS);Datum		pg_type_is_visible(PG_FUNCTION_ARGS);Datum		pg_function_is_visible(PG_FUNCTION_ARGS);Datum		pg_operator_is_visible(PG_FUNCTION_ARGS);Datum		pg_opclass_is_visible(PG_FUNCTION_ARGS);Datum		pg_conversion_is_visible(PG_FUNCTION_ARGS);/* * RangeVarGetRelid *		Given a RangeVar describing an existing relation, *		select the proper namespace and look up the relation OID. * * If the relation is not found, return InvalidOid if failOK = true, * otherwise raise an error. */OidRangeVarGetRelid(const RangeVar *relation, bool failOK){	Oid			namespaceId;	Oid			relId;	/*	 * We check the catalog name and then ignore it.	 */	if (relation->catalogname)	{		if (strcmp(relation->catalogname, get_database_name(MyDatabaseId)) != 0)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),			   errmsg("cross-database references are not implemented")));	}	if (relation->schemaname)	{		/* use exact schema given */		namespaceId = LookupExplicitNamespace(relation->schemaname);		relId = get_relname_relid(relation->relname, namespaceId);	}	else	{		/* search the namespace path */		relId = RelnameGetRelid(relation->relname);	}	if (!OidIsValid(relId) && !failOK)	{		if (relation->schemaname)			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_TABLE),					 errmsg("relation \"%s.%s\" does not exist",							relation->schemaname, relation->relname)));		else			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_TABLE),					 errmsg("relation \"%s\" does not exist",							relation->relname)));	}	return relId;}/* * RangeVarGetCreationNamespace *		Given a RangeVar describing a to-be-created relation, *		choose which namespace to create it in. * * Note: calling this may result in a CommandCounterIncrement operation. * That will happen on the first request for a temp table in any particular * backend run; we will need to either create or clean out the temp schema. */OidRangeVarGetCreationNamespace(const RangeVar *newRelation){	Oid			namespaceId;	/*	 * We check the catalog name and then ignore it.	 */	if (newRelation->catalogname)	{		if (strcmp(newRelation->catalogname, get_database_name(MyDatabaseId)) != 0)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),			   errmsg("cross-database references are not implemented")));	}	if (newRelation->istemp)	{		/* TEMP tables are created in our backend-local temp namespace */		if (newRelation->schemaname)			ereport(ERROR,					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),				   errmsg("temporary tables may not specify a schema name")));		/* Initialize temp namespace if first time through */		if (!OidIsValid(myTempNamespace))			InitTempTableNamespace();		return myTempNamespace;	}	if (newRelation->schemaname)	{		/* use exact schema given */		namespaceId = GetSysCacheOid(NAMESPACENAME,								CStringGetDatum(newRelation->schemaname),									 0, 0, 0);		if (!OidIsValid(namespaceId))			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_SCHEMA),					 errmsg("schema \"%s\" does not exist",							newRelation->schemaname)));		/* we do not check for USAGE rights here! */	}	else	{		/* use the default creation namespace */		recomputeNamespacePath();		namespaceId = defaultCreationNamespace;		if (!OidIsValid(namespaceId))			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_SCHEMA),					 errmsg("no schema has been selected to create in")));	}	/* Note: callers will check for CREATE rights when appropriate */	return namespaceId;}/* * RelnameGetRelid *		Try to resolve an unqualified relation name. *		Returns OID if relation found in search path, else InvalidOid. */OidRelnameGetRelid(const char *relname){	Oid			relid;	List	   *lptr;	recomputeNamespacePath();	foreach(lptr, namespaceSearchPath)	{		Oid			namespaceId = lfirsto(lptr);		relid = get_relname_relid(relname, namespaceId);		if (OidIsValid(relid))			return relid;	}	/* Not found in path */	return InvalidOid;}/* * RelationIsVisible *		Determine whether a relation (identified by OID) is visible in the *		current search path.  Visible means "would be found by searching *		for the unqualified relation name". */boolRelationIsVisible(Oid relid){	HeapTuple	reltup;	Form_pg_class relform;	Oid			relnamespace;	bool		visible;	reltup = SearchSysCache(RELOID,							ObjectIdGetDatum(relid),							0, 0, 0);	if (!HeapTupleIsValid(reltup))		elog(ERROR, "cache lookup failed for relation %u", relid);	relform = (Form_pg_class) GETSTRUCT(reltup);	recomputeNamespacePath();	/*	 * Quick check: if it ain't in the path at all, it ain't visible.	 * Items in the system namespace are surely in the path and so we	 * needn't even do oidMember() for them.	 */	relnamespace = relform->relnamespace;	if (relnamespace != PG_CATALOG_NAMESPACE &&		!oidMember(relnamespace, namespaceSearchPath))		visible = false;	else	{		/*		 * If it is in the path, it might still not be visible; it could		 * be hidden by another relation of the same name earlier in the		 * path. So we must do a slow check to see if this rel would be		 * found by RelnameGetRelid.		 */		char	   *relname = NameStr(relform->relname);		visible = (RelnameGetRelid(relname) == relid);	}	ReleaseSysCache(reltup);	return visible;}/* * TypenameGetTypid *		Try to resolve an unqualified datatype name. *		Returns OID if type found in search path, else InvalidOid. * * This is essentially the same as RelnameGetRelid. */OidTypenameGetTypid(const char *typname){	Oid			typid;	List	   *lptr;	recomputeNamespacePath();	foreach(lptr, namespaceSearchPath)	{		Oid			namespaceId = lfirsto(lptr);		typid = GetSysCacheOid(TYPENAMENSP,							   PointerGetDatum(typname),							   ObjectIdGetDatum(namespaceId),							   0, 0);		if (OidIsValid(typid))			return typid;	}	/* Not found in path */	return InvalidOid;}/* * TypeIsVisible *		Determine whether a type (identified by OID) is visible in the *		current search path.  Visible means "would be found by searching *		for the unqualified type name". */boolTypeIsVisible(Oid typid){	HeapTuple	typtup;	Form_pg_type typform;	Oid			typnamespace;	bool		visible;	typtup = SearchSysCache(TYPEOID,							ObjectIdGetDatum(typid),							0, 0, 0);	if (!HeapTupleIsValid(typtup))		elog(ERROR, "cache lookup failed for type %u", typid);	typform = (Form_pg_type) GETSTRUCT(typtup);	recomputeNamespacePath();	/*	 * Quick check: if it ain't in the path at all, it ain't visible.	 * Items in the system namespace are surely in the path and so we	 * needn't even do oidMember() for them.	 */	typnamespace = typform->typnamespace;	if (typnamespace != PG_CATALOG_NAMESPACE &&		!oidMember(typnamespace, namespaceSearchPath))		visible = false;	else	{		/*		 * If it is in the path, it might still not be visible; it could		 * be hidden by another type of the same name earlier in the path.		 * So we must do a slow check to see if this type would be found		 * by TypenameGetTypid.		 */		char	   *typname = NameStr(typform->typname);		visible = (TypenameGetTypid(typname) == typid);	}	ReleaseSysCache(typtup);	return visible;}/* * FuncnameGetCandidates *		Given a possibly-qualified function name and argument count, *		retrieve a list of the possible matches. * * If nargs is -1, we return all functions matching the given name, * regardless of argument count. * * We search a single namespace if the function name is qualified, else * all namespaces in the search path.  The return list will never contain * multiple entries with identical argument lists --- in the multiple- * namespace case, we arrange for entries in earlier namespaces to mask * identical entries in later namespaces. */FuncCandidateListFuncnameGetCandidates(List *names, int nargs){	FuncCandidateList resultList = NULL;	char	   *schemaname;	char	   *funcname;	Oid			namespaceId;	CatCList   *catlist;	int			i;	/* deconstruct the name list */	DeconstructQualifiedName(names, &schemaname, &funcname);	if (schemaname)	{		/* use exact schema given */		namespaceId = LookupExplicitNamespace(schemaname);	}	else	{		/* flag to indicate we need namespace search */		namespaceId = InvalidOid;		recomputeNamespacePath();	}	/* Search syscache by name and (optionally) nargs only */	if (nargs >= 0)		catlist = SearchSysCacheList(PROCNAMENSP, 2,									 CStringGetDatum(funcname),									 Int16GetDatum(nargs),									 0, 0);	else		catlist = SearchSysCacheList(PROCNAMENSP, 1,									 CStringGetDatum(funcname),									 0, 0, 0);	for (i = 0; i < catlist->n_members; i++)	{		HeapTuple	proctup = &catlist->members[i]->tuple;		Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);		int			pathpos = 0;		FuncCandidateList newResult;		nargs = procform->pronargs;		if (OidIsValid(namespaceId))		{			/* Consider only procs in specified namespace */

⌨️ 快捷键说明

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