public inbox for [email protected]
help / color / mirror / Atom feedDubious usage of TYPCATEGORY_STRING
11+ messages / 4 participants
[nested] [flat]
* Dubious usage of TYPCATEGORY_STRING
@ 2021-12-02 21:22 Tom Lane <[email protected]>
0 siblings, 3 replies; 11+ messages in thread
From: Tom Lane @ 2021-12-02 21:22 UTC (permalink / raw)
To: [email protected]
The parser's type-coercion heuristics include some special rules
for types belonging to the STRING category, which are predicated
on the assumption that such types are reasonably general-purpose
string types. This assumption has been violated by a few types,
one error being ancient and the rest not so much:
1. The "char" type is labeled as STRING category, even though it's
(a) deprecated for general use and (b) unable to store more than
one byte, making "string" quite a misnomer.
2. Various types we invented to store special catalog data, such as
pg_node_tree and pg_ndistinct, are also labeled as STRING category.
This seems like a fairly bad idea too.
An example of the reasons not to treat these types as being
general-purpose strings can be seen at [1], where the "char"
type has acquired some never-intended cast behaviors. Taking
that to an extreme, we currently accept
regression=# select '(1,2)'::point::"char";
char
------
(
(1 row)
My first thought about fixing point 1 was to put "char" into some
other typcategory, but that turns out to break some of psql's
catalog queries, with results like:
regression=# \dp
ERROR: operator is not unique: unknown || "char"
LINE 16: E' (' || polcmd || E'):'
^
HINT: Could not choose a best candidate operator. You might need to add explicit type casts.
I looked briefly at rejiggering the casting rules so that that
would still work, but it looks like a mess. The problem is that
unknown || "char" can match either text || text or text || anynonarray,
and it's only the special preference for preferred types *of the
same typcategory as the input type* that allows us to prefer one
of those over the other.
Hence, what 0001 below does is to leave "char" in the string
category, but explicitly disable its access to the special
cast-via-I/O rules. This is a hack for sure, but it won't have
any surprising side-effects on other types, which changing the
general operator-matching rules could. The only thing it breaks
in check-world is that contrib/citext expects casting between
"char" and citext to work. I think that's not a very reasonable
expectation so I just took out the relevant test cases. (If anyone
is hot about it, we could add explicit support for such casts in
the citext module ... but it doesn't seem worth the trouble.)
As for point 2, I haven't found any negative side-effects of
taking the special types out of the string category, so 0002
attached invents a separate TYPCATEGORY_INTERNAL category to
put them in.
Thoughts?
regards, tom lane
[1] https://www.postgresql.org/message-id/flat/CAOC8YUcXymCMpC5d%3D7JvcwyjXPTT00WeebOM3UqTBreOD1N9hw%40m...
Attachments:
[text/x-diff] 0001-hack-behavior-of-char-type.patch (5.0K, ../../[email protected]/2-0001-hack-behavior-of-char-type.patch)
download | inline diff:
diff --git a/contrib/citext/expected/citext.out b/contrib/citext/expected/citext.out
index ec99aaed5d..307d292d56 100644
--- a/contrib/citext/expected/citext.out
+++ b/contrib/citext/expected/citext.out
@@ -721,18 +721,6 @@ SELECT 'f'::citext::char = 'f'::char AS t;
t
(1 row)
-SELECT 'f'::"char"::citext = 'f' AS t;
- t
----
- t
-(1 row)
-
-SELECT 'f'::citext::"char" = 'f'::"char" AS t;
- t
----
- t
-(1 row)
-
SELECT '100'::money::citext = '$100.00' AS t;
t
---
@@ -1041,7 +1029,6 @@ CREATE TABLE caster (
varchar varchar,
bpchar bpchar,
char char,
- chr "char",
name name,
bytea bytea,
boolean boolean,
@@ -1087,10 +1074,6 @@ INSERT INTO caster (char) VALUES ('f'::text);
INSERT INTO caster (text) VALUES ('f'::char);
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 (citext) VALUES ('f'::"char");
INSERT INTO caster (name) VALUES ('foo'::text);
INSERT INTO caster (text) VALUES ('foo'::name);
INSERT INTO caster (name) VALUES ('foo'::citext);
diff --git a/contrib/citext/expected/citext_1.out b/contrib/citext/expected/citext_1.out
index 75fd08b7cc..9f423b7496 100644
--- a/contrib/citext/expected/citext_1.out
+++ b/contrib/citext/expected/citext_1.out
@@ -721,18 +721,6 @@ SELECT 'f'::citext::char = 'f'::char AS t;
t
(1 row)
-SELECT 'f'::"char"::citext = 'f' AS t;
- t
----
- t
-(1 row)
-
-SELECT 'f'::citext::"char" = 'f'::"char" AS t;
- t
----
- t
-(1 row)
-
SELECT '100'::money::citext = '$100.00' AS t;
t
---
@@ -1041,7 +1029,6 @@ CREATE TABLE caster (
varchar varchar,
bpchar bpchar,
char char,
- chr "char",
name name,
bytea bytea,
boolean boolean,
@@ -1087,10 +1074,6 @@ INSERT INTO caster (char) VALUES ('f'::text);
INSERT INTO caster (text) VALUES ('f'::char);
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 (citext) VALUES ('f'::"char");
INSERT INTO caster (name) VALUES ('foo'::text);
INSERT INTO caster (text) VALUES ('foo'::name);
INSERT INTO caster (name) VALUES ('foo'::citext);
diff --git a/contrib/citext/sql/citext.sql b/contrib/citext/sql/citext.sql
index 10232f5a9f..30ce6b807d 100644
--- a/contrib/citext/sql/citext.sql
+++ b/contrib/citext/sql/citext.sql
@@ -230,9 +230,6 @@ SELECT 'foo'::citext::name = 'foo'::name AS t;
SELECT 'f'::char::citext = 'f' AS t;
SELECT 'f'::citext::char = 'f'::char AS t;
-SELECT 'f'::"char"::citext = 'f' AS t;
-SELECT 'f'::citext::"char" = 'f'::"char" AS t;
-
SELECT '100'::money::citext = '$100.00' AS t;
SELECT '100'::citext::money = '100'::money AS t;
@@ -308,7 +305,6 @@ CREATE TABLE caster (
varchar varchar,
bpchar bpchar,
char char,
- chr "char",
name name,
bytea bytea,
boolean boolean,
@@ -359,11 +355,6 @@ INSERT INTO caster (text) VALUES ('f'::char);
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 (citext) VALUES ('f'::"char");
-
INSERT INTO caster (name) VALUES ('foo'::text);
INSERT INTO caster (text) VALUES ('foo'::name);
INSERT INTO caster (name) VALUES ('foo'::citext);
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 78194afedf..4ece7278f4 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -3139,13 +3139,19 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
* probably be better to insist on explicit casts in both directions,
* but this is a compromise to preserve something of the pre-8.3
* behavior that many types had implicit (yipes!) casts to text.
+ *
+ * As a special case, don't treat type "char" as being a string type
+ * for this purpose. In principle we should give it some other
+ * typcategory, but doing so breaks cases that we want to work.
*/
if (result == COERCION_PATH_NONE)
{
if (ccontext >= COERCION_ASSIGNMENT &&
+ targetTypeId != CHAROID &&
TypeCategory(targetTypeId) == TYPCATEGORY_STRING)
result = COERCION_PATH_COERCEVIAIO;
else if (ccontext >= COERCION_EXPLICIT &&
+ sourceTypeId != CHAROID &&
TypeCategory(sourceTypeId) == TYPCATEGORY_STRING)
result = COERCION_PATH_COERCEVIAIO;
}
[text/x-diff] 0002-dont-put-special-purpose-types-in-string-category.patch (3.9K, ../../[email protected]/3-0002-dont-put-special-purpose-types-in-string-category.patch)
download | inline diff:
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index c1d11be73f..216aa4510d 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -9305,6 +9305,10 @@ SCRAM-SHA-256$<replaceable><iteration count></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>
diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat
index 41074c994b..14d50376a1 100644
--- a/src/include/catalog/pg_type.dat
+++ b/src/include/catalog/pg_type.dat
@@ -145,24 +145,24 @@
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' },
@@ -681,13 +681,13 @@
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',
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index e568e21dee..5e891a0596 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -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) */
^ permalink raw reply [nested|flat] 11+ messages in thread
* types reliant on encodings [was Re: Dubious usage of TYPCATEGORY_STRING]
@ 2021-12-03 18:42 Chapman Flack <[email protected]>
parent: Tom Lane <[email protected]>
2 siblings, 1 reply; 11+ messages in thread
From: Chapman Flack @ 2021-12-03 18:42 UTC (permalink / raw)
To: Tom Lane <[email protected]>; [email protected]
On 12/02/21 16:22, Tom Lane wrote:
> ... types belonging to the STRING category, which are predicated
> on the assumption that such types are reasonably general-purpose
> string types.
This prods me to submit a question I've been incubating for a while.
Is there any way to find out, from the catalogs or in any automatable way,
which types are implemented with a dependence on the database encoding
(or on some encoding)?
You might think S category types, for a start: name, text, character,
varchar, all dependent on the server encoding, as you'd expect. The ones
Tom moves here to category Z were most of the ones I wondered about.
Then there's "char". It's category S, but does not apply the server
encoding. You could call it an 8-bit int type, but it's typically used
as a character, making it well-defined for ASCII values and not so
for others, just like SQL_ASCII encoding. You could as well say that
the "char" type has a defined encoding of SQL_ASCII at all times,
regardless of the database encoding.
U types are a mixed bag. Category U includes bytea (no character encoding)
and xml/json/jsonb (server encoding). Also tied to the server encoding
are cstring and unknown.
As an aside, I think it's unfortunate that the xml type has this implicit
dependency on the server encoding, when XML is by definition Unicode.
It means there are valid XML documents that PostgreSQL may not be able
to store, and which documents those are depends on what the database
encoding is. I think json and jsonb suffer in the same way.
Changing that would be disruptive at this point and I'm not suggesting it,
but there might be value in the thought experiment to see what the
alternate universe would look like.
In the alternate world, you would know that certain datatypes were
inherently encoding-oblivious (numbers, polygons, times, ...), certain
others are bound to the server encoding (text, varchar, name, ...), and
still others are bound to a known encoding other than the server encoding:
the ISO SQL NCHAR type (bound to an alternate configurable database
encoding), "char" (always SQL_ASCII), xml/json/jsonb (always with the full
Unicode repertoire, however they choose to represent it internally).
That last parenthetical reminded me that I'm really talking
about 'repertoire' here, which ISO SQL treats as a separate topic from
'encoding'. Exactly how an xml or jsonb type is represented internally
might be none of my business (unless I am developing a binary-capable
driver), but it's fair to ask what its repertoire is, and whether that's
full Unicode or not, and if not, whether the repertoire changes when some
server setting does.
I also think in that ideal world, or even this one, you could want
some way to query the catalogs to answer that basic question
about some given type.
Am I right that we simply don't have that? I currently answer such questions
by querying the catalog for the type's _send or _recv function name, then
going off to read the code, but that's hard to automate.
Regards,
-Chap
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: Dubious usage of TYPCATEGORY_STRING
@ 2021-12-07 15:48 Peter Eisentraut <[email protected]>
parent: Tom Lane <[email protected]>
2 siblings, 1 reply; 11+ messages in thread
From: Peter Eisentraut @ 2021-12-07 15:48 UTC (permalink / raw)
To: Tom Lane <[email protected]>; [email protected]
On 02.12.21 22:22, Tom Lane wrote:
> My first thought about fixing point 1 was to put "char" into some
> other typcategory, but that turns out to break some of psql's
> catalog queries, with results like:
>
> regression=# \dp
> ERROR: operator is not unique: unknown || "char"
> LINE 16: E' (' || polcmd || E'):'
> ^
> HINT: Could not choose a best candidate operator. You might need to add explicit type casts.
Could we add explicit casts (like polcmd::text) here? Or would it break
too much?
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: Dubious usage of TYPCATEGORY_STRING
@ 2021-12-07 15:51 Tom Lane <[email protected]>
parent: Peter Eisentraut <[email protected]>
0 siblings, 1 reply; 11+ messages in thread
From: Tom Lane @ 2021-12-07 15:51 UTC (permalink / raw)
To: Peter Eisentraut <[email protected]>; +Cc: [email protected]
Peter Eisentraut <[email protected]> writes:
> On 02.12.21 22:22, Tom Lane wrote:
>> My first thought about fixing point 1 was to put "char" into some
>> other typcategory, but that turns out to break some of psql's
>> catalog queries, with results like:
>>
>> regression=# \dp
>> ERROR: operator is not unique: unknown || "char"
>> LINE 16: E' (' || polcmd || E'):'
>> ^
>> HINT: Could not choose a best candidate operator. You might need to add explicit type casts.
> Could we add explicit casts (like polcmd::text) here? Or would it break
> too much?
I assumed it'd break too much to consider doing that. But I suppose
that since a typcategory change would be initdb-forcing anyway, maybe
it's not out of the question. I'll investigate and see exactly how
many places would need an explicit cast.
regards, tom lane
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: types reliant on encodings [was Re: Dubious usage of TYPCATEGORY_STRING]
@ 2021-12-07 15:52 Peter Eisentraut <[email protected]>
parent: Chapman Flack <[email protected]>
0 siblings, 0 replies; 11+ messages in thread
From: Peter Eisentraut @ 2021-12-07 15:52 UTC (permalink / raw)
To: Chapman Flack <[email protected]>; Tom Lane <[email protected]>; [email protected]
On 03.12.21 19:42, Chapman Flack wrote:
> Is there any way to find out, from the catalogs or in any automatable way,
> which types are implemented with a dependence on the database encoding
> (or on some encoding)?
What is this needed for? C code can internally do whatever it wants,
and the database encoding is effectively a constant, so there is no need
for server-side code to be very much concerned about whether types do this.
Also, "types" is perhaps the wrong subject here. Types only contain
input and output functions and a few more bits. Additional functions
operating on the type could look at the server encoding without the type
and its core functions knowing about it.
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: Dubious usage of TYPCATEGORY_STRING
@ 2021-12-07 15:59 Robert Haas <[email protected]>
parent: Tom Lane <[email protected]>
2 siblings, 1 reply; 11+ messages in thread
From: Robert Haas @ 2021-12-07 15:59 UTC (permalink / raw)
To: Tom Lane <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>
On Thu, Dec 2, 2021 at 4:22 PM Tom Lane <[email protected]> wrote:
> An example of the reasons not to treat these types as being
> general-purpose strings can be seen at [1], where the "char"
> type has acquired some never-intended cast behaviors. Taking
> that to an extreme, we currently accept
>
> regression=# select '(1,2)'::point::"char";
> char
> ------
> (
> (1 row)
What's wrong with that?
--
Robert Haas
EDB: http://www.enterprisedb.com
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: Dubious usage of TYPCATEGORY_STRING
@ 2021-12-07 17:19 Tom Lane <[email protected]>
parent: Robert Haas <[email protected]>
0 siblings, 1 reply; 11+ messages in thread
From: Tom Lane @ 2021-12-07 17:19 UTC (permalink / raw)
To: Robert Haas <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>
Robert Haas <[email protected]> writes:
> On Thu, Dec 2, 2021 at 4:22 PM Tom Lane <[email protected]> wrote:
>> An example of the reasons not to treat these types as being
>> general-purpose strings can be seen at [1], where the "char"
>> type has acquired some never-intended cast behaviors. Taking
>> that to an extreme, we currently accept
>>
>> regression=# select '(1,2)'::point::"char";
>> char
>> ------
>> (
>> (1 row)
> What's wrong with that?
Well, we don't allow things like
regression=# select '(1,2)'::point::float8;
ERROR: cannot cast type point to double precision
LINE 1: select '(1,2)'::point::float8;
^
It's not very clear to me why "char" should get a pass on that.
We allow such cases when the target is text/varchar/etc, but
the assumption is that the textual representation is sufficient
for your purposes. It's hard to claim that just the first
byte is a useful textual representation.
Worse, PG is actually treating this as an assignment-level cast,
so we accept this:
regression=# create table t(f1 "char");
CREATE TABLE
regression=# insert into t values ('(1,2)'::point);
INSERT 0 1
regression=# table t;
f1
----
(
(1 row)
I definitely don't think that should have worked without
any complaint.
regards, tom lane
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: Dubious usage of TYPCATEGORY_STRING
@ 2021-12-07 18:04 Robert Haas <[email protected]>
parent: Tom Lane <[email protected]>
0 siblings, 0 replies; 11+ messages in thread
From: Robert Haas @ 2021-12-07 18:04 UTC (permalink / raw)
To: Tom Lane <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>
On Tue, Dec 7, 2021 at 12:19 PM Tom Lane <[email protected]> wrote:
> > What's wrong with that?
>
> Well, we don't allow things like
>
> regression=# select '(1,2)'::point::float8;
> ERROR: cannot cast type point to double precision
> LINE 1: select '(1,2)'::point::float8;
> ^
>
> It's not very clear to me why "char" should get a pass on that.
> We allow such cases when the target is text/varchar/etc, but
> the assumption is that the textual representation is sufficient
> for your purposes. It's hard to claim that just the first
> byte is a useful textual representation.
Fair enough, I guess. I am pretty skeptical of the merits of refusing
an explicit cast. If I ran the zoo, I would probably choose to allow
all such casts and make them coerce via IO when no other pathway is
available. But I get that's not our policy.
> Worse, PG is actually treating this as an assignment-level cast,
> so we accept this:
>
> regression=# create table t(f1 "char");
> CREATE TABLE
> regression=# insert into t values ('(1,2)'::point);
> INSERT 0 1
> regression=# table t;
> f1
> ----
> (
> (1 row)
>
> I definitely don't think that should have worked without
> any complaint.
Yes, that one's a bridge too far, even for me.
--
Robert Haas
EDB: http://www.enterprisedb.com
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: Dubious usage of TYPCATEGORY_STRING
@ 2021-12-07 20:24 Tom Lane <[email protected]>
parent: Tom Lane <[email protected]>
0 siblings, 1 reply; 11+ messages in thread
From: Tom Lane @ 2021-12-07 20:24 UTC (permalink / raw)
To: Peter Eisentraut <[email protected]>; +Cc: [email protected]
I wrote:
> Peter Eisentraut <[email protected]> writes:
>> Could we add explicit casts (like polcmd::text) here? Or would it break
>> too much?
> I assumed it'd break too much to consider doing that. But I suppose
> that since a typcategory change would be initdb-forcing anyway, maybe
> it's not out of the question. I'll investigate and see exactly how
> many places would need an explicit cast.
Um, I definitely gave up too easily there. The one usage in \dp
seems to be the *only* thing that breaks in describe.c, and pg_dump
doesn't need any changes so far as check-world reveals. So let's
just move "char" to another category, as attached.
regards, tom lane
Attachments:
[text/x-diff] 0001-dont-put-special-purpose-types-in-string-category-2.patch (8.2K, ../../[email protected]/2-0001-dont-put-special-purpose-types-in-string-category-2.patch)
download | inline diff:
diff --git a/contrib/citext/expected/citext.out b/contrib/citext/expected/citext.out
index ec99aaed5d..3bac0534fb 100644
--- a/contrib/citext/expected/citext.out
+++ b/contrib/citext/expected/citext.out
@@ -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);
diff --git a/contrib/citext/expected/citext_1.out b/contrib/citext/expected/citext_1.out
index 75fd08b7cc..57fc863f7a 100644
--- a/contrib/citext/expected/citext_1.out
+++ b/contrib/citext/expected/citext_1.out
@@ -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);
diff --git a/contrib/citext/sql/citext.sql b/contrib/citext/sql/citext.sql
index 10232f5a9f..55fb1d11a6 100644
--- a/contrib/citext/sql/citext.sql
+++ b/contrib/citext/sql/citext.sql
@@ -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);
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index c1d11be73f..216aa4510d 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -9305,6 +9305,10 @@ SCRAM-SHA-256$<replaceable><iteration count></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>
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index ea721d963a..72d8547628 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -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"
diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat
index 41074c994b..f3d94f3cf5 100644
--- a/src/include/catalog/pg_type.dat
+++ b/src/include/catalog/pg_type.dat
@@ -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',
@@ -145,24 +145,24 @@
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' },
@@ -681,13 +681,13 @@
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',
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index e568e21dee..5e891a0596 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -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) */
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: Dubious usage of TYPCATEGORY_STRING
@ 2021-12-09 15:27 Peter Eisentraut <[email protected]>
parent: Tom Lane <[email protected]>
0 siblings, 1 reply; 11+ messages in thread
From: Peter Eisentraut @ 2021-12-09 15:27 UTC (permalink / raw)
To: Tom Lane <[email protected]>; +Cc: [email protected]
On 07.12.21 21:24, Tom Lane wrote:
> I wrote:
>> Peter Eisentraut<[email protected]> writes:
>>> Could we add explicit casts (like polcmd::text) here? Or would it break
>>> too much?
>> I assumed it'd break too much to consider doing that. But I suppose
>> that since a typcategory change would be initdb-forcing anyway, maybe
>> it's not out of the question. I'll investigate and see exactly how
>> many places would need an explicit cast.
> Um, I definitely gave up too easily there. The one usage in \dp
> seems to be the*only* thing that breaks in describe.c, and pg_dump
> doesn't need any changes so far as check-world reveals. So let's
> just move "char" to another category, as attached.
Looks good to me.
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: Dubious usage of TYPCATEGORY_STRING
@ 2021-12-11 19:12 Tom Lane <[email protected]>
parent: Peter Eisentraut <[email protected]>
0 siblings, 0 replies; 11+ messages in thread
From: Tom Lane @ 2021-12-11 19:12 UTC (permalink / raw)
To: Peter Eisentraut <[email protected]>; +Cc: [email protected]
Peter Eisentraut <[email protected]> writes:
> On 07.12.21 21:24, Tom Lane wrote:
>> Um, I definitely gave up too easily there. The one usage in \dp
>> seems to be the*only* thing that breaks in describe.c, and pg_dump
>> doesn't need any changes so far as check-world reveals. So let's
>> just move "char" to another category, as attached.
> Looks good to me.
Pushed, thanks for reviewing.
regards, tom lane
^ permalink raw reply [nested|flat] 11+ messages in thread
end of thread, other threads:[~2021-12-11 19:12 UTC | newest]
Thread overview: 11+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2021-12-02 21:22 Dubious usage of TYPCATEGORY_STRING Tom Lane <[email protected]>
2021-12-03 18:42 ` types reliant on encodings [was Re: Dubious usage of TYPCATEGORY_STRING] Chapman Flack <[email protected]>
2021-12-07 15:52 ` Re: types reliant on encodings [was Re: Dubious usage of TYPCATEGORY_STRING] Peter Eisentraut <[email protected]>
2021-12-07 15:48 ` Peter Eisentraut <[email protected]>
2021-12-07 15:51 ` Tom Lane <[email protected]>
2021-12-07 20:24 ` Tom Lane <[email protected]>
2021-12-09 15:27 ` Peter Eisentraut <[email protected]>
2021-12-11 19:12 ` Tom Lane <[email protected]>
2021-12-07 15:59 ` Robert Haas <[email protected]>
2021-12-07 17:19 ` Tom Lane <[email protected]>
2021-12-07 18:04 ` Robert Haas <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox