📄 namespace.c
字号:
proc = FindDefaultConversion(namespaceId, for_encoding, to_encoding); if (OidIsValid(proc)) return proc; } /* Not found in path */ return InvalidOid;}/* * recomputeNamespacePath - recompute path derived variables if needed. */static voidrecomputeNamespacePath(void){ AclId userId = GetUserId(); char *rawname; List *namelist; List *oidlist; List *newpath; List *l; Oid firstNS; MemoryContext oldcxt; /* * Do nothing if path is already valid. */ if (namespaceSearchPathValid && namespaceUser == userId) return; /* Need a modifiable copy of namespace_search_path string */ rawname = pstrdup(namespace_search_path); /* Parse string into list of identifiers */ if (!SplitIdentifierString(rawname, ',', &namelist)) { /* syntax error in name list */ /* this should not happen if GUC checked check_search_path */ elog(ERROR, "invalid list syntax"); } /* * Convert the list of names to a list of OIDs. If any names are not * recognizable or we don't have read access, just leave them out of * the list. (We can't raise an error, since the search_path setting * has already been accepted.) Don't make duplicate entries, either. */ oidlist = NIL; foreach(l, namelist) { char *curname = (char *) lfirst(l); Oid namespaceId; if (strcmp(curname, "$user") == 0) { /* $user --- substitute namespace matching user name, if any */ HeapTuple tuple; tuple = SearchSysCache(SHADOWSYSID, ObjectIdGetDatum(userId), 0, 0, 0); if (HeapTupleIsValid(tuple)) { char *uname; uname = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename); namespaceId = GetSysCacheOid(NAMESPACENAME, CStringGetDatum(uname), 0, 0, 0); ReleaseSysCache(tuple); if (OidIsValid(namespaceId) && !oidMember(namespaceId, oidlist) && pg_namespace_aclcheck(namespaceId, userId, ACL_USAGE) == ACLCHECK_OK) oidlist = lappendo(oidlist, namespaceId); } } else { /* normal namespace reference */ namespaceId = GetSysCacheOid(NAMESPACENAME, CStringGetDatum(curname), 0, 0, 0); if (OidIsValid(namespaceId) && !oidMember(namespaceId, oidlist) && pg_namespace_aclcheck(namespaceId, userId, ACL_USAGE) == ACLCHECK_OK) oidlist = lappendo(oidlist, namespaceId); } } /* * Remember the first member of the explicit list. */ if (oidlist == NIL) firstNS = InvalidOid; else firstNS = lfirsto(oidlist); /* * Add any implicitly-searched namespaces to the list. Note these go * on the front, not the back; also notice that we do not check USAGE * permissions for these. */ if (!oidMember(PG_CATALOG_NAMESPACE, oidlist)) oidlist = lconso(PG_CATALOG_NAMESPACE, oidlist); if (OidIsValid(myTempNamespace) && !oidMember(myTempNamespace, oidlist)) oidlist = lconso(myTempNamespace, oidlist); if (OidIsValid(mySpecialNamespace) && !oidMember(mySpecialNamespace, oidlist)) oidlist = lconso(mySpecialNamespace, oidlist); /* * Now that we've successfully built the new list of namespace OIDs, * save it in permanent storage. */ oldcxt = MemoryContextSwitchTo(TopMemoryContext); newpath = listCopy(oidlist); MemoryContextSwitchTo(oldcxt); /* Now safe to assign to state variable. */ freeList(namespaceSearchPath); namespaceSearchPath = newpath; /* * Update info derived from search path. */ firstExplicitNamespace = firstNS; if (OidIsValid(mySpecialNamespace)) defaultCreationNamespace = mySpecialNamespace; else defaultCreationNamespace = firstNS; /* Mark the path valid. */ namespaceSearchPathValid = true; namespaceUser = userId; /* Clean up. */ pfree(rawname); freeList(namelist); freeList(oidlist);}/* * InitTempTableNamespace * Initialize temp table namespace on first use in a particular backend */static voidInitTempTableNamespace(void){ char namespaceName[NAMEDATALEN]; Oid namespaceId; /* * First, do permission check to see if we are authorized to make temp * tables. We use a nonstandard error message here since * "databasename: permission denied" might be a tad cryptic. * * Note we apply the check to the session user, not the currently active * userid, since we are not going to change our minds about temp table * availability during the session. */ if (pg_database_aclcheck(MyDatabaseId, GetSessionUserId(), ACL_CREATE_TEMP) != ACLCHECK_OK) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied to create temporary tables in database \"%s\"", get_database_name(MyDatabaseId)))); snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId); namespaceId = GetSysCacheOid(NAMESPACENAME, CStringGetDatum(namespaceName), 0, 0, 0); if (!OidIsValid(namespaceId)) { /* * First use of this temp namespace in this database; create it. * The temp namespaces are always owned by the superuser. We * leave their permissions at default --- i.e., no access except * to superuser --- to ensure that unprivileged users can't peek * at other backends' temp tables. This works because the places * that access the temp namespace for my own backend skip * permissions checks on it. */ namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_USESYSID); /* Advance command counter to make namespace visible */ CommandCounterIncrement(); } else { /* * If the namespace already exists, clean it out (in case the * former owner crashed without doing so). */ RemoveTempRelations(namespaceId); } /* * Okay, we've prepared the temp namespace ... but it's not committed * yet, so all our work could be undone by transaction rollback. Set * flag for AtEOXact_Namespace to know what to do. */ myTempNamespace = namespaceId; firstTempTransaction = true; namespaceSearchPathValid = false; /* need to rebuild list */}/* * End-of-transaction cleanup for namespaces. */voidAtEOXact_Namespace(bool isCommit){ /* * If we abort the transaction in which a temp namespace was selected, * we'll have to do any creation or cleanout work over again. So, * just forget the namespace entirely until next time. On the other * hand, if we commit then register an exit callback to clean out the * temp tables at backend shutdown. (We only want to register the * callback once per session, so this is a good place to do it.) */ if (firstTempTransaction) { if (isCommit) on_shmem_exit(RemoveTempRelationsCallback, 0); else { myTempNamespace = InvalidOid; namespaceSearchPathValid = false; /* need to rebuild list */ } firstTempTransaction = false; } /* * Clean up if someone failed to do PopSpecialNamespace */ if (OidIsValid(mySpecialNamespace)) { mySpecialNamespace = InvalidOid; namespaceSearchPathValid = false; /* need to rebuild list */ }}/* * Remove all relations in the specified temp namespace. * * This is called at backend shutdown (if we made any temp relations). * It is also called when we begin using a pre-existing temp namespace, * in order to clean out any relations that might have been created by * a crashed backend. */static voidRemoveTempRelations(Oid tempNamespaceId){ ObjectAddress object; /* * We want to get rid of everything in the target namespace, but not * the namespace itself (deleting it only to recreate it later would * be a waste of cycles). We do this by finding everything that has a * dependency on the namespace. */ object.classId = get_system_catalog_relid(NamespaceRelationName); object.objectId = tempNamespaceId; object.objectSubId = 0; deleteWhatDependsOn(&object, false);}/* * Callback to remove temp relations at backend exit. */static voidRemoveTempRelationsCallback(void){ if (OidIsValid(myTempNamespace)) /* should always be true */ { /* Need to ensure we have a usable transaction. */ AbortOutOfAnyTransaction(); StartTransactionCommand(); RemoveTempRelations(myTempNamespace); CommitTransactionCommand(); }}/* * Routines for handling the GUC variable 'search_path'. *//* assign_hook: validate new search_path, do extra actions as needed */const char *assign_search_path(const char *newval, bool doit, bool interactive){ char *rawname; List *namelist; List *l; /* Need a modifiable copy of string */ rawname = pstrdup(newval); /* Parse string into list of identifiers */ if (!SplitIdentifierString(rawname, ',', &namelist)) { /* syntax error in name list */ pfree(rawname); freeList(namelist); return NULL; } /* * If we aren't inside a transaction, we cannot do database access so * cannot verify the individual names. Must accept the list on faith. */ if (interactive && IsTransactionState()) { /* * Verify that all the names are either valid namespace names or * "$user". We do not require $user to correspond to a valid * namespace. We do not check for USAGE rights, either; should * we? */ foreach(l, namelist) { char *curname = (char *) lfirst(l); if (strcmp(curname, "$user") == 0) continue; if (!SearchSysCacheExists(NAMESPACENAME, CStringGetDatum(curname), 0, 0, 0)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_SCHEMA), errmsg("schema \"%s\" does not exist", curname))); } } pfree(rawname); freeList(namelist); /* * We mark the path as needing recomputation, but don't do anything * until it's needed. This avoids trying to do database access during * GUC initialization. */ if (doit) namespaceSearchPathValid = false; return newval;}/* * InitializeSearchPath: initialize module during InitPostgres. * * This is called after we are up enough to be able to do catalog lookups. */voidInitializeSearchPath(void){ if (IsBootstrapProcessingMode()) { /* * In bootstrap mode, the search path must be 'pg_catalog' so that * tables are created in the proper namespace; ignore the GUC * setting. */ MemoryContext oldcxt; oldcxt = MemoryContextSwitchTo(TopMemoryContext); namespaceSearchPath = makeListo1(PG_CATALOG_NAMESPACE); MemoryContextSwitchTo(oldcxt); defaultCreationNamespace = PG_CATALOG_NAMESPACE; firstExplicitNamespace = PG_CATALOG_NAMESPACE; namespaceSearchPathValid = true; namespaceUser = GetUserId(); } else { /* * In normal mode, arrange for a callback on any syscache * invalidation of pg_namespace rows. */ CacheRegisterSyscacheCallback(NAMESPACEOID, NamespaceCallback, (Datum) 0); /* Force search path to be recomputed on next use */ namespaceSearchPathValid = false; }}/* * NamespaceCallback * Syscache inval callback function */static voidNamespaceCallback(Datum arg, Oid relid){ /* Force search path to be recomputed on next use */ namespaceSearchPathValid = false;}/* * Fetch the active search path, expressed as a List of OIDs. * * The returned list includes the implicitly-prepended namespaces only if * includeImplicit is true. * * NB: caller must treat the list as read-only! */List *fetch_search_path(bool includeImplicit){ List *result; recomputeNamespacePath(); result = namespaceSearchPath; if (!includeImplicit) { while (result && lfirsto(result) != firstExplicitNamespace) result = lnext(result); } return result;}/* * Export the FooIsVisible functions as SQL-callable functions. */Datumpg_table_is_visible(PG_FUNCTION_ARGS){ Oid oid = PG_GETARG_OID(0); PG_RETURN_BOOL(RelationIsVisible(oid));}Datumpg_type_is_visible(PG_FUNCTION_ARGS){ Oid oid = PG_GETARG_OID(0); PG_RETURN_BOOL(TypeIsVisible(oid));}Datumpg_function_is_visible(PG_FUNCTION_ARGS){ Oid oid = PG_GETARG_OID(0); PG_RETURN_BOOL(FunctionIsVisible(oid));}Datumpg_operator_is_visible(PG_FUNCTION_ARGS){ Oid oid = PG_GETARG_OID(0); PG_RETURN_BOOL(OperatorIsVisible(oid));}Datumpg_opclass_is_visible(PG_FUNCTION_ARGS){ Oid oid = PG_GETARG_OID(0); PG_RETURN_BOOL(OpclassIsVisible(oid));}Datumpg_conversion_is_visible(PG_FUNCTION_ARGS){ Oid oid = PG_GETARG_OID(0); PG_RETURN_BOOL(ConversionIsVisible(oid));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -