From 0886fc6a5c75b294544263ea979b9cf6195407d9 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Tue, 8 Apr 2014 10:27:56 -0400 Subject: [PATCH] Add new to_reg* functions for error-free OID lookups. These functions won't throw an error if the object doesn't exist, or if (for functions and operators) there's more than one matching object. Yugo Nagata and Nozomi Anzai, reviewed by Amit Khandekar, Marti Raudsepp, Amit Kapila, and me. --- doc/src/sgml/func.sgml | 48 +++++++ src/backend/catalog/namespace.c | 6 +- src/backend/parser/parse_oper.c | 6 +- src/backend/parser/parse_type.c | 29 +++- src/backend/utils/adt/regproc.c | 108 ++++++++++++++- src/include/catalog/catversion.h | 2 +- src/include/catalog/namespace.h | 3 +- src/include/catalog/pg_proc.h | 8 ++ src/include/parser/parse_type.h | 2 +- src/include/utils/builtins.h | 4 + src/pl/plperl/plperl.c | 2 +- src/pl/plpgsql/src/pl_gram.y | 2 +- src/pl/plpython/plpy_spi.c | 2 +- src/pl/tcl/pltcl.c | 2 +- src/test/regress/expected/regproc.out | 188 ++++++++++++++++++++++++++ src/test/regress/parallel_schedule | 2 +- src/test/regress/serial_schedule | 1 + src/test/regress/sql/regproc.sql | 61 +++++++++ 18 files changed, 457 insertions(+), 19 deletions(-) create mode 100644 src/test/regress/expected/regproc.out create mode 100644 src/test/regress/sql/regproc.sql diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 6e2fbda6c2..33e093e2ab 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -15279,6 +15279,22 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); collation for + + to_regclass + + + + to_regproc + + + + to_regoper + + + + to_regtype + + lists functions that extract information from the system catalogs. @@ -15449,6 +15465,26 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); text get the collation of the argument + + to_regclass(rel_name) + regclass + get the oid of the named relation + + + to_regproc(func_name) + regproc + get the oid of the named function + + + to_regoper(operator_name) + regoper + get the oid of the named operator + + + to_regtype(type_name) + regtype + get the oid of the named type + @@ -15614,6 +15650,18 @@ SELECT collation for ('foo' COLLATE "de_DE"); is not of a collatable data type, then an error is raised. + + The to_regclass, to_regproc, + to_regoper and to_regtype + translate relation, function, operator, and type names to objects of + type regclass, regproc, regoper and + regtype, respectively. These functions differ from a cast from + text in that they don't accept a numeric OID, and that they return null + rather than throwing an error if the name is not found (or, for + to_regproc and to_regoper, if + the given name matches multiple objects). + + col_description diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index 6c2a5d2af5..5bf6d289d8 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -1556,7 +1556,7 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright) * will be InvalidOid for a prefix or postfix oprkind. nargs is 2, too. */ FuncCandidateList -OpernameGetCandidates(List *names, char oprkind) +OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok) { FuncCandidateList resultList = NULL; char *resultSpace = NULL; @@ -1573,7 +1573,9 @@ OpernameGetCandidates(List *names, char oprkind) if (schemaname) { /* use exact schema given */ - namespaceId = LookupExplicitNamespace(schemaname, false); + namespaceId = LookupExplicitNamespace(schemaname, missing_schema_ok); + if (missing_schema_ok && !OidIsValid(namespaceId)) + return NULL; } else { diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index 99dbd30d75..a2b712d516 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -407,7 +407,7 @@ oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, FuncCandidateList clist; /* Get binary operators of given name */ - clist = OpernameGetCandidates(opname, 'b'); + clist = OpernameGetCandidates(opname, 'b', false); /* No operators found? Then fail... */ if (clist != NULL) @@ -553,7 +553,7 @@ right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location) FuncCandidateList clist; /* Get postfix operators of given name */ - clist = OpernameGetCandidates(op, 'r'); + clist = OpernameGetCandidates(op, 'r', false); /* No operators found? Then fail... */ if (clist != NULL) @@ -631,7 +631,7 @@ left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location) FuncCandidateList clist; /* Get prefix operators of given name */ - clist = OpernameGetCandidates(op, 'l'); + clist = OpernameGetCandidates(op, 'l', false); /* No operators found? Then fail... */ if (clist != NULL) diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index b329dfb168..b8c10e11c9 100644 --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -706,9 +706,12 @@ pts_error_callback(void *arg) * Given a string that is supposed to be a SQL-compatible type declaration, * such as "int4" or "integer" or "character varying(32)", parse * the string and convert it to a type OID and type modifier. + * If missing_ok is true, InvalidOid is returned rather than raising an error + * when the type name is not found. */ void -parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p) +parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, + bool missing_ok) { StringInfoData buf; List *raw_parsetree_list; @@ -717,6 +720,7 @@ parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p) TypeCast *typecast; TypeName *typeName; ErrorContextCallback ptserrcontext; + Type tup; /* make sure we give useful error for empty input */ if (strspn(str, " \t\n\r\f") == strlen(str)) @@ -782,7 +786,28 @@ parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p) if (typeName->setof) goto fail; - typenameTypeIdAndMod(NULL, typeName, typeid_p, typmod_p); + tup = LookupTypeName(NULL, typeName, typmod_p, missing_ok); + if (tup == NULL) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("type \"%s\" does not exist", + TypeNameToString(typeName)), + parser_errposition(NULL, typeName->location))); + *typeid_p = InvalidOid; + } + else + { + if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("type \"%s\" is only a shell", + TypeNameToString(typeName)), + parser_errposition(NULL, typeName->location))); + *typeid_p = HeapTupleGetOid(tup); + ReleaseSysCache(tup); + } pfree(buf.data); diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index 5d73562a4f..ed2bdbfb09 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -152,6 +152,31 @@ regprocin(PG_FUNCTION_ARGS) PG_RETURN_OID(result); } +/* + * to_regproc - converts "proname" to proc OID + * + * If the name is not found, we return NULL. + */ +Datum +to_regproc(PG_FUNCTION_ARGS) +{ + char *pro_name = PG_GETARG_CSTRING(0); + List *names; + FuncCandidateList clist; + + /* + * Parse the name into components and see if it matches any pg_proc entries + * in the current search path. + */ + names = stringToQualifiedNameList(pro_name); + clist = FuncnameGetCandidates(names, -1, NIL, false, false, true); + + if (clist == NULL || clist->next != NULL) + PG_RETURN_NULL(); + + PG_RETURN_OID(clist->oid); +} + /* * regprocout - converts proc OID to "pro_name" */ @@ -502,7 +527,7 @@ regoperin(PG_FUNCTION_ARGS) * pg_operator entries in the current search path. */ names = stringToQualifiedNameList(opr_name_or_oid); - clist = OpernameGetCandidates(names, '\0'); + clist = OpernameGetCandidates(names, '\0', false); if (clist == NULL) ereport(ERROR, @@ -519,6 +544,31 @@ regoperin(PG_FUNCTION_ARGS) PG_RETURN_OID(result); } +/* + * to_regoper - converts "oprname" to operator OID + * + * If the name is not found, we return NULL. + */ +Datum +to_regoper(PG_FUNCTION_ARGS) +{ + char *opr_name = PG_GETARG_CSTRING(0); + List *names; + FuncCandidateList clist; + + /* + * Parse the name into components and see if it matches any pg_operator + * entries in the current search path. + */ + names = stringToQualifiedNameList(opr_name); + clist = OpernameGetCandidates(names, '\0', true); + + if (clist == NULL || clist->next != NULL) + PG_RETURN_NULL(); + + PG_RETURN_OID(clist->oid); +} + /* * regoperout - converts operator OID to "opr_name" */ @@ -558,7 +608,7 @@ regoperout(PG_FUNCTION_ARGS) * qualify it. */ clist = OpernameGetCandidates(list_make1(makeString(oprname)), - '\0'); + '\0', false); if (clist != NULL && clist->next == NULL && clist->oid == oprid) result = pstrdup(oprname); @@ -872,6 +922,33 @@ regclassin(PG_FUNCTION_ARGS) PG_RETURN_OID(result); } +/* + * to_regclass - converts "classname" to class OID + * + * If the name is not found, we return NULL. + */ +Datum +to_regclass(PG_FUNCTION_ARGS) +{ + char *class_name = PG_GETARG_CSTRING(0); + Oid result; + List *names; + + /* + * Parse the name into components and see if it matches any pg_class entries + * in the current search path. + */ + names = stringToQualifiedNameList(class_name); + + /* We might not even have permissions on this relation; don't lock it. */ + result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true); + + if (OidIsValid(result)) + PG_RETURN_OID(result); + else + PG_RETURN_NULL(); +} + /* * regclassout - converts class OID to "class_name" */ @@ -1028,11 +1105,34 @@ regtypein(PG_FUNCTION_ARGS) * Normal case: invoke the full parser to deal with special cases such as * array syntax. */ - parseTypeString(typ_name_or_oid, &result, &typmod); + parseTypeString(typ_name_or_oid, &result, &typmod, false); PG_RETURN_OID(result); } +/* + * to_regtype - converts "typename" to type OID + * + * If the name is not found, we return NULL. + */ +Datum +to_regtype(PG_FUNCTION_ARGS) +{ + char *typ_name = PG_GETARG_CSTRING(0); + Oid result; + int32 typmod; + + /* + * Invoke the full parser to deal with special cases such as array syntax. + */ + parseTypeString(typ_name, &result, &typmod, true); + + if (OidIsValid(result)) + PG_RETURN_OID(result); + else + PG_RETURN_NULL(); +} + /* * regtypeout - converts type OID to "typ_name" */ @@ -1523,7 +1623,7 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names, else { /* Use full parser to resolve the type name */ - parseTypeString(typename, &typeid, &typmod); + parseTypeString(typename, &typeid, &typmod, false); } if (*nargs >= FUNC_MAX_ARGS) ereport(ERROR, diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index e1a04c88b2..4b3357ccd9 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201404031 +#define CATALOG_VERSION_NO 201404081 #endif diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h index b30e5e8d02..2f9d391d28 100644 --- a/src/include/catalog/namespace.h +++ b/src/include/catalog/namespace.h @@ -76,7 +76,8 @@ extern FuncCandidateList FuncnameGetCandidates(List *names, extern bool FunctionIsVisible(Oid funcid); extern Oid OpernameGetOprid(List *names, Oid oprleft, Oid oprright); -extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind); +extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind, + bool missing_schema_ok); extern bool OperatorIsVisible(Oid oprid); extern Oid OpclassnameGetOpcid(Oid amid, const char *opcname); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 334e6b8d15..21c17a08ed 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -173,6 +173,8 @@ DATA(insert OID = 44 ( regprocin PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 DESCR("I/O"); DATA(insert OID = 45 ( regprocout PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2275 "24" _null_ _null_ _null_ _null_ regprocout _null_ _null_ _null_ )); DESCR("I/O"); +DATA(insert OID = 3494 ( to_regproc PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 24 "2275" _null_ _null_ _null_ _null_ to_regproc _null_ _null_ _null_ )); +DESCR("convert proname to regproc"); DATA(insert OID = 46 ( textin PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 25 "2275" _null_ _null_ _null_ _null_ textin _null_ _null_ _null_ )); DESCR("I/O"); DATA(insert OID = 47 ( textout PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "25" _null_ _null_ _null_ _null_ textout _null_ _null_ _null_ )); @@ -3304,6 +3306,8 @@ DATA(insert OID = 2214 ( regoperin PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2 DESCR("I/O"); DATA(insert OID = 2215 ( regoperout PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2275 "2203" _null_ _null_ _null_ _null_ regoperout _null_ _null_ _null_ )); DESCR("I/O"); +DATA(insert OID = 3492 ( to_regoper PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2203 "2275" _null_ _null_ _null_ _null_ to_regoper _null_ _null_ _null_ )); +DESCR("convert operator name to regoper"); DATA(insert OID = 2216 ( regoperatorin PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2204 "2275" _null_ _null_ _null_ _null_ regoperatorin _null_ _null_ _null_ )); DESCR("I/O"); DATA(insert OID = 2217 ( regoperatorout PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2275 "2204" _null_ _null_ _null_ _null_ regoperatorout _null_ _null_ _null_ )); @@ -3312,10 +3316,14 @@ DATA(insert OID = 2218 ( regclassin PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2 DESCR("I/O"); DATA(insert OID = 2219 ( regclassout PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2275 "2205" _null_ _null_ _null_ _null_ regclassout _null_ _null_ _null_ )); DESCR("I/O"); +DATA(insert OID = 3495 ( to_regclass PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2205 "2275" _null_ _null_ _null_ _null_ to_regclass _null_ _null_ _null_ )); +DESCR("convert classname to regclass"); DATA(insert OID = 2220 ( regtypein PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2206 "2275" _null_ _null_ _null_ _null_ regtypein _null_ _null_ _null_ )); DESCR("I/O"); DATA(insert OID = 2221 ( regtypeout PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2275 "2206" _null_ _null_ _null_ _null_ regtypeout _null_ _null_ _null_ )); DESCR("I/O"); +DATA(insert OID = 3493 ( to_regtype PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2206 "2275" _null_ _null_ _null_ _null_ to_regtype _null_ _null_ _null_ )); +DESCR("convert type name to regtype"); DATA(insert OID = 1079 ( regclass PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2205 "25" _null_ _null_ _null_ _null_ text_regclass _null_ _null_ _null_ )); DESCR("convert text to regclass"); diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h index ab73148dca..fa9cc5989b 100644 --- a/src/include/parser/parse_type.h +++ b/src/include/parser/parse_type.h @@ -47,7 +47,7 @@ extern Datum stringTypeDatum(Type tp, char *string, int32 atttypmod); extern Oid typeidTypeRelid(Oid type_id); -extern void parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p); +extern void parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, bool missing_ok); #define ISCOMPLEX(typeid) (typeidTypeRelid(typeid) != InvalidOid) diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 031a43a7e7..720c831801 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -597,6 +597,7 @@ extern char *regexp_fixed_prefix(text *text_re, bool case_insensitive, /* regproc.c */ extern Datum regprocin(PG_FUNCTION_ARGS); extern Datum regprocout(PG_FUNCTION_ARGS); +extern Datum to_regproc(PG_FUNCTION_ARGS); extern Datum regprocrecv(PG_FUNCTION_ARGS); extern Datum regprocsend(PG_FUNCTION_ARGS); extern Datum regprocedurein(PG_FUNCTION_ARGS); @@ -607,6 +608,7 @@ extern Datum regoperin(PG_FUNCTION_ARGS); extern Datum regoperout(PG_FUNCTION_ARGS); extern Datum regoperrecv(PG_FUNCTION_ARGS); extern Datum regopersend(PG_FUNCTION_ARGS); +extern Datum to_regoper(PG_FUNCTION_ARGS); extern Datum regoperatorin(PG_FUNCTION_ARGS); extern Datum regoperatorout(PG_FUNCTION_ARGS); extern Datum regoperatorrecv(PG_FUNCTION_ARGS); @@ -615,10 +617,12 @@ extern Datum regclassin(PG_FUNCTION_ARGS); extern Datum regclassout(PG_FUNCTION_ARGS); extern Datum regclassrecv(PG_FUNCTION_ARGS); extern Datum regclasssend(PG_FUNCTION_ARGS); +extern Datum to_regclass(PG_FUNCTION_ARGS); extern Datum regtypein(PG_FUNCTION_ARGS); extern Datum regtypeout(PG_FUNCTION_ARGS); extern Datum regtyperecv(PG_FUNCTION_ARGS); extern Datum regtypesend(PG_FUNCTION_ARGS); +extern Datum to_regtype(PG_FUNCTION_ARGS); extern Datum regconfigin(PG_FUNCTION_ARGS); extern Datum regconfigout(PG_FUNCTION_ARGS); extern Datum regconfigrecv(PG_FUNCTION_ARGS); diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index 7bc29a6b32..5fff63558f 100644 --- a/src/pl/plperl/plperl.c +++ b/src/pl/plperl/plperl.c @@ -3420,7 +3420,7 @@ plperl_spi_prepare(char *query, int argc, SV **argv) char *typstr; typstr = sv2cstr(argv[i]); - parseTypeString(typstr, &typId, &typmod); + parseTypeString(typstr, &typId, &typmod, false); pfree(typstr); getTypeInputInfo(typId, &typInput, &typIOParam); diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index 91186c6b9a..e3a992cf0f 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -3492,7 +3492,7 @@ parse_datatype(const char *string, int location) error_context_stack = &syntax_errcontext; /* Let the main parser try to parse it under standard SQL rules */ - parseTypeString(string, &type_id, &typmod); + parseTypeString(string, &type_id, &typmod, false); /* Restore former ereport callback */ error_context_stack = syntax_errcontext.previous; diff --git a/src/pl/plpython/plpy_spi.c b/src/pl/plpython/plpy_spi.c index 982bf84e0e..060d514a80 100644 --- a/src/pl/plpython/plpy_spi.c +++ b/src/pl/plpython/plpy_spi.c @@ -113,7 +113,7 @@ PLy_spi_prepare(PyObject *self, PyObject *args) *information for input conversion. ********************************************************/ - parseTypeString(sptr, &typeId, &typmod); + parseTypeString(sptr, &typeId, &typmod, false); typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeId)); diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index b3bf65ec88..2d862a6b05 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -2165,7 +2165,7 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp, typIOParam; int32 typmod; - parseTypeString(args[i], &typId, &typmod); + parseTypeString(args[i], &typId, &typmod, false); getTypeInputInfo(typId, &typInput, &typIOParam); diff --git a/src/test/regress/expected/regproc.out b/src/test/regress/expected/regproc.out new file mode 100644 index 0000000000..56ab245223 --- /dev/null +++ b/src/test/regress/expected/regproc.out @@ -0,0 +1,188 @@ +-- +-- regproc +-- +/* If objects exist, return oids */ +-- without schemaname +SELECT regoper('||/'); + regoper +--------- + ||/ +(1 row) + +SELECT regproc('now'); + regproc +--------- + now +(1 row) + +SELECT regclass('pg_class'); + regclass +---------- + pg_class +(1 row) + +SELECT regtype('int4'); + regtype +--------- + integer +(1 row) + +SELECT to_regoper('||/'); + to_regoper +------------ + ||/ +(1 row) + +SELECT to_regproc('now'); + to_regproc +------------ + now +(1 row) + +SELECT to_regclass('pg_class'); + to_regclass +------------- + pg_class +(1 row) + +SELECT to_regtype('int4'); + to_regtype +------------ + integer +(1 row) + +-- with schemaname +SELECT regoper('pg_catalog.||/'); + regoper +--------- + ||/ +(1 row) + +SELECT regproc('pg_catalog.now'); + regproc +--------- + now +(1 row) + +SELECT regclass('pg_catalog.pg_class'); + regclass +---------- + pg_class +(1 row) + +SELECT regtype('pg_catalog.int4'); + regtype +--------- + integer +(1 row) + +SELECT to_regoper('pg_catalog.||/'); + to_regoper +------------ + ||/ +(1 row) + +SELECT to_regproc('pg_catalog.now'); + to_regproc +------------ + now +(1 row) + +SELECT to_regclass('pg_catalog.pg_class'); + to_regclass +------------- + pg_class +(1 row) + +SELECT to_regtype('pg_catalog.int4'); + to_regtype +------------ + integer +(1 row) + +/* If objects don't exist, raise errors. */ +-- without schemaname +SELECT regoper('||//'); +ERROR: operator does not exist: ||// +LINE 3: SELECT regoper('||//'); + ^ +SELECT regproc('know'); +ERROR: function "know" does not exist +LINE 1: SELECT regproc('know'); + ^ +SELECT regclass('pg_classes'); +ERROR: relation "pg_classes" does not exist +LINE 1: SELECT regclass('pg_classes'); + ^ +SELECT regtype('int3'); +ERROR: type "int3" does not exist +LINE 1: SELECT regtype('int3'); + ^ +-- with schemaname +SELECT regoper('ng_catalog.||/'); +ERROR: schema "ng_catalog" does not exist +LINE 1: SELECT regoper('ng_catalog.||/'); + ^ +SELECT regproc('ng_catalog.now'); +ERROR: schema "ng_catalog" does not exist +LINE 1: SELECT regproc('ng_catalog.now'); + ^ +SELECT regclass('ng_catalog.pg_class'); +ERROR: schema "ng_catalog" does not exist +LINE 1: SELECT regclass('ng_catalog.pg_class'); + ^ +SELECT regtype('ng_catalog.int4'); +ERROR: schema "ng_catalog" does not exist +LINE 1: SELECT regtype('ng_catalog.int4'); + ^ +/* If objects don't exist, return NULL with no error. */ +-- without schemaname +SELECT to_regoper('||//'); + to_regoper +------------ + +(1 row) + +SELECT to_regproc('know'); + to_regproc +------------ + +(1 row) + +SELECT to_regclass('pg_classes'); + to_regclass +------------- + +(1 row) + +SELECT to_regtype('int3'); + to_regtype +------------ + +(1 row) + +-- with schemaname +SELECT to_regoper('ng_catalog.||/'); + to_regoper +------------ + +(1 row) + +SELECT to_regproc('ng_catalog.now'); + to_regproc +------------ + +(1 row) + +SELECT to_regclass('ng_catalog.pg_class'); + to_regclass +------------- + +(1 row) + +SELECT to_regtype('ng_catalog.int4'); + to_regtype +------------ + +(1 row) + diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index c62be2a023..c0416f4fb9 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -13,7 +13,7 @@ test: tablespace # ---------- # The first group of parallel tests # ---------- -test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric txid uuid enum money rangetypes pg_lsn +test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric txid uuid enum money rangetypes pg_lsn regproc # Depends on things setup during char, varchar and text test: strings diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index 885ca9aa5d..16a190507d 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -20,6 +20,7 @@ test: enum test: money test: rangetypes test: pg_lsn +test: regproc test: strings test: numerology test: point diff --git a/src/test/regress/sql/regproc.sql b/src/test/regress/sql/regproc.sql new file mode 100644 index 0000000000..1334cfb7aa --- /dev/null +++ b/src/test/regress/sql/regproc.sql @@ -0,0 +1,61 @@ +-- +-- regproc +-- + +/* If objects exist, return oids */ + +-- without schemaname + +SELECT regoper('||/'); +SELECT regproc('now'); +SELECT regclass('pg_class'); +SELECT regtype('int4'); + +SELECT to_regoper('||/'); +SELECT to_regproc('now'); +SELECT to_regclass('pg_class'); +SELECT to_regtype('int4'); + +-- with schemaname + +SELECT regoper('pg_catalog.||/'); +SELECT regproc('pg_catalog.now'); +SELECT regclass('pg_catalog.pg_class'); +SELECT regtype('pg_catalog.int4'); + +SELECT to_regoper('pg_catalog.||/'); +SELECT to_regproc('pg_catalog.now'); +SELECT to_regclass('pg_catalog.pg_class'); +SELECT to_regtype('pg_catalog.int4'); + +/* If objects don't exist, raise errors. */ + +-- without schemaname + +SELECT regoper('||//'); +SELECT regproc('know'); +SELECT regclass('pg_classes'); +SELECT regtype('int3'); + +-- with schemaname + +SELECT regoper('ng_catalog.||/'); +SELECT regproc('ng_catalog.now'); +SELECT regclass('ng_catalog.pg_class'); +SELECT regtype('ng_catalog.int4'); + +/* If objects don't exist, return NULL with no error. */ + +-- without schemaname + +SELECT to_regoper('||//'); +SELECT to_regproc('know'); +SELECT to_regclass('pg_classes'); +SELECT to_regtype('int3'); + +-- with schemaname + +SELECT to_regoper('ng_catalog.||/'); +SELECT to_regproc('ng_catalog.now'); +SELECT to_regclass('ng_catalog.pg_class'); +SELECT to_regtype('ng_catalog.int4');