Centralize code for interpreting schema references, which had gotten
authorTom Lane
Mon, 29 Jul 2002 23:46:35 +0000 (23:46 +0000)
committerTom Lane
Mon, 29 Jul 2002 23:46:35 +0000 (23:46 +0000)
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.

src/backend/catalog/namespace.c
src/backend/commands/comment.c
src/backend/commands/indexcmds.c
src/backend/commands/opclasscmds.c
src/backend/parser/parse_type.c
src/include/catalog/namespace.h

index f02789fa807295840902fa48e0a5f0b3242b07d6..0425e44c1cd8653bb0cbd037d90047b99eae7f55 100644 (file)
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * 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)
    if (relation->schemaname)
    {
        /* use exact schema given */
-       AclResult   aclresult;
-
-       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);
-
+       namespaceId = LookupExplicitNamespace(relation->schemaname);
        relId = get_relname_relid(relation->relname, namespaceId);
    }
    else
@@ -239,6 +228,7 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation)
        if (!OidIsValid(namespaceId))
            elog(ERROR, "Namespace \"%s\" does not exist",
                 newRelation->schemaname);
+       /* we do not check for USAGE rights here! */
    }
    else
    {
@@ -431,53 +421,19 @@ FuncCandidateList
 FuncnameGetCandidates(List *names, int nargs)
 {
    FuncCandidateList resultList = NULL;
-   char       *catalogname;
-   char       *schemaname = NULL;
-   char       *funcname = NULL;
+   char       *schemaname;
+   char       *funcname;
    Oid         namespaceId;
    CatCList   *catlist;
    int         i;
 
    /* deconstruct the name list */
-   switch (length(names))
-   {
-       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;
-   }
+   DeconstructQualifiedName(names, &schemaname, &funcname);
 
    if (schemaname)
    {
        /* use exact schema given */
-       AclResult   aclresult;
-
-       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);
+       namespaceId = LookupExplicitNamespace(schemaname);
    }
    else
    {
@@ -684,53 +640,19 @@ FuncCandidateList
 OpernameGetCandidates(List *names, char oprkind)
 {
    FuncCandidateList resultList = NULL;
-   char       *catalogname;
-   char       *schemaname = NULL;
-   char       *opername = NULL;
+   char       *schemaname;
+   char       *opername;
    Oid         namespaceId;
    CatCList   *catlist;
    int         i;
 
    /* deconstruct the name list */
-   switch (length(names))
-   {
-       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;
-   }
+   DeconstructQualifiedName(names, &schemaname, &opername);
 
    if (schemaname)
    {
        /* use exact schema given */
-       AclResult   aclresult;
-
-       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);
+       namespaceId = LookupExplicitNamespace(schemaname);
    }
    else
    {
@@ -1105,25 +1027,22 @@ OpclassIsVisible(Oid opcid)
    return visible;
 }
 
-
 /*
- * 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).
+ * DeconstructQualifiedName
+ *     Given a possibly-qualified name expressed as a list of String nodes,
+ *     extract the schema name and object name.
  *
- * This is *not* used for tables.  Hence, the TEMP table namespace is
- * never selected as the creation target.
+ * *nspname_p is set to NULL if there is no explicit schema name.
  */
-Oid
-QualifiedNameGetCreationNamespace(List *names, char **objname_p)
+void
+DeconstructQualifiedName(List *names,
+                        char **nspname_p,
+                        char **objname_p)
 {
    char       *catalogname;
    char       *schemaname = NULL;
    char       *objname = NULL;
-   Oid         namespaceId;
 
-   /* deconstruct the name list */
    switch (length(names))
    {
        case 1:
@@ -1149,6 +1068,55 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p)
            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)
    {
        /* use exact schema given */
@@ -1158,6 +1126,7 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p)
        if (!OidIsValid(namespaceId))
            elog(ERROR, "Namespace \"%s\" does not exist",
                 schemaname);
+       /* we do not check for USAGE rights here! */
    }
    else
    {
index 83b8af7e6bfd1d0fd1aa464f52df445d6f0ffd7e..c5dee8f8af9a65651b5bcd075a7993894e37cf65 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright (c) 1996-2001, PostgreSQL Global Development Group
  *
  * 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 @@
 #include "catalog/pg_constraint.h"
 #include "catalog/pg_database.h"
 #include "catalog/pg_description.h"
-#include "catalog/pg_namespace.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_rewrite.h"
 #include "catalog/pg_trigger.h"
@@ -468,36 +467,28 @@ CommentNamespace(List *qualname, char *comment)
 {
    Oid         oid;
    Oid         classoid;
-   HeapTuple   tp;
    char       *namespace;
 
    if (length(qualname) != 1)
        elog(ERROR, "CommentSchema: schema name may not be qualified");
    namespace = strVal(lfirst(qualname));
 
-   tp = SearchSysCache(NAMESPACENAME,
-                       CStringGetDatum(namespace),
-                       0, 0, 0);
-   if (!HeapTupleIsValid(tp))
+   oid = GetSysCacheOid(NAMESPACENAME,
+                        CStringGetDatum(namespace),
+                        0, 0, 0);
+   if (!OidIsValid(oid))
        elog(ERROR, "CommentSchema: Schema \"%s\" could not be found",
             namespace);
 
-   /* no TupleDesc here to Assert(...->tdhasoid); */
-   oid = HeapTupleGetOid(tp);
-
    /* Check object security */
    if (!pg_namespace_ownercheck(oid, GetUserId()))
        aclcheck_error(ACLCHECK_NOT_OWNER, namespace);
 
    /* pg_namespace doesn't have a hard-coded OID, so must look it up */
-   classoid = get_relname_relid(NamespaceRelationName, PG_CATALOG_NAMESPACE);
-   Assert(OidIsValid(classoid));
+   classoid = get_system_catalog_relid(NamespaceRelationName);
 
    /* Call CreateComments() to create/drop the comments */
    CreateComments(oid, classoid, 0, comment);
-
-   /* Cleanup */
-   ReleaseSysCache(tp);
 }
 
 /*
@@ -607,8 +598,7 @@ CommentRule(List *qualname, char *comment)
        aclcheck_error(aclcheck, rulename);
 
    /* pg_rewrite doesn't have a hard-coded OID, so must look it up */
-   classoid = get_relname_relid(RewriteRelationName, PG_CATALOG_NAMESPACE);
-   Assert(OidIsValid(classoid));
+   classoid = get_system_catalog_relid(RewriteRelationName);
 
    /* Call CreateComments() to create/drop the comments */
 
@@ -740,8 +730,7 @@ CommentOperator(List *opername, List *arguments, char *comment)
        aclcheck_error(ACLCHECK_NOT_OWNER, NameListToString(opername));
 
    /* pg_operator doesn't have a hard-coded OID, so must look it up */
-   classoid = get_relname_relid(OperatorRelationName, PG_CATALOG_NAMESPACE);
-   Assert(OidIsValid(classoid));
+   classoid = get_system_catalog_relid(OperatorRelationName);
 
    /* Call CreateComments() to create/drop the comments */
    CreateComments(oid, classoid, 0, comment);
index f36bad8ada17fdd7fa6f347dda6fa8a27be76ba4..4049e7435c56a54af4ed4f1e571779b8178d7c66 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
 GetAttrOpClass(IndexElem *attribute, Oid attrType,
               char *accessMethodName, Oid accessMethodId)
 {
-   char       *catalogname;
-   char       *schemaname = NULL;
-   char       *opcname = NULL;
+   char       *schemaname;
+   char       *opcname;
    HeapTuple   tuple;
    Oid         opClassId,
                opInputType;
@@ -434,42 +433,14 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
     */
 
    /* deconstruct the name list */
-   switch (length(attribute->opclass))
-   {
-       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;
-   }
+   DeconstructQualifiedName(attribute->opclass, &schemaname, &opcname);
 
    if (schemaname)
    {
        /* Look in specific schema only */
        Oid     namespaceId;
 
-       namespaceId = GetSysCacheOid(NAMESPACENAME,
-                                    CStringGetDatum(schemaname),
-                                    0, 0, 0);
-       if (!OidIsValid(namespaceId))
-           elog(ERROR, "Namespace \"%s\" does not exist",
-                schemaname);
+       namespaceId = LookupExplicitNamespace(schemaname);
        tuple = SearchSysCache(CLAAMNAMENSP,
                               ObjectIdGetDatum(accessMethodId),
                               PointerGetDatum(opcname),
index fb86c980b986f4229e760fbf39334e6446f8f686..c56b0e1fa84b0b5f7fcb7605dc2d5a0ed3637f03 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * 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)
 void
 RemoveOpClass(RemoveOpClassStmt *stmt)
 {
-   Oid             amID, opcID;
-   char       *catalogname;
-   char       *schemaname = NULL;
-   char       *opcname = NULL;
+   Oid         amID, opcID;
+   char       *schemaname;
+   char       *opcname;
    HeapTuple   tuple;
    ObjectAddress object;
 
@@ -489,42 +488,14 @@ RemoveOpClass(RemoveOpClassStmt *stmt)
     */
 
    /* deconstruct the name list */
-   switch (length(stmt->opclassname))
-   {
-       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;
-   }
+   DeconstructQualifiedName(stmt->opclassname, &schemaname, &opcname);
 
    if (schemaname)
    {
        /* Look in specific schema only */
        Oid     namespaceId;
 
-       namespaceId = GetSysCacheOid(NAMESPACENAME,
-                                    CStringGetDatum(schemaname),
-                                    0, 0, 0);
-       if (!OidIsValid(namespaceId))
-           elog(ERROR, "Namespace \"%s\" does not exist",
-                schemaname);
+       namespaceId = LookupExplicitNamespace(schemaname);
        tuple = SearchSysCache(CLAAMNAMENSP,
                               ObjectIdGetDatum(amID),
                               PointerGetDatum(opcname),
index 7eafe3e7c84bdef8a2b04263b45b7d9b63938474..159428894e47bf886a4a277e07d481f0aeb0366b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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)
    else
    {
        /* Normal reference to a type name */
-       char       *catalogname;
-       char       *schemaname = NULL;
-       char       *typname = NULL;
+       char       *schemaname;
+       char       *typname;
 
        /* deconstruct the name list */
-       switch (length(typename->names))
-       {
-           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;
-       }
+       DeconstructQualifiedName(typename->names, &schemaname, &typname);
 
        /* If an array reference, look up the array type instead */
        if (typename->arrayBounds != NIL)
@@ -138,12 +114,7 @@ LookupTypeName(const TypeName *typename)
            /* Look in specific schema only */
            Oid     namespaceId;
 
-           namespaceId = GetSysCacheOid(NAMESPACENAME,
-                                        CStringGetDatum(schemaname),
-                                        0, 0, 0);
-           if (!OidIsValid(namespaceId))
-               elog(ERROR, "Namespace \"%s\" does not exist",
-                    schemaname);
+           namespaceId = LookupExplicitNamespace(schemaname);
            restype = GetSysCacheOid(TYPENAMENSP,
                                     PointerGetDatum(typname),
                                     ObjectIdGetDatum(namespaceId),
index 5341027c0716d4653831b2bd3f69bfb2e8688157..bd0f176f28a88fb5ce59d3bca19d829a8fbd6b5b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * 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);
 extern Oid OpclassnameGetOpcid(Oid amid, const char *opcname);
 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 RangeVar *makeRangeVarFromNameList(List *names);
 extern char *NameListToString(List *names);