Commit b5eebc1f authored by Tom Lane's avatar Tom Lane

Centralize code for interpreting schema references, which had gotten

copied more places than I first thought it would.  This fixes a bug:
a couple of these places were neglecting to enforce USAGE access on
explicitly-referenced schemas.
parent 7b970bc1
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.26 2002/07/20 05:16:56 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.27 2002/07/29 23:46:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -164,18 +164,7 @@ RangeVarGetRelid(const RangeVar *relation, bool failOK) ...@@ -164,18 +164,7 @@ RangeVarGetRelid(const RangeVar *relation, bool failOK)
if (relation->schemaname) if (relation->schemaname)
{ {
/* use exact schema given */ /* use exact schema given */
AclResult aclresult; namespaceId = LookupExplicitNamespace(relation->schemaname);
namespaceId = GetSysCacheOid(NAMESPACENAME,
CStringGetDatum(relation->schemaname),
0, 0, 0);
if (!OidIsValid(namespaceId))
elog(ERROR, "Namespace \"%s\" does not exist",
relation->schemaname);
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, relation->schemaname);
relId = get_relname_relid(relation->relname, namespaceId); relId = get_relname_relid(relation->relname, namespaceId);
} }
else else
...@@ -239,6 +228,7 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation) ...@@ -239,6 +228,7 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation)
if (!OidIsValid(namespaceId)) if (!OidIsValid(namespaceId))
elog(ERROR, "Namespace \"%s\" does not exist", elog(ERROR, "Namespace \"%s\" does not exist",
newRelation->schemaname); newRelation->schemaname);
/* we do not check for USAGE rights here! */
} }
else else
{ {
...@@ -431,53 +421,19 @@ FuncCandidateList ...@@ -431,53 +421,19 @@ FuncCandidateList
FuncnameGetCandidates(List *names, int nargs) FuncnameGetCandidates(List *names, int nargs)
{ {
FuncCandidateList resultList = NULL; FuncCandidateList resultList = NULL;
char *catalogname; char *schemaname;
char *schemaname = NULL; char *funcname;
char *funcname = NULL;
Oid namespaceId; Oid namespaceId;
CatCList *catlist; CatCList *catlist;
int i; int i;
/* deconstruct the name list */ /* deconstruct the name list */
switch (length(names)) DeconstructQualifiedName(names, &schemaname, &funcname);
{
case 1:
funcname = strVal(lfirst(names));
break;
case 2:
schemaname = strVal(lfirst(names));
funcname = strVal(lsecond(names));
break;
case 3:
catalogname = strVal(lfirst(names));
schemaname = strVal(lsecond(names));
funcname = 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): %s",
NameListToString(names));
break;
}
if (schemaname) if (schemaname)
{ {
/* use exact schema given */ /* use exact schema given */
AclResult aclresult; namespaceId = LookupExplicitNamespace(schemaname);
namespaceId = GetSysCacheOid(NAMESPACENAME,
CStringGetDatum(schemaname),
0, 0, 0);
if (!OidIsValid(namespaceId))
elog(ERROR, "Namespace \"%s\" does not exist",
schemaname);
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, schemaname);
} }
else else
{ {
...@@ -684,53 +640,19 @@ FuncCandidateList ...@@ -684,53 +640,19 @@ FuncCandidateList
OpernameGetCandidates(List *names, char oprkind) OpernameGetCandidates(List *names, char oprkind)
{ {
FuncCandidateList resultList = NULL; FuncCandidateList resultList = NULL;
char *catalogname; char *schemaname;
char *schemaname = NULL; char *opername;
char *opername = NULL;
Oid namespaceId; Oid namespaceId;
CatCList *catlist; CatCList *catlist;
int i; int i;
/* deconstruct the name list */ /* deconstruct the name list */
switch (length(names)) DeconstructQualifiedName(names, &schemaname, &opername);
{
case 1:
opername = strVal(lfirst(names));
break;
case 2:
schemaname = strVal(lfirst(names));
opername = strVal(lsecond(names));
break;
case 3:
catalogname = strVal(lfirst(names));
schemaname = strVal(lsecond(names));
opername = 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): %s",
NameListToString(names));
break;
}
if (schemaname) if (schemaname)
{ {
/* use exact schema given */ /* use exact schema given */
AclResult aclresult; namespaceId = LookupExplicitNamespace(schemaname);
namespaceId = GetSysCacheOid(NAMESPACENAME,
CStringGetDatum(schemaname),
0, 0, 0);
if (!OidIsValid(namespaceId))
elog(ERROR, "Namespace \"%s\" does not exist",
schemaname);
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, schemaname);
} }
else else
{ {
...@@ -1105,25 +1027,22 @@ OpclassIsVisible(Oid opcid) ...@@ -1105,25 +1027,22 @@ OpclassIsVisible(Oid opcid)
return visible; return visible;
} }
/* /*
* QualifiedNameGetCreationNamespace * DeconstructQualifiedName
* Given a possibly-qualified name for an object (in List-of-Values * Given a possibly-qualified name expressed as a list of String nodes,
* format), determine what namespace the object should be created in. * extract the schema name and object name.
* Also extract and return the object name (last component of list).
* *
* This is *not* used for tables. Hence, the TEMP table namespace is * *nspname_p is set to NULL if there is no explicit schema name.
* never selected as the creation target.
*/ */
Oid void
QualifiedNameGetCreationNamespace(List *names, char **objname_p) DeconstructQualifiedName(List *names,
char **nspname_p,
char **objname_p)
{ {
char *catalogname; char *catalogname;
char *schemaname = NULL; char *schemaname = NULL;
char *objname = NULL; char *objname = NULL;
Oid namespaceId;
/* deconstruct the name list */
switch (length(names)) switch (length(names))
{ {
case 1: case 1:
...@@ -1149,6 +1068,55 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p) ...@@ -1149,6 +1068,55 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p)
break; break;
} }
*nspname_p = schemaname;
*objname_p = objname;
}
/*
* LookupExplicitNamespace
* Process an explicitly-specified schema name: look up the schema
* and verify we have USAGE (lookup) rights in it.
*
* Returns the namespace OID. Raises elog if any problem.
*/
Oid
LookupExplicitNamespace(char *nspname)
{
Oid namespaceId;
AclResult aclresult;
namespaceId = GetSysCacheOid(NAMESPACENAME,
CStringGetDatum(nspname),
0, 0, 0);
if (!OidIsValid(namespaceId))
elog(ERROR, "Namespace \"%s\" does not exist", nspname);
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, nspname);
return namespaceId;
}
/*
* 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).
*
* This is *not* used for tables. Hence, the TEMP table namespace is
* never selected as the creation target.
*/
Oid
QualifiedNameGetCreationNamespace(List *names, char **objname_p)
{
char *schemaname;
char *objname;
Oid namespaceId;
/* deconstruct the name list */
DeconstructQualifiedName(names, &schemaname, &objname);
if (schemaname) if (schemaname)
{ {
/* use exact schema given */ /* use exact schema given */
...@@ -1158,6 +1126,7 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p) ...@@ -1158,6 +1126,7 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p)
if (!OidIsValid(namespaceId)) if (!OidIsValid(namespaceId))
elog(ERROR, "Namespace \"%s\" does not exist", elog(ERROR, "Namespace \"%s\" does not exist",
schemaname); schemaname);
/* we do not check for USAGE rights here! */
} }
else else
{ {
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Copyright (c) 1996-2001, PostgreSQL Global Development Group * Copyright (c) 1996-2001, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.52 2002/07/20 05:16:57 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.53 2002/07/29 23:46:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include "catalog/pg_constraint.h" #include "catalog/pg_constraint.h"
#include "catalog/pg_database.h" #include "catalog/pg_database.h"
#include "catalog/pg_description.h" #include "catalog/pg_description.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_rewrite.h" #include "catalog/pg_rewrite.h"
#include "catalog/pg_trigger.h" #include "catalog/pg_trigger.h"
...@@ -468,36 +467,28 @@ CommentNamespace(List *qualname, char *comment) ...@@ -468,36 +467,28 @@ CommentNamespace(List *qualname, char *comment)
{ {
Oid oid; Oid oid;
Oid classoid; Oid classoid;
HeapTuple tp;
char *namespace; char *namespace;
if (length(qualname) != 1) if (length(qualname) != 1)
elog(ERROR, "CommentSchema: schema name may not be qualified"); elog(ERROR, "CommentSchema: schema name may not be qualified");
namespace = strVal(lfirst(qualname)); namespace = strVal(lfirst(qualname));
tp = SearchSysCache(NAMESPACENAME, oid = GetSysCacheOid(NAMESPACENAME,
CStringGetDatum(namespace), CStringGetDatum(namespace),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(tp)) if (!OidIsValid(oid))
elog(ERROR, "CommentSchema: Schema \"%s\" could not be found", elog(ERROR, "CommentSchema: Schema \"%s\" could not be found",
namespace); namespace);
/* no TupleDesc here to Assert(...->tdhasoid); */
oid = HeapTupleGetOid(tp);
/* Check object security */ /* Check object security */
if (!pg_namespace_ownercheck(oid, GetUserId())) if (!pg_namespace_ownercheck(oid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, namespace); aclcheck_error(ACLCHECK_NOT_OWNER, namespace);
/* pg_namespace doesn't have a hard-coded OID, so must look it up */ /* pg_namespace doesn't have a hard-coded OID, so must look it up */
classoid = get_relname_relid(NamespaceRelationName, PG_CATALOG_NAMESPACE); classoid = get_system_catalog_relid(NamespaceRelationName);
Assert(OidIsValid(classoid));
/* Call CreateComments() to create/drop the comments */ /* Call CreateComments() to create/drop the comments */
CreateComments(oid, classoid, 0, comment); CreateComments(oid, classoid, 0, comment);
/* Cleanup */
ReleaseSysCache(tp);
} }
/* /*
...@@ -607,8 +598,7 @@ CommentRule(List *qualname, char *comment) ...@@ -607,8 +598,7 @@ CommentRule(List *qualname, char *comment)
aclcheck_error(aclcheck, rulename); aclcheck_error(aclcheck, rulename);
/* pg_rewrite doesn't have a hard-coded OID, so must look it up */ /* pg_rewrite doesn't have a hard-coded OID, so must look it up */
classoid = get_relname_relid(RewriteRelationName, PG_CATALOG_NAMESPACE); classoid = get_system_catalog_relid(RewriteRelationName);
Assert(OidIsValid(classoid));
/* Call CreateComments() to create/drop the comments */ /* Call CreateComments() to create/drop the comments */
...@@ -740,8 +730,7 @@ CommentOperator(List *opername, List *arguments, char *comment) ...@@ -740,8 +730,7 @@ CommentOperator(List *opername, List *arguments, char *comment)
aclcheck_error(ACLCHECK_NOT_OWNER, NameListToString(opername)); aclcheck_error(ACLCHECK_NOT_OWNER, NameListToString(opername));
/* pg_operator doesn't have a hard-coded OID, so must look it up */ /* pg_operator doesn't have a hard-coded OID, so must look it up */
classoid = get_relname_relid(OperatorRelationName, PG_CATALOG_NAMESPACE); classoid = get_system_catalog_relid(OperatorRelationName);
Assert(OidIsValid(classoid));
/* Call CreateComments() to create/drop the comments */ /* Call CreateComments() to create/drop the comments */
CreateComments(oid, classoid, 0, comment); CreateComments(oid, classoid, 0, comment);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.78 2002/07/20 05:16:57 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.79 2002/07/29 23:46:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -410,9 +410,8 @@ static Oid ...@@ -410,9 +410,8 @@ static Oid
GetAttrOpClass(IndexElem *attribute, Oid attrType, GetAttrOpClass(IndexElem *attribute, Oid attrType,
char *accessMethodName, Oid accessMethodId) char *accessMethodName, Oid accessMethodId)
{ {
char *catalogname; char *schemaname;
char *schemaname = NULL; char *opcname;
char *opcname = NULL;
HeapTuple tuple; HeapTuple tuple;
Oid opClassId, Oid opClassId,
opInputType; opInputType;
...@@ -434,42 +433,14 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType, ...@@ -434,42 +433,14 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
*/ */
/* deconstruct the name list */ /* deconstruct the name list */
switch (length(attribute->opclass)) DeconstructQualifiedName(attribute->opclass, &schemaname, &opcname);
{
case 1:
opcname = strVal(lfirst(attribute->opclass));
break;
case 2:
schemaname = strVal(lfirst(attribute->opclass));
opcname = strVal(lsecond(attribute->opclass));
break;
case 3:
catalogname = strVal(lfirst(attribute->opclass));
schemaname = strVal(lsecond(attribute->opclass));
opcname = strVal(lfirst(lnext(lnext(attribute->opclass))));
/*
* 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 opclass name (too many dotted names): %s",
NameListToString(attribute->opclass));
break;
}
if (schemaname) if (schemaname)
{ {
/* Look in specific schema only */ /* Look in specific schema only */
Oid namespaceId; Oid namespaceId;
namespaceId = GetSysCacheOid(NAMESPACENAME, namespaceId = LookupExplicitNamespace(schemaname);
CStringGetDatum(schemaname),
0, 0, 0);
if (!OidIsValid(namespaceId))
elog(ERROR, "Namespace \"%s\" does not exist",
schemaname);
tuple = SearchSysCache(CLAAMNAMENSP, tuple = SearchSysCache(CLAAMNAMENSP,
ObjectIdGetDatum(accessMethodId), ObjectIdGetDatum(accessMethodId),
PointerGetDatum(opcname), PointerGetDatum(opcname),
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/opclasscmds.c,v 1.1 2002/07/29 22:14:10 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/opclasscmds.c,v 1.2 2002/07/29 23:46:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -467,10 +467,9 @@ storeProcedures(Oid opclassoid, int numProcs, Oid *procedures) ...@@ -467,10 +467,9 @@ storeProcedures(Oid opclassoid, int numProcs, Oid *procedures)
void void
RemoveOpClass(RemoveOpClassStmt *stmt) RemoveOpClass(RemoveOpClassStmt *stmt)
{ {
Oid amID, opcID; Oid amID, opcID;
char *catalogname; char *schemaname;
char *schemaname = NULL; char *opcname;
char *opcname = NULL;
HeapTuple tuple; HeapTuple tuple;
ObjectAddress object; ObjectAddress object;
...@@ -489,42 +488,14 @@ RemoveOpClass(RemoveOpClassStmt *stmt) ...@@ -489,42 +488,14 @@ RemoveOpClass(RemoveOpClassStmt *stmt)
*/ */
/* deconstruct the name list */ /* deconstruct the name list */
switch (length(stmt->opclassname)) DeconstructQualifiedName(stmt->opclassname, &schemaname, &opcname);
{
case 1:
opcname = strVal(lfirst(stmt->opclassname));
break;
case 2:
schemaname = strVal(lfirst(stmt->opclassname));
opcname = strVal(lsecond(stmt->opclassname));
break;
case 3:
catalogname = strVal(lfirst(stmt->opclassname));
schemaname = strVal(lsecond(stmt->opclassname));
opcname = strVal(lfirst(lnext(lnext(stmt->opclassname))));
/*
* 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 opclass name (too many dotted names): %s",
NameListToString(stmt->opclassname));
break;
}
if (schemaname) if (schemaname)
{ {
/* Look in specific schema only */ /* Look in specific schema only */
Oid namespaceId; Oid namespaceId;
namespaceId = GetSysCacheOid(NAMESPACENAME, namespaceId = LookupExplicitNamespace(schemaname);
CStringGetDatum(schemaname),
0, 0, 0);
if (!OidIsValid(namespaceId))
elog(ERROR, "Namespace \"%s\" does not exist",
schemaname);
tuple = SearchSysCache(CLAAMNAMENSP, tuple = SearchSysCache(CLAAMNAMENSP,
ObjectIdGetDatum(amID), ObjectIdGetDatum(amID),
PointerGetDatum(opcname), PointerGetDatum(opcname),
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.45 2002/07/20 05:16:58 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.46 2002/07/29 23:46:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -99,35 +99,11 @@ LookupTypeName(const TypeName *typename) ...@@ -99,35 +99,11 @@ LookupTypeName(const TypeName *typename)
else else
{ {
/* Normal reference to a type name */ /* Normal reference to a type name */
char *catalogname; char *schemaname;
char *schemaname = NULL; char *typname;
char *typname = NULL;
/* deconstruct the name list */ /* deconstruct the name list */
switch (length(typename->names)) DeconstructQualifiedName(typename->names, &schemaname, &typname);
{
case 1:
typname = strVal(lfirst(typename->names));
break;
case 2:
schemaname = strVal(lfirst(typename->names));
typname = strVal(lsecond(typename->names));
break;
case 3:
catalogname = strVal(lfirst(typename->names));
schemaname = strVal(lsecond(typename->names));
typname = strVal(lfirst(lnext(lnext(typename->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 type name (too many dotted names): %s",
NameListToString(typename->names));
break;
}
/* If an array reference, look up the array type instead */ /* If an array reference, look up the array type instead */
if (typename->arrayBounds != NIL) if (typename->arrayBounds != NIL)
...@@ -138,12 +114,7 @@ LookupTypeName(const TypeName *typename) ...@@ -138,12 +114,7 @@ LookupTypeName(const TypeName *typename)
/* Look in specific schema only */ /* Look in specific schema only */
Oid namespaceId; Oid namespaceId;
namespaceId = GetSysCacheOid(NAMESPACENAME, namespaceId = LookupExplicitNamespace(schemaname);
CStringGetDatum(schemaname),
0, 0, 0);
if (!OidIsValid(namespaceId))
elog(ERROR, "Namespace \"%s\" does not exist",
schemaname);
restype = GetSysCacheOid(TYPENAMENSP, restype = GetSysCacheOid(TYPENAMENSP,
PointerGetDatum(typname), PointerGetDatum(typname),
ObjectIdGetDatum(namespaceId), ObjectIdGetDatum(namespaceId),
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: namespace.h,v 1.16 2002/07/16 06:58:13 ishii Exp $ * $Id: namespace.h,v 1.17 2002/07/29 23:46:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -66,6 +66,11 @@ extern OpclassCandidateList OpclassGetCandidates(Oid amid); ...@@ -66,6 +66,11 @@ extern OpclassCandidateList OpclassGetCandidates(Oid amid);
extern Oid OpclassnameGetOpcid(Oid amid, const char *opcname); extern Oid OpclassnameGetOpcid(Oid amid, const char *opcname);
extern bool OpclassIsVisible(Oid opcid); extern bool OpclassIsVisible(Oid opcid);
extern void DeconstructQualifiedName(List *names,
char **nspname_p,
char **objname_p);
extern Oid LookupExplicitNamespace(char *nspname);
extern Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p); extern Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p);
extern RangeVar *makeRangeVarFromNameList(List *names); extern RangeVar *makeRangeVarFromNameList(List *names);
extern char *NameListToString(List *names); extern char *NameListToString(List *names);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment