Create a new type category for "internal use" types.
authorTom Lane <[email protected]>
Sat, 11 Dec 2021 19:10:51 +0000 (14:10 -0500)
committerTom Lane <[email protected]>
Sat, 11 Dec 2021 19:10:51 +0000 (14:10 -0500)
Historically we've put type "char" into the S (String) typcategory,
although calling it a string is a stretch considering it can only
store one byte.  (In our actual usage, it's more like an enum.)
This choice now seems wrong in view of the special heuristics
that parse_func.c and parse_coerce.c have for TYPCATEGORY_STRING:
it's not a great idea for "char" to have those preferential casting
behaviors.

Worse than that, recent patches inventing special-purpose types
like pg_node_tree have assigned typcategory S to those types,
meaning they also get preferential casting treatment that's designed
on the assumption that they can hold arbitrary text.

To fix, invent a new category TYPCATEGORY_INTERNAL for internal-use
types, and assign that to all these types.  I used code 'Z' for
lack of a better idea ('I' was already taken).

This change breaks one query in psql/describe.c, which now needs to
explicitly cast a catalog "char" column to text before concatenating
it with an undecorated literal.  Also, a test case in contrib/citext
now needs an explicit cast to convert citext to "char".  Since the
point of this change is to not have "char" be a surprisingly-available
cast target, these breakages seem OK.

Per report from Ian Campbell.

Discussion: https://postgr.es/m/2216388.1638480141@sss.pgh.pa.us

contrib/citext/expected/citext.out
contrib/citext/expected/citext_1.out
contrib/citext/sql/citext.sql
doc/src/sgml/catalogs.sgml
src/bin/psql/describe.c
src/include/catalog/catversion.h
src/include/catalog/pg_type.dat
src/include/catalog/pg_type.h

index ec99aaed5dcc60898e8af1f7c0b3ebbce96331a2..3bac0534fb86b6211b3f5bd4d5a1d482365cfbe6 100644 (file)
@@ -1089,7 +1089,12 @@ INSERT INTO caster (char)          VALUES ('f'::citext);
 INSERT INTO caster (citext)        VALUES ('f'::char);
 INSERT INTO caster (chr)           VALUES ('f'::text);
 INSERT INTO caster (text)          VALUES ('f'::"char");
-INSERT INTO caster (chr)           VALUES ('f'::citext);
+INSERT INTO caster (chr)           VALUES ('f'::citext);  -- requires cast
+ERROR:  column "chr" is of type "char" but expression is of type citext
+LINE 1: INSERT INTO caster (chr)           VALUES ('f'::citext);
+                                                   ^
+HINT:  You will need to rewrite or cast the expression.
+INSERT INTO caster (chr)           VALUES ('f'::citext::text);
 INSERT INTO caster (citext)        VALUES ('f'::"char");
 INSERT INTO caster (name)          VALUES ('foo'::text);
 INSERT INTO caster (text)          VALUES ('foo'::name);
index 75fd08b7cc4a32edcb970e02c81e8abaec5e27ea..57fc863f7a57821609c816e70e2673095f42771c 100644 (file)
@@ -1089,7 +1089,12 @@ INSERT INTO caster (char)          VALUES ('f'::citext);
 INSERT INTO caster (citext)        VALUES ('f'::char);
 INSERT INTO caster (chr)           VALUES ('f'::text);
 INSERT INTO caster (text)          VALUES ('f'::"char");
-INSERT INTO caster (chr)           VALUES ('f'::citext);
+INSERT INTO caster (chr)           VALUES ('f'::citext);  -- requires cast
+ERROR:  column "chr" is of type "char" but expression is of type citext
+LINE 1: INSERT INTO caster (chr)           VALUES ('f'::citext);
+                                                   ^
+HINT:  You will need to rewrite or cast the expression.
+INSERT INTO caster (chr)           VALUES ('f'::citext::text);
 INSERT INTO caster (citext)        VALUES ('f'::"char");
 INSERT INTO caster (name)          VALUES ('foo'::text);
 INSERT INTO caster (text)          VALUES ('foo'::name);
index 10232f5a9f44852315259c04c50ea083d13b3372..55fb1d11a6f6a0c4a88db544ec7dd4b385121e16 100644 (file)
@@ -361,7 +361,8 @@ INSERT INTO caster (citext)        VALUES ('f'::char);
 
 INSERT INTO caster (chr)           VALUES ('f'::text);
 INSERT INTO caster (text)          VALUES ('f'::"char");
-INSERT INTO caster (chr)           VALUES ('f'::citext);
+INSERT INTO caster (chr)           VALUES ('f'::citext);  -- requires cast
+INSERT INTO caster (chr)           VALUES ('f'::citext::text);
 INSERT INTO caster (citext)        VALUES ('f'::"char");
 
 INSERT INTO caster (name)          VALUES ('foo'::text);
index 025db98763351aa96a76eee2a714ac50bb6290a2..03e2537b07d65916acb66904dcb4ff7caed507c0 100644 (file)
@@ -9317,6 +9317,10 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
       <entry><literal>X</literal></entry>
       <entry><type>unknown</type> type</entry>
      </row>
+     <row>
+      <entry><literal>Z</literal></entry>
+      <entry>Internal-use types</entry>
+     </row>
     </tbody>
    </tgroup>
   </table>
index ea721d963a7274ccb5d03d8f33689293d70091ba..72d8547628a3e5dcd3081faa79421d0a84c1cab3 100644 (file)
@@ -1142,7 +1142,7 @@ permissionsList(const char *pattern)
                                                  ",\n  pg_catalog.array_to_string(ARRAY(\n"
                                                  "    SELECT polname\n"
                                                  "    || CASE WHEN polcmd != '*' THEN\n"
-                                                 "           E' (' || polcmd || E'):'\n"
+                                                 "           E' (' || polcmd::pg_catalog.text || E'):'\n"
                                                  "       ELSE E':'\n"
                                                  "       END\n"
                                                  "    || CASE WHEN polqual IS NOT NULL THEN\n"
@@ -1176,7 +1176,7 @@ permissionsList(const char *pattern)
                                                  "       E' (RESTRICTIVE)'\n"
                                                  "       ELSE '' END\n"
                                                  "    || CASE WHEN polcmd != '*' THEN\n"
-                                                 "           E' (' || polcmd || E'):'\n"
+                                                 "           E' (' || polcmd::pg_catalog.text || E'):'\n"
                                                  "       ELSE E':'\n"
                                                  "       END\n"
                                                  "    || CASE WHEN polqual IS NOT NULL THEN\n"
index c8259b833bcd5caf7fcad3e6d0303ead85b44b01..6b19ffddde9b72d7844f37cfdb9e2c56cb05dcfd 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     202112081
+#define CATALOG_VERSION_NO     202112111
 
 #endif
index 41074c994b1187f1b7010f92914a6c45d51a4d5f..f3d94f3cf5d1817d497a7ac638b0e50e62554e37 100644 (file)
@@ -42,7 +42,7 @@
   typinput => 'byteain', typoutput => 'byteaout', typreceive => 'bytearecv',
   typsend => 'byteasend', typalign => 'i', typstorage => 'x' },
 { oid => '18', array_type_oid => '1002', descr => 'single character',
-  typname => 'char', typlen => '1', typbyval => 't', typcategory => 'S',
+  typname => 'char', typlen => '1', typbyval => 't', typcategory => 'Z',
   typinput => 'charin', typoutput => 'charout', typreceive => 'charrecv',
   typsend => 'charsend', typalign => 'c' },
 { oid => '19', array_type_oid => '1003',
   typsend => 'xml_send', typalign => 'i', typstorage => 'x' },
 { oid => '194', descr => 'string representing an internal node tree',
   typname => 'pg_node_tree', typlen => '-1', typbyval => 'f',
-  typcategory => 'S', typinput => 'pg_node_tree_in',
+  typcategory => 'Z', typinput => 'pg_node_tree_in',
   typoutput => 'pg_node_tree_out', typreceive => 'pg_node_tree_recv',
   typsend => 'pg_node_tree_send', typalign => 'i', typstorage => 'x',
   typcollation => 'default' },
 { oid => '3361', descr => 'multivariate ndistinct coefficients',
   typname => 'pg_ndistinct', typlen => '-1', typbyval => 'f',
-  typcategory => 'S', typinput => 'pg_ndistinct_in',
+  typcategory => 'Z', typinput => 'pg_ndistinct_in',
   typoutput => 'pg_ndistinct_out', typreceive => 'pg_ndistinct_recv',
   typsend => 'pg_ndistinct_send', typalign => 'i', typstorage => 'x',
   typcollation => 'default' },
 { oid => '3402', descr => 'multivariate dependencies',
   typname => 'pg_dependencies', typlen => '-1', typbyval => 'f',
-  typcategory => 'S', typinput => 'pg_dependencies_in',
+  typcategory => 'Z', typinput => 'pg_dependencies_in',
   typoutput => 'pg_dependencies_out', typreceive => 'pg_dependencies_recv',
   typsend => 'pg_dependencies_send', typalign => 'i', typstorage => 'x',
   typcollation => 'default' },
 { oid => '5017', descr => 'multivariate MCV list',
-  typname => 'pg_mcv_list', typlen => '-1', typbyval => 'f', typcategory => 'S',
+  typname => 'pg_mcv_list', typlen => '-1', typbyval => 'f', typcategory => 'Z',
   typinput => 'pg_mcv_list_in', typoutput => 'pg_mcv_list_out',
   typreceive => 'pg_mcv_list_recv', typsend => 'pg_mcv_list_send',
   typalign => 'i', typstorage => 'x', typcollation => 'default' },
   typalign => 'd', typstorage => 'x' },
 { oid => '4600', descr => 'BRIN bloom summary',
   typname => 'pg_brin_bloom_summary', typlen => '-1', typbyval => 'f',
-  typcategory => 'S', typinput => 'brin_bloom_summary_in',
+  typcategory => 'Z', typinput => 'brin_bloom_summary_in',
   typoutput => 'brin_bloom_summary_out',
   typreceive => 'brin_bloom_summary_recv', typsend => 'brin_bloom_summary_send',
   typalign => 'i', typstorage => 'x', typcollation => 'default' },
 { oid => '4601', descr => 'BRIN minmax-multi summary',
   typname => 'pg_brin_minmax_multi_summary', typlen => '-1', typbyval => 'f',
-  typcategory => 'S', typinput => 'brin_minmax_multi_summary_in',
+  typcategory => 'Z', typinput => 'brin_minmax_multi_summary_in',
   typoutput => 'brin_minmax_multi_summary_out',
   typreceive => 'brin_minmax_multi_summary_recv',
   typsend => 'brin_minmax_multi_summary_send', typalign => 'i',
index e568e21dee606ba96d2a7058e6df5a6e1a71de45..5e891a05962d00e5a258f7e6bd1c055a9c6d5d33 100644 (file)
@@ -294,6 +294,7 @@ DECLARE_UNIQUE_INDEX(pg_type_typname_nsp_index, 2704, TypeNameNspIndexId, on pg_
 #define  TYPCATEGORY_USER              'U'
 #define  TYPCATEGORY_BITSTRING 'V' /* er ... "varbit"? */
 #define  TYPCATEGORY_UNKNOWN   'X'
+#define  TYPCATEGORY_INTERNAL  'Z'
 
 #define  TYPALIGN_CHAR                 'c' /* char alignment (i.e. unaligned) */
 #define  TYPALIGN_SHORT                        's' /* short alignment (typically 2 bytes) */