diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 5b225ccf4f5f1..31321f27b0ba4 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -24872,7 +24872,7 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
-
+
format_type
@@ -25570,7 +25570,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
-
+
to_regtype
@@ -25578,13 +25578,53 @@ SELECT collation for ('foo' COLLATE "de_DE");
regtype
- Translates a textual type name to its OID. A similar result is
- obtained by casting the string to type regtype (see
- ); however, this function will return
- NULL rather than throwing an error if the name is
- not found.
+ Parses a string of text, extracts a potential type name from it, and
+ translates that name into an OID. A similar result is obtained by
+ casting the string to type regtype (see
+ ). Failure to extract a valid potential
+ type name results in an error. For example:
+
+SELECT to_regtype('interval nonesuch');
+ERROR: syntax error at or near "nonesuch"
+LINE 1: select to_regtype('interval nonesuch');
+ ^
+CONTEXT: invalid type name "interval nonesuch"
+
+ However, if the extracted name is not known to the system, this function
+ will return NULL. For example:
+
+SELECT to_regtype('party');
+ to_regtype
+------------
+
+
+
+
+
+
+
+
+ to_regtypemod
+
+ to_regtypemod ( text )
+ integer
+
+
+ Parses a string of text, extracts a potential type name from it, and
+ translates its type modifier, if any. Failure to extract a valid
+ potential type name results in an error; however, if the extracted name
+ is not known to the system, this function will return
+ NULL. Complements , and
+ can be passed to . For example:
+
+SELECT format_type(to_regtype('varchar(32)'), to_regtypemod('varchar(32)'));
+ format_type
+-----------------------
+ character varying(32)
+
+
diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl
index 94afdc5491dd8..a0c299f067b6b 100644
--- a/src/backend/catalog/genbki.pl
+++ b/src/backend/catalog/genbki.pl
@@ -1098,7 +1098,7 @@ sub lookup_oids
{
warn sprintf
"unresolved OID reference \"%s\" in %s.dat field %s line %s\n",
- $lookupname, $catname, $attname, $bki_values->{line_number};
+ $lookupname || '', $catname || '', $attname || '', $bki_values->{line_number} || '';
$num_errors++;
}
}
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index 1e3bf3f5fd6f6..75b8429e0d240 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -1220,6 +1220,35 @@ to_regtype(PG_FUNCTION_ARGS)
PG_RETURN_DATUM(result);
}
+
+/*
+ * to_regtypemod() complements to_regtype, returning the typmod for the type,
+ * if any.
+ *
+ * If the type name is not found, we return NULL.
+ *
+ * Internally it relies on the Postgres core parseTypeString() function defined
+ * in src/backend/parser/parse_type.c.
+ */
+Datum
+to_regtypemod(PG_FUNCTION_ARGS)
+{
+ char *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
+ Oid typid;
+ int32 typmod;
+ ErrorSaveContext escontext = {T_ErrorSaveContext};
+
+ /*
+ * Parse type-name argument to obtain the encoded typmod. Return NULL
+ * on failure.
+ */
+ if (!parseTypeString(typ_name, &typid, &typmod, (Node *) &escontext)) {
+ PG_RETURN_NULL();
+ }
+
+ PG_RETURN_INT32(typmod);
+}
+
/*
* regtypeout - converts type OID to "typ_name"
*/
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 177d81a891c33..770591c7346ee 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -7155,6 +7155,9 @@
{ oid => '3493', descr => 'convert type name to regtype',
proname => 'to_regtype', provolatile => 's', prorettype => 'regtype',
proargtypes => 'text', prosrc => 'to_regtype' },
+{ oid => '8401', descr => 'convert type name to type mod',
+ proname => 'to_regtypemod', provolatile => 's', prorettype => 'int4',
+ proargtypes => 'text', prosrc => 'to_regtypemod' },
{ oid => '1079', descr => 'convert text to regclass',
proname => 'regclass', provolatile => 's', prorettype => 'regclass',
proargtypes => 'text', prosrc => 'text_regclass' },
diff --git a/src/test/regress/expected/regproc.out b/src/test/regress/expected/regproc.out
index a9420850b87ec..ff1ee5b52c531 100644
--- a/src/test/regress/expected/regproc.out
+++ b/src/test/regress/expected/regproc.out
@@ -544,3 +544,69 @@ SELECT * FROM pg_input_error_info('way.too.many.names', 'regtype');
ERROR: improper qualified name (too many dotted names): way.too.many.names
SELECT * FROM pg_input_error_info('no_such_catalog.schema.name', 'regtype');
ERROR: cross-database references are not implemented: no_such_catalog.schema.name
+-- Test to_regtypemod
+SELECT to_regtypemod('text');
+ to_regtypemod
+---------------
+ -1
+(1 row)
+
+SELECT to_regtypemod('timestamp(4)');
+ to_regtypemod
+---------------
+ 4
+(1 row)
+
+SELECT to_regtypemod('interval(0)');
+ to_regtypemod
+---------------
+ 2147418112
+(1 row)
+
+SELECT to_regtypemod('interval second(0)');
+ to_regtypemod
+---------------
+ 268435456
+(1 row)
+
+SELECT to_regtypemod('timestamptz');
+ to_regtypemod
+---------------
+ -1
+(1 row)
+
+SELECT to_regtypemod('timestamptz(6)');
+ to_regtypemod
+---------------
+ 6
+(1 row)
+
+SELECT to_regtypemod('varchar');
+ to_regtypemod
+---------------
+ -1
+(1 row)
+
+SELECT to_regtypemod('varchar(128)');
+ to_regtypemod
+---------------
+ 132
+(1 row)
+
+SELECT to_regtypemod(NULL); -- returns null on null input
+ to_regtypemod
+---------------
+
+(1 row)
+
+SELECT to_regtypemod('year(4)'); -- error trapped, returns null
+ to_regtypemod
+---------------
+
+(1 row)
+
+SELECT to_regtypemod('interval nonesuch'); -- grammar error raised, not trapped
+ERROR: syntax error at or near "nonesuch"
+LINE 1: SELECT to_regtypemod('interval nonesuch');
+ ^
+CONTEXT: invalid type name "interval nonesuch"
diff --git a/src/test/regress/sql/regproc.sql b/src/test/regress/sql/regproc.sql
index de2aa881a8dc0..c1717e1f8fc43 100644
--- a/src/test/regress/sql/regproc.sql
+++ b/src/test/regress/sql/regproc.sql
@@ -145,3 +145,17 @@ SELECT * FROM pg_input_error_info('incorrect type name syntax', 'regtype');
SELECT * FROM pg_input_error_info('numeric(1,2,3)', 'regtype'); -- bogus typmod
SELECT * FROM pg_input_error_info('way.too.many.names', 'regtype');
SELECT * FROM pg_input_error_info('no_such_catalog.schema.name', 'regtype');
+
+-- Test to_regtypemod
+SELECT to_regtypemod('text');
+SELECT to_regtypemod('timestamp(4)');
+SELECT to_regtypemod('interval(0)');
+SELECT to_regtypemod('interval second(0)');
+SELECT to_regtypemod('timestamptz');
+SELECT to_regtypemod('timestamptz(6)');
+SELECT to_regtypemod('varchar');
+SELECT to_regtypemod('varchar(128)');
+
+SELECT to_regtypemod(NULL); -- returns null on null input
+SELECT to_regtypemod('year(4)'); -- error trapped, returns null
+SELECT to_regtypemod('interval nonesuch'); -- grammar error raised, not trapped