diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index 80ce60f8ab24643641d88fe71c03e3c8f5f4e99b..5c521da2a42c5dcf570d132f45b537f724948b01 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -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.16 2002/04/30 01:26:25 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.17 2002/05/01 23:06:41 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -31,6 +31,7 @@ #include "catalog/pg_operator.h" #include "catalog/pg_proc.h" #include "catalog/pg_shadow.h" +#include "catalog/pg_type.h" #include "lib/stringinfo.h" #include "miscadmin.h" #include "nodes/makefuncs.h" @@ -296,6 +297,56 @@ RelnameGetRelid(const char *relname) return InvalidOid; } +/* + * RelationIsVisible + * Determine whether a relation (identified by OID) is visible in the + * current search path. Visible means "would be found by searching + * for the unqualified relation name". + */ +bool +RelationIsVisible(Oid relid) +{ + HeapTuple reltup; + Form_pg_class relform; + Oid relnamespace; + bool visible; + + recomputeNamespacePath(); + + reltup = SearchSysCache(RELOID, + ObjectIdGetDatum(relid), + 0, 0, 0); + if (!HeapTupleIsValid(reltup)) + elog(ERROR, "Cache lookup failed for relation %u", relid); + relform = (Form_pg_class) GETSTRUCT(reltup); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. + */ + relnamespace = relform->relnamespace; + if (relnamespace != myTempNamespace && + relnamespace != PG_CATALOG_NAMESPACE && + !intMember(relnamespace, namespaceSearchPath)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another relation of the same name earlier in the path. + * So we must do a slow check to see if this rel would be found by + * RelnameGetRelid. + */ + char *relname = NameStr(relform->relname); + + visible = (RelnameGetRelid(relname) == relid); + } + + ReleaseSysCache(reltup); + + return visible; +} + + /* * TypenameGetTypid * Try to resolve an unqualified datatype name. @@ -346,55 +397,54 @@ TypenameGetTypid(const char *typname) } /* - * OpclassnameGetOpcid - * Try to resolve an unqualified index opclass name. - * Returns OID if opclass found in search path, else InvalidOid. - * - * This is essentially the same as TypenameGetTypid, but we have to have - * an extra argument for the index AM OID. + * TypeIsVisible + * Determine whether a type (identified by OID) is visible in the + * current search path. Visible means "would be found by searching + * for the unqualified type name". */ -Oid -OpclassnameGetOpcid(Oid amid, const char *opcname) +bool +TypeIsVisible(Oid typid) { - Oid opcid; - List *lptr; + HeapTuple typtup; + Form_pg_type typform; + Oid typnamespace; + bool visible; recomputeNamespacePath(); - /* - * If system namespace is not in path, implicitly search it before path - */ - if (!pathContainsSystemNamespace) - { - opcid = GetSysCacheOid(CLAAMNAMENSP, - ObjectIdGetDatum(amid), - PointerGetDatum(opcname), - ObjectIdGetDatum(PG_CATALOG_NAMESPACE), - 0); - if (OidIsValid(opcid)) - return opcid; - } + typtup = SearchSysCache(TYPEOID, + ObjectIdGetDatum(typid), + 0, 0, 0); + if (!HeapTupleIsValid(typtup)) + elog(ERROR, "Cache lookup failed for type %u", typid); + typform = (Form_pg_type) GETSTRUCT(typtup); /* - * Else search the path + * Quick check: if it ain't in the path at all, it ain't visible. */ - foreach(lptr, namespaceSearchPath) + typnamespace = typform->typnamespace; + if (typnamespace != PG_CATALOG_NAMESPACE && + !intMember(typnamespace, namespaceSearchPath)) + visible = false; + else { - Oid namespaceId = (Oid) lfirsti(lptr); + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another type of the same name earlier in the path. + * So we must do a slow check to see if this type would be found by + * TypenameGetTypid. + */ + char *typname = NameStr(typform->typname); - opcid = GetSysCacheOid(CLAAMNAMENSP, - ObjectIdGetDatum(amid), - PointerGetDatum(opcname), - ObjectIdGetDatum(namespaceId), - 0); - if (OidIsValid(opcid)) - return opcid; + visible = (TypenameGetTypid(typname) == typid); } - /* Not found in path */ - return InvalidOid; + ReleaseSysCache(typtup); + + return visible; } + /* * FuncnameGetCandidates * Given a possibly-qualified function name and argument count, @@ -582,6 +632,70 @@ FuncnameGetCandidates(List *names, int nargs) return resultList; } +/* + * FunctionIsVisible + * Determine whether a function (identified by OID) is visible in the + * current search path. Visible means "would be found by searching + * for the unqualified function name with exact argument matches". + */ +bool +FunctionIsVisible(Oid funcid) +{ + HeapTuple proctup; + Form_pg_proc procform; + Oid pronamespace; + bool visible; + + recomputeNamespacePath(); + + proctup = SearchSysCache(PROCOID, + ObjectIdGetDatum(funcid), + 0, 0, 0); + if (!HeapTupleIsValid(proctup)) + elog(ERROR, "Cache lookup failed for procedure %u", funcid); + procform = (Form_pg_proc) GETSTRUCT(proctup); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. + */ + pronamespace = procform->pronamespace; + if (pronamespace != PG_CATALOG_NAMESPACE && + !intMember(pronamespace, namespaceSearchPath)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another proc of the same name and arguments earlier + * in the path. So we must do a slow check to see if this is the + * same proc that would be found by FuncnameGetCandidates. + */ + char *proname = NameStr(procform->proname); + int nargs = procform->pronargs; + FuncCandidateList clist; + + visible = false; + + clist = FuncnameGetCandidates(makeList1(makeString(proname)), nargs); + + for (; clist; clist = clist->next) + { + if (memcmp(clist->args, procform->proargtypes, + nargs * sizeof(Oid)) == 0) + { + /* Found the expected entry; is it the right proc? */ + visible = (clist->oid == funcid); + break; + } + } + } + + ReleaseSysCache(proctup); + + return visible; +} + + /* * OpernameGetCandidates * Given a possibly-qualified operator name and operator kind, @@ -765,6 +879,70 @@ OpernameGetCandidates(List *names, char oprkind) return resultList; } +/* + * OperatorIsVisible + * Determine whether an operator (identified by OID) is visible in the + * current search path. Visible means "would be found by searching + * for the unqualified operator name with exact argument matches". + */ +bool +OperatorIsVisible(Oid oprid) +{ + HeapTuple oprtup; + Form_pg_operator oprform; + Oid oprnamespace; + bool visible; + + recomputeNamespacePath(); + + oprtup = SearchSysCache(OPEROID, + ObjectIdGetDatum(oprid), + 0, 0, 0); + if (!HeapTupleIsValid(oprtup)) + elog(ERROR, "Cache lookup failed for operator %u", oprid); + oprform = (Form_pg_operator) GETSTRUCT(oprtup); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. + */ + oprnamespace = oprform->oprnamespace; + if (oprnamespace != PG_CATALOG_NAMESPACE && + !intMember(oprnamespace, namespaceSearchPath)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another operator of the same name and arguments earlier + * in the path. So we must do a slow check to see if this is the + * same operator that would be found by OpernameGetCandidates. + */ + char *oprname = NameStr(oprform->oprname); + FuncCandidateList clist; + + visible = false; + + clist = OpernameGetCandidates(makeList1(makeString(oprname)), + oprform->oprkind); + + for (; clist; clist = clist->next) + { + if (clist->args[0] == oprform->oprleft && + clist->args[1] == oprform->oprright) + { + /* Found the expected entry; is it the right op? */ + visible = (clist->oid == oprid); + break; + } + } + } + + ReleaseSysCache(oprtup); + + return visible; +} + + /* * OpclassGetCandidates * Given an index access method OID, retrieve a list of all the @@ -883,6 +1061,104 @@ OpclassGetCandidates(Oid amid) return resultList; } +/* + * OpclassnameGetOpcid + * Try to resolve an unqualified index opclass name. + * Returns OID if opclass found in search path, else InvalidOid. + * + * This is essentially the same as TypenameGetTypid, but we have to have + * an extra argument for the index AM OID. + */ +Oid +OpclassnameGetOpcid(Oid amid, const char *opcname) +{ + Oid opcid; + List *lptr; + + recomputeNamespacePath(); + + /* + * If system namespace is not in path, implicitly search it before path + */ + if (!pathContainsSystemNamespace) + { + opcid = GetSysCacheOid(CLAAMNAMENSP, + ObjectIdGetDatum(amid), + PointerGetDatum(opcname), + ObjectIdGetDatum(PG_CATALOG_NAMESPACE), + 0); + if (OidIsValid(opcid)) + return opcid; + } + + /* + * Else search the path + */ + foreach(lptr, namespaceSearchPath) + { + Oid namespaceId = (Oid) lfirsti(lptr); + + opcid = GetSysCacheOid(CLAAMNAMENSP, + ObjectIdGetDatum(amid), + PointerGetDatum(opcname), + ObjectIdGetDatum(namespaceId), + 0); + if (OidIsValid(opcid)) + return opcid; + } + + /* Not found in path */ + return InvalidOid; +} + +/* + * OpclassIsVisible + * Determine whether an opclass (identified by OID) is visible in the + * current search path. Visible means "would be found by searching + * for the unqualified opclass name". + */ +bool +OpclassIsVisible(Oid opcid) +{ + HeapTuple opctup; + Form_pg_opclass opcform; + Oid opcnamespace; + bool visible; + + recomputeNamespacePath(); + + opctup = SearchSysCache(CLAOID, + ObjectIdGetDatum(opcid), + 0, 0, 0); + if (!HeapTupleIsValid(opctup)) + elog(ERROR, "Cache lookup failed for opclass %u", opcid); + opcform = (Form_pg_opclass) GETSTRUCT(opctup); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. + */ + opcnamespace = opcform->opcnamespace; + if (opcnamespace != PG_CATALOG_NAMESPACE && + !intMember(opcnamespace, namespaceSearchPath)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another opclass of the same name earlier in the path. + * So we must do a slow check to see if this opclass would be found by + * OpclassnameGetOpcid. + */ + char *opcname = NameStr(opcform->opcname); + + visible = (OpclassnameGetOpcid(opcform->opcamid, opcname) == opcid); + } + + ReleaseSysCache(opctup); + + return visible; +} + /* * QualifiedNameGetCreationNamespace @@ -1016,6 +1292,7 @@ isTempNamespace(Oid namespaceId) return false; } + /* * recomputeNamespacePath - recompute path derived variables if needed. */ @@ -1453,6 +1730,7 @@ RemoveTempRelationsCallback(void) } } + /* * Routines for handling the GUC variable 'search_path'. */ diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c index c85d7ea08842cfab8c9a13d6133a43024eaf77b6..62b80d23c641a2d9843e92479dee4573b643e059 100644 --- a/src/backend/utils/adt/format_type.c +++ b/src/backend/utils/adt/format_type.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.28 2002/03/20 19:44:40 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.29 2002/05/01 23:06:41 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,11 +17,13 @@ #include <ctype.h> -#include "fmgr.h" +#include "catalog/namespace.h" #include "catalog/pg_type.h" +#include "fmgr.h" #include "utils/builtins.h" #include "utils/datetime.h" #include "utils/numeric.h" +#include "utils/lsyscache.h" #include "utils/syscache.h" #ifdef MULTIBYTE #include "mb/pg_wchar.h" @@ -47,7 +49,7 @@ __attribute__((format(printf, 2, 3))); * pg_attribute.atttypmod. This function will get the type name and * format it and the modifier to canonical SQL format, if the type is * a standard type. Otherwise you just get pg_type.typname back, - * double quoted if it contains funny characters. + * double quoted if it contains funny characters or matches a keyword. * * If typemod is NULL then we are formatting a type name in a context where * no typemod is available, eg a function argument or result type. This @@ -121,11 +123,9 @@ format_type_internal(Oid type_oid, int32 typemod, { bool with_typemod = typemod_given && (typemod >= 0); HeapTuple tuple; + Form_pg_type typeform; Oid array_base_type; - int16 typlen; - char typtype; bool is_array; - char *name; char *buf; if (type_oid == InvalidOid && allow_invalid) @@ -142,17 +142,18 @@ format_type_internal(Oid type_oid, int32 typemod, elog(ERROR, "could not locate data type with oid %u in catalog", type_oid); } + typeform = (Form_pg_type) GETSTRUCT(tuple); /* * Check if it's an array (and not a domain --- we don't want to show * the substructure of a domain type). Fixed-length array types such * as "name" shouldn't get deconstructed either. */ - array_base_type = ((Form_pg_type) GETSTRUCT(tuple))->typelem; - typlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen; - typtype = ((Form_pg_type) GETSTRUCT(tuple))->typtype; + array_base_type = typeform->typelem; - if (array_base_type != InvalidOid && typlen < 0 && typtype != 'd') + if (array_base_type != InvalidOid && + typeform->typlen < 0 && + typeform->typtype != 'd') { /* Switch our attention to the array element type */ ReleaseSysCache(tuple); @@ -167,12 +168,26 @@ format_type_internal(Oid type_oid, int32 typemod, elog(ERROR, "could not locate data type with oid %u in catalog", type_oid); } - is_array = true; + typeform = (Form_pg_type) GETSTRUCT(tuple); type_oid = array_base_type; + is_array = true; } else is_array = false; + /* + * See if we want to special-case the output for certain built-in types. + * Note that these special cases should all correspond to special + * productions in gram.y, to ensure that the type name will be taken as + * a system type, not a user type of the same name. + * + * If we do not provide a special-case output here, the type name will + * be handled the same way as a user type name --- in particular, it + * will be double-quoted if it matches any lexer keyword. This behavior + * is essential for some cases, such as types "bit" and "char". + */ + buf = NULL; /* flag for no special case */ + switch (type_oid) { case BITOID: @@ -186,7 +201,6 @@ format_type_internal(Oid type_oid, int32 typemod, * BIT(1) per SQL spec. Report it as the quoted typename * so that parser will not assign a bogus typmod. */ - buf = pstrdup("\"bit\""); } else buf = pstrdup("bit"); @@ -207,20 +221,11 @@ format_type_internal(Oid type_oid, int32 typemod, * which means CHARACTER(1) per SQL spec. Report it as * bpchar so that parser will not assign a bogus typmod. */ - buf = pstrdup("bpchar"); } else buf = pstrdup("character"); break; - case CHAROID: - /* - * This char type is the single-byte version. You have to - * double-quote it to get at it in the parser. - */ - buf = pstrdup("\"char\""); - break; - case FLOAT4OID: buf = pstrdup("real"); break; @@ -365,19 +370,27 @@ format_type_internal(Oid type_oid, int32 typemod, else buf = pstrdup("character varying"); break; + } - default: - name = NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname); - /* - * Double-quote the name if it's not a standard identifier. - * Note this is *necessary* for ruleutils.c's use. - */ - if (strspn(name, "abcdefghijklmnopqrstuvwxyz0123456789_") != strlen(name) - || isdigit((unsigned char) name[0])) - buf = psnprintf(strlen(name) + 3, "\"%s\"", name); - else - buf = pstrdup(name); - break; + if (buf == NULL) + { + /* + * Default handling: report the name as it appears in the catalog. + * Here, we must qualify the name if it is not visible in the search + * path, and we must double-quote it if it's not a standard identifier + * or if it matches any keyword. + */ + char *nspname; + char *typname; + + if (TypeIsVisible(type_oid)) + nspname = NULL; + else + nspname = get_namespace_name(typeform->typnamespace); + + typname = NameStr(typeform->typname); + + buf = quote_qualified_identifier(nspname, typname); } if (is_array) diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index 89be1bac96b3e70ecc84c1cf6c3ea78c3cd09eb4..ac5a7fc84d1e01d8afcf77c3116cbc0ba9f7db90 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -13,7 +13,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.66 2002/04/25 02:56:55 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.67 2002/05/01 23:06:41 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -307,31 +307,21 @@ regprocedureout(PG_FUNCTION_ARGS) int nargs = procform->pronargs; int i; char *nspname; - FuncCandidateList clist; StringInfoData buf; /* XXX no support here for bootstrap mode */ + initStringInfo(&buf); + /* * Would this proc be found (given the right args) by regprocedurein? * If not, we need to qualify it. */ - clist = FuncnameGetCandidates(makeList1(makeString(proname)), nargs); - - for (; clist; clist = clist->next) - { - if (memcmp(clist->args, procform->proargtypes, - nargs * sizeof(Oid)) == 0) - break; - } - - if (clist != NULL && clist->oid == proid) + if (FunctionIsVisible(proid)) nspname = NULL; else nspname = get_namespace_name(procform->pronamespace); - initStringInfo(&buf); - appendStringInfo(&buf, "%s(", quote_qualified_identifier(nspname, proname)); for (i = 0; i < nargs; i++) @@ -632,28 +622,17 @@ regoperatorout(PG_FUNCTION_ARGS) Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup); char *oprname = NameStr(operform->oprname); char *nspname; - FuncCandidateList clist; StringInfoData buf; /* XXX no support here for bootstrap mode */ + initStringInfo(&buf); + /* * Would this oper be found (given the right args) by regoperatorin? * If not, we need to qualify it. */ - clist = OpernameGetCandidates(makeList1(makeString(oprname)), - operform->oprkind); - - for (; clist; clist = clist->next) - { - if (clist->args[0] == operform->oprleft && - clist->args[1] == operform->oprright) - break; - } - - initStringInfo(&buf); - - if (clist == NULL || clist->oid != oprid) + if (!OperatorIsVisible(oprid)) { nspname = get_namespace_name(operform->oprnamespace); appendStringInfo(&buf, "%s.", @@ -815,7 +794,7 @@ regclassout(PG_FUNCTION_ARGS) * Would this class be found by regclassin? * If not, qualify it. */ - if (RelnameGetRelid(classname) == classid) + if (RelationIsVisible(classid)) nspname = NULL; else nspname = get_namespace_name(classform->relnamespace); @@ -947,7 +926,6 @@ regtypeout(PG_FUNCTION_ARGS) if (HeapTupleIsValid(typetup)) { Form_pg_type typeform = (Form_pg_type) GETSTRUCT(typetup); - char *typname = NameStr(typeform->typname); /* * In bootstrap mode, skip the fancy namespace stuff and just @@ -956,24 +934,13 @@ regtypeout(PG_FUNCTION_ARGS) */ if (IsBootstrapProcessingMode()) { + char *typname = NameStr(typeform->typname); + result = pstrdup(typname); } else { - char *nspname; - - /* - * Would this type be found by regtypein? - * If not, qualify it. - * - * XXX shouldn't we use format_type instead? - */ - if (TypenameGetTypid(typname) == typid) - nspname = NULL; - else - nspname = get_namespace_name(typeform->typnamespace); - - result = quote_qualified_identifier(nspname, typname); + result = format_type_be(typid); } ReleaseSysCache(typetup); diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h index c285977599d99d5f022bfb9e91cac39465eaec6e..545b1a1383aedcb189764d45292b3ec6f627f414 100644 --- a/src/include/catalog/namespace.h +++ b/src/include/catalog/namespace.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: namespace.h,v 1.11 2002/04/26 01:24:08 tgl Exp $ + * $Id: namespace.h,v 1.12 2002/05/01 23:06:41 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -49,25 +49,25 @@ typedef struct _OpclassCandidateList extern Oid RangeVarGetRelid(const RangeVar *relation, bool failOK); - extern Oid RangeVarGetCreationNamespace(const RangeVar *newRelation); - extern Oid RelnameGetRelid(const char *relname); +extern bool RelationIsVisible(Oid relid); extern Oid TypenameGetTypid(const char *typname); - -extern Oid OpclassnameGetOpcid(Oid amid, const char *opcname); +extern bool TypeIsVisible(Oid typid); extern FuncCandidateList FuncnameGetCandidates(List *names, int nargs); +extern bool FunctionIsVisible(Oid funcid); extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind); +extern bool OperatorIsVisible(Oid oprid); extern OpclassCandidateList OpclassGetCandidates(Oid amid); +extern Oid OpclassnameGetOpcid(Oid amid, const char *opcname); +extern bool OpclassIsVisible(Oid opcid); extern Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p); - extern RangeVar *makeRangeVarFromNameList(List *names); - extern char *NameListToString(List *names); extern bool isTempNamespace(Oid namespaceId);