summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2024-03-20 21:11:23 +0000
committerTom Lane2024-03-20 21:11:28 +0000
commit1218ca9956ee60afc6975f14c1a4c953bd6bbaa7 (patch)
tree193accadb5fecf5c0866e522e77cd3bd090d184c
parent80686761c49d5194d224b344e968c26981611726 (diff)
Add to_regtypemod function to extract typemod from a string type name.
In combination with to_regtype, this allows converting a string to the "canonicalized" form emitted by format_type. That usage requires parsing the string twice, which is slightly annoying but not really too expensive. We considered alternatives such as returning a record type, but that way was notationally uglier than this, and possibly less flexible. Like to_regtype(), we'd rather that this return NULL for any bad input, but the underlying type-parsing logic isn't yet capable of not throwing syntax errors. Adjust the documentation for both functions to point that out. In passing, fix up a couple of nearby entries in the System Catalog Information Functions table that had not gotten the word about our since-v13 convention for displaying function usage examples. David Wheeler and Erik Wienhold, reviewed by Pavel Stehule, Jim Jones, and others. Discussion: https://postgr.es/m/[email protected]
-rw-r--r--doc/src/sgml/func.sgml77
-rw-r--r--src/backend/utils/adt/regproc.c20
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/catalog/pg_proc.dat3
-rw-r--r--src/test/regress/expected/regproc.out37
-rw-r--r--src/test/regress/sql/regproc.sql8
6 files changed, 115 insertions, 32 deletions
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 5b225ccf4f5..030ea8affdf 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);
<tbody>
<row>
- <entry role="func_table_entry"><para role="func_signature">
+ <entry id="format-type" xreflabel="format_type" role="func_table_entry"><para role="func_signature">
<indexterm>
<primary>format_type</primary>
</indexterm>
@@ -25387,18 +25387,8 @@ SELECT currval(pg_get_serial_sequence('sometable', 'id'));
OID for comparison purposes but displays as a type name.
</para>
<para>
- For example:
-<programlisting>
-SELECT pg_typeof(33);
- pg_typeof
------------
- integer
-
-SELECT typlen FROM pg_type WHERE oid = pg_typeof(33);
- typlen
---------
- 4
-</programlisting>
+ <literal>pg_typeof(33)</literal>
+ <returnvalue>integer</returnvalue>
</para></entry>
</row>
@@ -25418,18 +25408,12 @@ SELECT typlen FROM pg_type WHERE oid = pg_typeof(33);
collatable data type, then an error is raised.
</para>
<para>
- For example:
-<programlisting>
-SELECT collation for (description) FROM pg_description LIMIT 1;
- pg_collation_for
-------------------
- "default"
-
-SELECT collation for ('foo' COLLATE "de_DE");
- pg_collation_for
-------------------
- "de_DE"
-</programlisting>
+ <literal>collation for ('foo'::text)</literal>
+ <returnvalue>"default"</returnvalue>
+ </para>
+ <para>
+ <literal>collation for ('foo' COLLATE "de_DE")</literal>
+ <returnvalue>"de_DE"</returnvalue>
</para></entry>
</row>
@@ -25570,7 +25554,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
</row>
<row>
- <entry role="func_table_entry"><para role="func_signature">
+ <entry id="to-regtype" xreflabel="to_regtype" role="func_table_entry"><para role="func_signature">
<indexterm>
<primary>to_regtype</primary>
</indexterm>
@@ -25578,11 +25562,42 @@ SELECT collation for ('foo' COLLATE "de_DE");
<returnvalue>regtype</returnvalue>
</para>
<para>
- Translates a textual type name to its OID. A similar result is
- obtained by casting the string to type <type>regtype</type> (see
- <xref linkend="datatype-oid"/>); however, this function will return
- <literal>NULL</literal> 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 a type OID. A syntax error in the
+ string will result in an error; but if the string is a
+ syntactically valid type name that happens not to be found in the
+ catalogs, the result is <literal>NULL</literal>. A similar result
+ is obtained by casting the string to type <type>regtype</type>
+ (see <xref linkend="datatype-oid"/>), except that that will throw
+ error for name not found.
+ </para></entry>
+ </row>
+
+ <row>
+ <entry role="func_table_entry"><para role="func_signature">
+ <indexterm>
+ <primary>to_regtypemod</primary>
+ </indexterm>
+ <function>to_regtypemod</function> ( <type>text</type> )
+ <returnvalue>integer</returnvalue>
+ </para>
+ <para>
+ Parses a string of text, extracts a potential type name from it,
+ and translates its type modifier, if any. A syntax error in the
+ string will result in an error; but if the string is a
+ syntactically valid type name that happens not to be found in the
+ catalogs, the result is <literal>NULL</literal>. The result is
+ <literal>-1</literal> if no type modifier is present.
+ </para>
+ <para>
+ <function>to_regtypemod</function> can be combined with
+ <xref linkend="to-regtype"/> to produce appropriate inputs for
+ <xref linkend="format-type"/>, allowing a string representing a
+ type name to be canonicalized.
+ </para>
+ <para>
+ <literal>format_type(to_regtype('varchar(32)'), to_regtypemod('varchar(32)'))</literal>
+ <returnvalue>character varying(32)</returnvalue>
</para></entry>
</row>
</tbody>
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index 1e3bf3f5fd6..18d5b7d166c 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -1221,6 +1221,26 @@ to_regtype(PG_FUNCTION_ARGS)
}
/*
+ * to_regtypemod - converts "typename" to type modifier
+ *
+ * If the name is not found, we return NULL.
+ */
+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};
+
+ /* We rely on parseTypeString to parse the input. */
+ if (!parseTypeString(typ_name, &typid, &typmod, (Node *) &escontext))
+ PG_RETURN_NULL();
+
+ PG_RETURN_INT32(typmod);
+}
+
+/*
* regtypeout - converts type OID to "typ_name"
*/
Datum
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index b05db0fa0ae..3c4e49b73a0 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -57,6 +57,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202403201
+#define CATALOG_VERSION_NO 202403202
#endif
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 177d81a891c..042f66f7145 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 modifier',
+ 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 a9420850b87..97b917502ca 100644
--- a/src/test/regress/expected/regproc.out
+++ b/src/test/regress/expected/regproc.out
@@ -447,6 +447,43 @@ SELECT to_regnamespace('foo.bar');
(1 row)
+-- 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('no_such_type(4)');
+ to_regtypemod
+---------------
+
+(1 row)
+
+SELECT format_type(to_regtype('varchar(32)'), to_regtypemod('varchar(32)'));
+ format_type
+-----------------------
+ character varying(32)
+(1 row)
+
+SELECT format_type(to_regtype('bit'), to_regtypemod('bit'));
+ format_type
+-------------
+ bit(1)
+(1 row)
+
+SELECT format_type(to_regtype('"bit"'), to_regtypemod('"bit"'));
+ format_type
+-------------
+ "bit"
+(1 row)
+
-- Test soft-error API
SELECT * FROM pg_input_error_info('ng_catalog.pg_class', 'regclass');
message | detail | hint | sql_error_code
diff --git a/src/test/regress/sql/regproc.sql b/src/test/regress/sql/regproc.sql
index de2aa881a8d..232289ac398 100644
--- a/src/test/regress/sql/regproc.sql
+++ b/src/test/regress/sql/regproc.sql
@@ -123,6 +123,14 @@ SELECT to_regnamespace('Nonexistent');
SELECT to_regnamespace('"Nonexistent"');
SELECT to_regnamespace('foo.bar');
+-- Test to_regtypemod
+SELECT to_regtypemod('text');
+SELECT to_regtypemod('timestamp(4)');
+SELECT to_regtypemod('no_such_type(4)');
+SELECT format_type(to_regtype('varchar(32)'), to_regtypemod('varchar(32)'));
+SELECT format_type(to_regtype('bit'), to_regtypemod('bit'));
+SELECT format_type(to_regtype('"bit"'), to_regtypemod('"bit"'));
+
-- Test soft-error API
SELECT * FROM pg_input_error_info('ng_catalog.pg_class', 'regclass');