?? namespace.c
字號(hào):
/*------------------------------------------------------------------------- * * 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 */
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -