/*------------------------------------------------------------------------- * * 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-2001, 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.3 2002/03/30 01:02:41 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "catalog/namespace.h" #include "catalog/pg_namespace.h" #include "miscadmin.h" #include "nodes/makefuncs.h" #include "utils/lsyscache.h" #include "utils/syscache.h" /* * 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. */ Oid RangeVarGetRelid(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, DatabaseName) != 0) elog(ERROR, "Cross-database references are not implemented"); } if (relation->schemaname) { namespaceId = GetSysCacheOid(NAMESPACENAME, CStringGetDatum(relation->schemaname), 0, 0, 0); if (!OidIsValid(namespaceId)) elog(ERROR, "Namespace \"%s\" does not exist", relation->schemaname); relId = get_relname_relid(relation->relname, namespaceId); } else { relId = RelnameGetRelid(relation->relname); } if (!OidIsValid(relId) && !failOK) { if (relation->schemaname) elog(ERROR, "Relation \"%s\".\"%s\" does not exist", relation->schemaname, relation->relname); else elog(ERROR, "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. */ Oid RangeVarGetCreationNamespace(const RangeVar *newRelation) { Oid namespaceId; /* * We check the catalog name and then ignore it. */ if (newRelation->catalogname) { if (strcmp(newRelation->catalogname, DatabaseName) != 0) elog(ERROR, "Cross-database references are not implemented"); } if (newRelation->schemaname) { namespaceId = GetSysCacheOid(NAMESPACENAME, CStringGetDatum(newRelation->schemaname), 0, 0, 0); if (!OidIsValid(namespaceId)) elog(ERROR, "Namespace \"%s\" does not exist", newRelation->schemaname); } else { /* XXX Wrong! Need to get a default schema from somewhere */ namespaceId = PG_CATALOG_NAMESPACE; } return namespaceId; } /* * RelnameGetRelid * Try to resolve an unqualified relation name. * Returns OID if relation found in search path, else InvalidOid. */ Oid RelnameGetRelid(const char *relname) { /* XXX Wrong! must search search path */ return get_relname_relid(relname, PG_CATALOG_NAMESPACE); } /* * TypenameGetTypid * Try to resolve an unqualified datatype name. * Returns OID if type found in search path, else InvalidOid. */ Oid TypenameGetTypid(const char *typname) { /* XXX wrong, should use namespace search */ return GetSysCacheOid(TYPENAMENSP, PointerGetDatum(typname), ObjectIdGetDatum(PG_CATALOG_NAMESPACE), 0, 0); } /* * QualifiedNameGetCreationNamespace * Given a possibly-qualified name for an object (in List-of-Values * format), determine what namespace the object should be created in. * Also extract and return the object name (last component of list). */ Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p) { char *catalogname; char *schemaname = NULL; char *objname = NULL; Oid namespaceId; /* deconstruct the name list */ switch (length(names)) { case 1: objname = strVal(lfirst(names)); break; case 2: schemaname = strVal(lfirst(names)); objname = strVal(lsecond(names)); break; case 3: catalogname = strVal(lfirst(names)); schemaname = strVal(lsecond(names)); objname = strVal(lfirst(lnext(lnext(names)))); /* * We check the catalog name and then ignore it. */ if (strcmp(catalogname, DatabaseName) != 0) elog(ERROR, "Cross-database references are not implemented"); break; default: elog(ERROR, "Improper qualified name (too many dotted names)"); break; } if (schemaname) { namespaceId = GetSysCacheOid(NAMESPACENAME, CStringGetDatum(schemaname), 0, 0, 0); if (!OidIsValid(namespaceId)) elog(ERROR, "Namespace \"%s\" does not exist", schemaname); } else { /* XXX Wrong! Need to get a default schema from somewhere */ namespaceId = PG_CATALOG_NAMESPACE; } *objname_p = objname; return namespaceId; } /* * makeRangeVarFromNameList * Utility routine to convert a qualified-name list into RangeVar form. */ RangeVar * makeRangeVarFromNameList(List *names) { RangeVar *rel = makeRangeVar(NULL, NULL); switch (length(names)) { case 1: rel->relname = strVal(lfirst(names)); break; case 2: rel->schemaname = strVal(lfirst(names)); rel->relname = strVal(lsecond(names)); break; case 3: rel->catalogname = strVal(lfirst(names)); rel->schemaname = strVal(lsecond(names)); rel->relname = strVal(lfirst(lnext(lnext(names)))); break; default: elog(ERROR, "Improper relation name (too many dotted names)"); break; } return rel; }