236 lines
5.9 KiB
C
236 lines
5.9 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* 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;
|
|
}
|