diff options
author | Tom Lane | 2024-03-20 21:11:23 +0000 |
---|---|---|
committer | Tom Lane | 2024-03-20 21:11:28 +0000 |
commit | 1218ca9956ee60afc6975f14c1a4c953bd6bbaa7 (patch) | |
tree | 193accadb5fecf5c0866e522e77cd3bd090d184c | |
parent | 80686761c49d5194d224b344e968c26981611726 (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.sgml | 77 | ||||
-rw-r--r-- | src/backend/utils/adt/regproc.c | 20 | ||||
-rw-r--r-- | src/include/catalog/catversion.h | 2 | ||||
-rw-r--r-- | src/include/catalog/pg_proc.dat | 3 | ||||
-rw-r--r-- | src/test/regress/expected/regproc.out | 37 | ||||
-rw-r--r-- | src/test/regress/sql/regproc.sql | 8 |
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'); |