aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/namespace.c6
-rw-r--r--src/backend/parser/parse_oper.c6
-rw-r--r--src/backend/parser/parse_type.c29
-rw-r--r--src/backend/utils/adt/regproc.c108
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/catalog/namespace.h3
-rw-r--r--src/include/catalog/pg_proc.h8
-rw-r--r--src/include/parser/parse_type.h2
-rw-r--r--src/include/utils/builtins.h4
-rw-r--r--src/pl/plperl/plperl.c2
-rw-r--r--src/pl/plpgsql/src/pl_gram.y2
-rw-r--r--src/pl/plpython/plpy_spi.c2
-rw-r--r--src/pl/tcl/pltcl.c2
-rw-r--r--src/test/regress/expected/regproc.out188
-rw-r--r--src/test/regress/parallel_schedule2
-rw-r--r--src/test/regress/serial_schedule1
-rw-r--r--src/test/regress/sql/regproc.sql61
17 files changed, 409 insertions, 19 deletions
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 6c2a5d2af5a..5bf6d289d84 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 99dbd30d758..a2b712d5161 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 b329dfb1684..b8c10e11c9f 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 5d73562a4fc..ed2bdbfb097 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -153,6 +153,31 @@ regprocin(PG_FUNCTION_ARGS)
}
/*
+ * 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"
*/
Datum
@@ -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,
@@ -520,6 +545,31 @@ regoperin(PG_FUNCTION_ARGS)
}
/*
+ * 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"
*/
Datum
@@ -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);
@@ -873,6 +923,33 @@ regclassin(PG_FUNCTION_ARGS)
}
/*
+ * 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"
*/
Datum
@@ -1028,12 +1105,35 @@ 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"
*/
Datum
@@ -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 e1a04c88b20..4b3357ccd97 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 b30e5e8d025..2f9d391d28f 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 334e6b8d155..21c17a08ed4 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 ab73148dcaa..fa9cc5989bd 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 031a43a7e78..720c8318011 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 7bc29a6b324..5fff63558f1 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 91186c6b9ae..e3a992cf0ff 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 982bf84e0e5..060d514a80d 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 b3bf65ec885..2d862a6b059 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 00000000000..56ab2452234
--- /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 c62be2a023e..c0416f4fb9d 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 885ca9aa5dd..16a190507d5 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 00000000000..1334cfb7aab
--- /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');