unchanged: --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -706,7 +706,7 @@ objectNamesToOids(ObjectType objtype, List *objnames) char *nspname = strVal(lfirst(cell)); Oid oid; - oid = get_namespace_oid(nspname, false); + oid = get_namespace_oid(nspname, InvalidOid, false); objects = lappend_oid(objects, oid); } break; @@ -1113,7 +1113,7 @@ SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames) { char *nspname = strVal(lfirst(nspcell)); - iacls->nspid = get_namespace_oid(nspname, false); + iacls->nspid = get_namespace_oid(nspname, InvalidOid, false); /* * We used to insist that the target role have CREATE privileges @@ -3372,6 +3372,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype, case OBJECT_MATVIEW: msg = gettext_noop("permission denied for materialized view %s"); break; + case OBJECT_MODULE: + msg = gettext_noop("permission denied for module %s"); + break; case OBJECT_OPCLASS: msg = gettext_noop("permission denied for operator class %s"); break; @@ -3500,6 +3503,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype, case OBJECT_MATVIEW: msg = gettext_noop("must be owner of materialized view %s"); break; + case OBJECT_MODULE: + msg = gettext_noop("must be owner of module %s"); + break; case OBJECT_OPCLASS: msg = gettext_noop("must be owner of operator class %s"); break; unchanged: --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -473,7 +473,7 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation) return myTempNamespace; } /* use exact schema given */ - namespaceId = get_namespace_oid(newRelation->schemaname, false); + namespaceId = get_namespace_oid(newRelation->schemaname, InvalidOid, false); /* we do not check for USAGE rights here! */ } else if (newRelation->relpersistence == RELPERSISTENCE_TEMP) @@ -945,9 +945,11 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames, { FuncCandidateList resultList = NULL; bool any_special = false; - char *schemaname; + char *nspname; + char *modulename; char *funcname; Oid namespaceId; + Oid moduleId; CatCList *catlist; int i; @@ -955,19 +957,31 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames, Assert(nargs >= 0 || !(expand_variadic | expand_defaults)); /* deconstruct the name list */ - DeconstructQualifiedName(names, &schemaname, &funcname); + DeconstructQualifiedName(names, &nspname, &modulename, &funcname, true); - if (schemaname) + if (nspname && modulename) { /* use exact schema given */ - namespaceId = LookupExplicitNamespace(schemaname, missing_ok); + namespaceId = LookupExplicitNamespace(nspname, missing_ok); if (!OidIsValid(namespaceId)) return NULL; + + moduleId = get_namespace_oid(modulename, namespaceId, true); + if (!OidIsValid(moduleId)) + return NULL; + } + else if (nspname) + { + moduleId = InvalidOid; + namespaceId = LookupExplicitNamespace(nspname, true); + if (!OidIsValid(namespaceId)) + recomputeNamespacePath(); } else { /* flag to indicate we need namespace search */ namespaceId = InvalidOid; + moduleId = InvalidOid; recomputeNamespacePath(); } @@ -987,9 +1001,15 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames, int *argnumbers = NULL; FuncCandidateList newResult; - if (OidIsValid(namespaceId)) + if (OidIsValid(moduleId)) { - /* Consider only procs in specified namespace */ + /* Consider only procs in specified module */ + if (procform->pronamespace != moduleId) + continue; + } + else if (OidIsValid(namespaceId)) + { + /* Consider only procs in specified schema */ if (procform->pronamespace != namespaceId) continue; } @@ -1003,7 +1023,16 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames, foreach(nsp, activeSearchPath) { - if (procform->pronamespace == lfirst_oid(nsp) && + /* check if there is a module in the schema */ + if (nspname) + { + moduleId = get_namespace_oid(nspname, lfirst_oid(nsp), true); + if (OidIsValid(moduleId)) + if (procform->pronamespace == moduleId && + procform->pronamespace != myTempNamespace) + break; + } + else if (procform->pronamespace == lfirst_oid(nsp) && procform->pronamespace != myTempNamespace) break; pathpos++; @@ -1449,7 +1478,6 @@ FunctionIsVisible(Oid funcid) clist = FuncnameGetCandidates(list_make1(makeString(proname)), nargs, NIL, false, false, false); - for (; clist; clist = clist->next) { if (memcmp(clist->args, procform->proargtypes.values, @@ -1488,7 +1516,7 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright) ListCell *l; /* deconstruct the name list */ - DeconstructQualifiedName(names, &schemaname, &opername); + DeconstructQualifiedName(names, &schemaname, NULL, &opername, false); if (schemaname) { @@ -1595,7 +1623,7 @@ OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok) int i; /* deconstruct the name list */ - DeconstructQualifiedName(names, &schemaname, &opername); + DeconstructQualifiedName(names, &schemaname, NULL, &opername, false); if (schemaname) { @@ -2183,7 +2211,7 @@ get_statistics_object_oid(List *names, bool missing_ok) ListCell *l; /* deconstruct the name list */ - DeconstructQualifiedName(names, &schemaname, &stats_name); + DeconstructQualifiedName(names, &schemaname, NULL, &stats_name, false); if (schemaname) { @@ -2224,6 +2252,60 @@ get_statistics_object_oid(List *names, bool missing_ok) return stats_oid; } +/* + * get_module_oid - find a module by possibly qualified name + * + * If not found, returns InvalidOid if missing_ok, else throws error + */ +Oid +get_module_oid(List *names, bool missing_ok) +{ + char *schemaname; + char *modulename; + Oid namespaceId; + Oid moduleId = InvalidOid; + ListCell *l; + + /* deconstruct the name list */ + DeconstructQualifiedName(names, &schemaname, NULL, &modulename, false); + + if (schemaname) + { + /* use exact schema given */ + namespaceId = LookupExplicitNamespace(schemaname, missing_ok); + if (missing_ok && !OidIsValid(namespaceId)) + moduleId = InvalidOid; + else + moduleId = GetSysCacheOid2(NAMESPACENAME, Anum_pg_namespace_oid, + CStringGetDatum(modulename), ObjectIdGetDatum(namespaceId)); + } + else + { + /* search for it in search path */ + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + moduleId = GetSysCacheOid2(NAMESPACENAME, Anum_pg_namespace_oid, + CStringGetDatum(modulename), ObjectIdGetDatum(namespaceId)); + if (OidIsValid(moduleId)) + break; + } + } + + if (!OidIsValid(moduleId) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("module \"%s\" does not exist", + NameListToString(names)))); + + return moduleId; +} + /* * StatisticsObjIsVisible * Determine whether a statistics object (identified by OID) is visible in @@ -2305,7 +2387,7 @@ get_ts_parser_oid(List *names, bool missing_ok) ListCell *l; /* deconstruct the name list */ - DeconstructQualifiedName(names, &schemaname, &parser_name); + DeconstructQualifiedName(names, &schemaname, NULL, &parser_name, false); if (schemaname) { @@ -2431,7 +2513,7 @@ get_ts_dict_oid(List *names, bool missing_ok) ListCell *l; /* deconstruct the name list */ - DeconstructQualifiedName(names, &schemaname, &dict_name); + DeconstructQualifiedName(names, &schemaname, NULL, &dict_name, false); if (schemaname) { @@ -2558,7 +2640,7 @@ get_ts_template_oid(List *names, bool missing_ok) ListCell *l; /* deconstruct the name list */ - DeconstructQualifiedName(names, &schemaname, &template_name); + DeconstructQualifiedName(names, &schemaname, NULL, &template_name, false); if (schemaname) { @@ -2684,7 +2766,7 @@ get_ts_config_oid(List *names, bool missing_ok) ListCell *l; /* deconstruct the name list */ - DeconstructQualifiedName(names, &schemaname, &config_name); + DeconstructQualifiedName(names, &schemaname, NULL, &config_name, false); if (schemaname) { @@ -2800,17 +2882,21 @@ TSConfigIsVisible(Oid cfgid) /* * DeconstructQualifiedName * Given a possibly-qualified name expressed as a list of String nodes, - * extract the schema name and object name. + * extract the schema name, module name and object name. * * *nspname_p is set to NULL if there is no explicit schema name. + * *modname_p is set to NULL if there is no explicit module name. */ void DeconstructQualifiedName(List *names, char **nspname_p, - char **objname_p) + char **modname_p, + char **objname_p, + bool check_module) { char *catalogname; - char *schemaname = NULL; + char *nspname = NULL; + char *modulename = NULL; char *objname = NULL; switch (list_length(names)) @@ -2819,22 +2905,70 @@ DeconstructQualifiedName(List *names, objname = strVal(linitial(names)); break; case 2: - schemaname = strVal(linitial(names)); + nspname = strVal(linitial(names)); objname = strVal(lsecond(names)); break; case 3: - catalogname = strVal(linitial(names)); - schemaname = strVal(lsecond(names)); - objname = strVal(lthird(names)); + if (check_module) + { + /* + * Since we don't allow cross-database references, check if the + * first element is the current catalog and if is different assume + * the first element is a schema + */ + if (strcmp(strVal(linitial(names)), get_database_name(MyDatabaseId)) != 0) + { + nspname = strVal(linitial(names)); + modulename = strVal(lsecond(names)); + } + else + { + catalogname = strVal(linitial(names)); + nspname = strVal(lsecond(names)); + } - /* - * We check the catalog name and then ignore it. - */ - if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0) + objname = strVal(lthird(names)); + } + else + { + catalogname = strVal(linitial(names)); + nspname = strVal(lsecond(names)); + objname = strVal(lthird(names)); + + /* + * We check the catalog name and then ignore it. + */ + if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cross-database references are not implemented: %s", + NameListToString(names)))); + } + break; + case 4: + if (check_module) + { + catalogname = strVal(linitial(names)); + nspname = strVal(lsecond(names)); + modulename = strVal(lthird(names)); + objname = strVal(lfourth(names)); + + /* + * We check the catalog name and then ignore it. + */ + if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cross-database references are not implemented: %s", + NameListToString(names)))); + } + else + { ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cross-database references are not implemented: %s", + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("improper qualified name (too many dotted names): %s", NameListToString(names)))); + } break; default: ereport(ERROR, @@ -2844,7 +2978,9 @@ DeconstructQualifiedName(List *names, break; } - *nspname_p = schemaname; + *nspname_p = nspname; + if (modname_p) + *modname_p = modulename; *objname_p = objname; } @@ -2878,7 +3014,7 @@ LookupNamespaceNoError(const char *nspname) return InvalidOid; } - return get_namespace_oid(nspname, true); + return get_namespace_oid(nspname, InvalidOid, true); } /* @@ -2907,7 +3043,7 @@ LookupExplicitNamespace(const char *nspname, bool missing_ok) */ } - namespaceId = get_namespace_oid(nspname, missing_ok); + namespaceId = get_namespace_oid(nspname, InvalidOid, missing_ok); if (missing_ok && !OidIsValid(namespaceId)) return InvalidOid; @@ -2945,7 +3081,7 @@ LookupCreationNamespace(const char *nspname) return myTempNamespace; } - namespaceId = get_namespace_oid(nspname, false); + namespaceId = get_namespace_oid(nspname, InvalidOid, false); aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) @@ -2991,25 +3127,34 @@ CheckSetNamespace(Oid oldNspOid, Oid nspOid) * if we have to create or clean out the temp namespace. */ Oid -QualifiedNameGetCreationNamespace(List *names, char **objname_p) +QualifiedNameGetCreationNamespace(List *names, char **objname_p, bool check_module) { - char *schemaname; + char *nspname = NULL; + char *modulename = NULL; + Oid nspparent; Oid namespaceId; /* deconstruct the name list */ - DeconstructQualifiedName(names, &schemaname, objname_p); + DeconstructQualifiedName(names, &nspname, &modulename, objname_p, check_module); - if (schemaname) + if (nspname && modulename) + { + /* use exact schema given */ + nspparent = LookupExplicitNamespace(nspname, false); + + namespaceId = get_namespace_oid(modulename, nspparent, false); + } + else if (nspname) { /* check for pg_temp alias */ - if (strcmp(schemaname, "pg_temp") == 0) + if (strcmp(nspname, "pg_temp") == 0) { /* Initialize temp namespace */ AccessTempTableNamespace(false); return myTempNamespace; } /* use exact schema given */ - namespaceId = get_namespace_oid(schemaname, false); + namespaceId = get_namespace_oid(nspname, InvalidOid, false); /* we do not check for USAGE rights here! */ } else @@ -3039,12 +3184,12 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p) * true, just return InvalidOid. */ Oid -get_namespace_oid(const char *nspname, bool missing_ok) +get_namespace_oid(const char *nspname, Oid nspnamespace, bool missing_ok) { Oid oid; - oid = GetSysCacheOid1(NAMESPACENAME, Anum_pg_namespace_oid, - CStringGetDatum(nspname)); + oid = GetSysCacheOid2(NAMESPACENAME, Anum_pg_namespace_oid, + CStringGetDatum(nspname), ObjectIdGetDatum(nspnamespace)); if (!OidIsValid(oid) && !missing_ok) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_SCHEMA), @@ -3607,7 +3752,7 @@ get_collation_oid(List *name, bool missing_ok) ListCell *l; /* deconstruct the name list */ - DeconstructQualifiedName(name, &schemaname, &collation_name); + DeconstructQualifiedName(name, &schemaname, NULL, &collation_name, false); if (schemaname) { @@ -3660,7 +3805,7 @@ get_conversion_oid(List *name, bool missing_ok) ListCell *l; /* deconstruct the name list */ - DeconstructQualifiedName(name, &schemaname, &conversion_name); + DeconstructQualifiedName(name, &schemaname, NULL, &conversion_name, false); if (schemaname) { @@ -3789,7 +3934,7 @@ recomputeNamespacePath(void) char *rname; rname = NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname); - namespaceId = get_namespace_oid(rname, true); + namespaceId = get_namespace_oid(rname, InvalidOid, true); ReleaseSysCache(tuple); if (OidIsValid(namespaceId) && !list_member_oid(oidlist, namespaceId) && @@ -3818,7 +3963,7 @@ recomputeNamespacePath(void) else { /* normal namespace reference */ - namespaceId = get_namespace_oid(curname, true); + namespaceId = get_namespace_oid(curname, InvalidOid, true); if (OidIsValid(namespaceId) && !list_member_oid(oidlist, namespaceId) && pg_namespace_aclcheck(namespaceId, roleid, @@ -3987,7 +4132,7 @@ InitTempTableNamespace(void) snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId); - namespaceId = get_namespace_oid(namespaceName, true); + namespaceId = get_namespace_oid(namespaceName, InvalidOid, true); if (!OidIsValid(namespaceId)) { /* @@ -3998,8 +4143,8 @@ InitTempTableNamespace(void) * 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_SUPERUSERID, - true); + namespaceId = NamespaceCreate(namespaceName, InvalidOid, NSPKIND_SCHEMA, + BOOTSTRAP_SUPERUSERID, true); /* Advance command counter to make namespace visible */ CommandCounterIncrement(); } @@ -4020,11 +4165,11 @@ InitTempTableNamespace(void) snprintf(namespaceName, sizeof(namespaceName), "pg_toast_temp_%d", MyBackendId); - toastspaceId = get_namespace_oid(namespaceName, true); + toastspaceId = get_namespace_oid(namespaceName, InvalidOid, true); if (!OidIsValid(toastspaceId)) { - toastspaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID, - true); + toastspaceId = NamespaceCreate(namespaceName, InvalidOid, NSPKIND_SCHEMA, + BOOTSTRAP_SUPERUSERID, true); /* Advance command counter to make namespace visible */ CommandCounterIncrement(); } unchanged: --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -406,12 +406,26 @@ static const ObjectPropertyType ObjectProperty[] = NAMESPACENAME, Anum_pg_namespace_oid, Anum_pg_namespace_nspname, - InvalidAttrNumber, + Anum_pg_namespace_nspnamespace, Anum_pg_namespace_nspowner, Anum_pg_namespace_nspacl, OBJECT_SCHEMA, true }, + { + "module", + NamespaceRelationId, + NamespaceOidIndexId, + NAMESPACEOID, + NAMESPACENAME, + Anum_pg_namespace_oid, + Anum_pg_namespace_nspname, + Anum_pg_namespace_nspnamespace, + Anum_pg_namespace_nspowner, + Anum_pg_namespace_nspacl, + OBJECT_MODULE, + true + }, { "relation", RelationRelationId, @@ -765,6 +779,10 @@ static const struct object_type_map { "schema", OBJECT_SCHEMA }, + /* OCLASS_MODULE */ + { + "module", OBJECT_MODULE + }, /* OCLASS_TSPARSER */ { "text search parser", OBJECT_TSPARSER @@ -1128,6 +1146,12 @@ get_object_address(ObjectType objtype, Node *object, missing_ok); address.objectSubId = 0; break; + case OBJECT_MODULE: + address.classId = NamespaceRelationId; + address.objectId = get_module_oid(castNode(List, object), + missing_ok); + address.objectSubId = 0; + break; default: elog(ERROR, "unrecognized objtype: %d", (int) objtype); /* placate compiler, in case it thinks elog might return */ @@ -1281,7 +1305,7 @@ get_object_address_unqualified(ObjectType objtype, break; case OBJECT_SCHEMA: address.classId = NamespaceRelationId; - address.objectId = get_namespace_oid(name, missing_ok); + address.objectId = get_namespace_oid(name, InvalidOid, missing_ok); address.objectSubId = 0; break; case OBJECT_LANGUAGE: @@ -2013,7 +2037,7 @@ get_object_address_defacl(List *object, bool missing_ok) */ if (schema) { - schemaid = get_namespace_oid(schema, true); + schemaid = get_namespace_oid(schema, InvalidOid, true); if (schemaid == InvalidOid) goto not_found; } @@ -2267,6 +2291,7 @@ pg_get_object_address(PG_FUNCTION_ARGS) case OBJECT_TABCONSTRAINT: case OBJECT_OPCLASS: case OBJECT_OPFAMILY: + case OBJECT_MODULE: objnode = (Node *) name; break; case OBJECT_ACCESS_METHOD: @@ -2431,6 +2456,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, NameListToString((castNode(ObjectWithArgs, object))->objname)); break; case OBJECT_SCHEMA: + case OBJECT_MODULE: if (!pg_namespace_ownercheck(address.objectId, roleid)) aclcheck_error(ACLCHECK_NOT_OWNER, objtype, strVal((Value *) object)); unchanged: --- a/src/backend/catalog/pg_namespace.c +++ b/src/backend/catalog/pg_namespace.c @@ -40,7 +40,8 @@ * --------------- */ Oid -NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp) +NamespaceCreate(const char *nspName, Oid nspnamespace, char nspkind, + Oid ownerId, bool isTemp) { Relation nspdesc; HeapTuple tup; @@ -58,7 +59,7 @@ NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp) elog(ERROR, "no namespace name supplied"); /* make sure there is no existing namespace of same name */ - if (SearchSysCacheExists1(NAMESPACENAME, PointerGetDatum(nspName))) + if (SearchSysCacheExists2(NAMESPACENAME, PointerGetDatum(nspName), nspnamespace)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_SCHEMA), errmsg("schema \"%s\" already exists", nspName))); @@ -85,6 +86,8 @@ NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp) namestrcpy(&nname, nspName); values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname); values[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(ownerId); + values[Anum_pg_namespace_nspnamespace - 1] = ObjectIdGetDatum(nspnamespace); + values[Anum_pg_namespace_nspkind - 1] = CharGetDatum(nspkind); if (nspacl != NULL) values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(nspacl); else unchanged: --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -1460,7 +1460,7 @@ CreateExtensionInternal(char *extensionName, if (schemaName) { /* If the user is giving us the schema name, it must exist already. */ - schemaOid = get_namespace_oid(schemaName, false); + schemaOid = get_namespace_oid(schemaName, InvalidOid, false); } if (control->schema != NULL) @@ -1484,7 +1484,7 @@ CreateExtensionInternal(char *extensionName, schemaName = control->schema; /* Find or create the schema in case it does not exist. */ - schemaOid = get_namespace_oid(schemaName, true); + schemaOid = get_namespace_oid(schemaName, InvalidOid, true); if (!OidIsValid(schemaOid)) { @@ -1501,7 +1501,7 @@ CreateExtensionInternal(char *extensionName, * CreateSchemaCommand includes CommandCounterIncrement, so new * schema is now visible. */ - schemaOid = get_namespace_oid(schemaName, false); + schemaOid = get_namespace_oid(schemaName, InvalidOid, false); } } else if (!OidIsValid(schemaOid)) unchanged: --- a/src/backend/commands/schemacmds.c +++ b/src/backend/commands/schemacmds.c @@ -113,7 +113,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString, * creation-permission check first, we do likewise. */ if (stmt->if_not_exists && - SearchSysCacheExists1(NAMESPACENAME, PointerGetDatum(schemaName))) + SearchSysCacheExists2(NAMESPACENAME, PointerGetDatum(schemaName), InvalidOid)) { ereport(NOTICE, (errcode(ERRCODE_DUPLICATE_SCHEMA), @@ -135,7 +135,8 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString, save_sec_context | SECURITY_LOCAL_USERID_CHANGE); /* Create the schema's namespace */ - namespaceId = NamespaceCreate(schemaName, owner_uid, false); + namespaceId = NamespaceCreate(schemaName, InvalidOid, NSPKIND_SCHEMA, + owner_uid, false); /* Advance cmd counter to make the namespace visible */ CommandCounterIncrement(); @@ -226,7 +227,7 @@ RenameSchema(const char *oldname, const char *newname) rel = table_open(NamespaceRelationId, RowExclusiveLock); - tup = SearchSysCacheCopy1(NAMESPACENAME, CStringGetDatum(oldname)); + tup = SearchSysCacheCopy2(NAMESPACENAME, CStringGetDatum(oldname), InvalidOid); if (!HeapTupleIsValid(tup)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_SCHEMA), @@ -236,7 +237,7 @@ RenameSchema(const char *oldname, const char *newname) nspOid = nspform->oid; /* make sure the new name doesn't exist */ - if (OidIsValid(get_namespace_oid(newname, true))) + if (OidIsValid(get_namespace_oid(newname, InvalidOid, true))) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_SCHEMA), errmsg("schema \"%s\" already exists", newname))); @@ -306,7 +307,7 @@ AlterSchemaOwner(const char *name, Oid newOwnerId) rel = table_open(NamespaceRelationId, RowExclusiveLock); - tup = SearchSysCache1(NAMESPACENAME, CStringGetDatum(name)); + tup = SearchSysCache2(NAMESPACENAME, CStringGetDatum(name), InvalidOid); if (!HeapTupleIsValid(tup)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_SCHEMA), unchanged: --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -3827,7 +3827,7 @@ convert_schema_name(text *schemaname) { char *nspname = text_to_cstring(schemaname); - return get_namespace_oid(nspname, false); + return get_namespace_oid(nspname, InvalidOid, false); } /* unchanged: --- a/src/backend/utils/adt/pg_upgrade_support.c +++ b/src/backend/utils/adt/pg_upgrade_support.c @@ -184,7 +184,7 @@ binary_upgrade_create_empty_extension(PG_FUNCTION_ARGS) InsertExtensionTuple(text_to_cstring(extName), GetUserId(), - get_namespace_oid(text_to_cstring(schemaName), false), + get_namespace_oid(text_to_cstring(schemaName), InvalidOid, false), relocatable, text_to_cstring(extVersion), extConfig, unchanged: --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -1762,7 +1762,7 @@ regnamespacein(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_NAME), errmsg("invalid name syntax"))); - result = get_namespace_oid(strVal(linitial(names)), false); + result = get_namespace_oid(strVal(linitial(names)), InvalidOid, false); PG_RETURN_OID(result); } @@ -1786,7 +1786,7 @@ to_regnamespace(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_NAME), errmsg("invalid name syntax"))); - result = get_namespace_oid(strVal(linitial(names)), true); + result = get_namespace_oid(strVal(linitial(names)), InvalidOid, true); if (OidIsValid(result)) PG_RETURN_OID(result); unchanged: --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -509,10 +509,10 @@ static const struct cachedesc cacheinfo[] = { }, {NamespaceRelationId, /* NAMESPACENAME */ NamespaceNameIndexId, - 1, + 2, { Anum_pg_namespace_nspname, - 0, + Anum_pg_namespace_nspnamespace, 0, 0 }, only in patch2: unchanged: --- a/src/include/catalog/namespace.h +++ b/src/include/catalog/namespace.h @@ -135,15 +135,18 @@ extern Oid get_ts_config_oid(List *names, bool missing_ok); extern bool TSConfigIsVisible(Oid cfgid); extern void DeconstructQualifiedName(List *names, - char **nspname_p, - char **objname_p); + char **nspname_p, + char **modname_p, + char **objname_p, + bool check_module); extern Oid LookupNamespaceNoError(const char *nspname); extern Oid LookupExplicitNamespace(const char *nspname, bool missing_ok); -extern Oid get_namespace_oid(const char *nspname, bool missing_ok); +extern Oid get_namespace_oid(const char *nspname, Oid nspnamespace, bool missing_ok); +extern Oid get_module_oid(List *names, bool missing_ok); extern Oid LookupCreationNamespace(const char *nspname); extern void CheckSetNamespace(Oid oldNspOid, Oid nspOid); -extern Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p); +extern Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p, bool check_module); extern RangeVar *makeRangeVarFromNameList(List *names); extern char *NameListToString(List *names); extern char *NameListToQuotedString(List *names); only in patch2: unchanged: --- a/src/include/catalog/pg_namespace.dat +++ b/src/include/catalog/pg_namespace.dat @@ -14,12 +14,15 @@ { oid => '11', oid_symbol => 'PG_CATALOG_NAMESPACE', descr => 'system catalog schema', - nspname => 'pg_catalog', nspacl => '_null_' }, + nspname => 'pg_catalog', nspnamespace => '0', + nspkind => 's', nspacl => '_null_' }, { oid => '99', oid_symbol => 'PG_TOAST_NAMESPACE', descr => 'reserved schema for TOAST tables', - nspname => 'pg_toast', nspacl => '_null_' }, + nspname => 'pg_toast', nspnamespace => '0', + nspkind => 's', nspacl => '_null_' }, { oid => '2200', oid_symbol => 'PG_PUBLIC_NAMESPACE', descr => 'standard public schema', - nspname => 'public', nspacl => '_null_' }, + nspname => 'public', nspnamespace => '0', + nspkind => 's', nspacl => '_null_' }, ] only in patch2: unchanged: --- a/src/include/catalog/pg_namespace.h +++ b/src/include/catalog/pg_namespace.h @@ -29,6 +29,8 @@ * * nspname name of the namespace * nspowner owner (creator) of the namespace + * nspnamespace parent of the namespace + * nspkind the type namespace * nspacl access privilege list * ---------------------------------------------------------------- */ @@ -38,6 +40,9 @@ CATALOG(pg_namespace,2615,NamespaceRelationId) NameData nspname; Oid nspowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); + Oid nspnamespace BKI_DEFAULT(0); + char nspkind BKI_DEFAULT(s); + #ifdef CATALOG_VARLEN /* variable-length fields start here */ aclitem nspacl[1]; @@ -53,14 +58,18 @@ typedef FormData_pg_namespace *Form_pg_namespace; DECLARE_TOAST(pg_namespace, 4163, 4164); -DECLARE_UNIQUE_INDEX(pg_namespace_nspname_index, 2684, on pg_namespace using btree(nspname name_ops)); +DECLARE_UNIQUE_INDEX(pg_namespace_nspname_index, 2684, on pg_namespace using btree(nspname name_ops, nspnamespace oid_ops)); #define NamespaceNameIndexId 2684 DECLARE_UNIQUE_INDEX_PKEY(pg_namespace_oid_index, 2685, on pg_namespace using btree(oid oid_ops)); #define NamespaceOidIndexId 2685 +#define NSPKIND_SCHEMA 's' /* schema */ +#define NSPKIND_MODULE 'm' /* module */ + /* * prototypes for functions in pg_namespace.c */ -extern Oid NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp); +extern Oid NamespaceCreate(const char *nspName, Oid nspnamespace, char nspkind, + Oid ownerId, bool isTemp); #endif /* PG_NAMESPACE_H */