| From: | Manu <manuelreyesbravo(at)gmail(dot)com> |
|---|---|
| To: | jian he <jian(dot)universality(at)gmail(dot)com> |
| Cc: | shihao zhong <zhong950419(at)gmail(dot)com>, Robert Haas <robertmhaas(at)gmail(dot)com>, pgsql-hackers(at)lists(dot)postgresql(dot)org |
| Subject: | Re: json/jsonb cleanup + FmgrInfo caching |
| Date: | 2026-10-23 23:28:10 |
| Message-ID: | 179279809045.1942440.2176959044031147982@gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi Jian,
On Fri, Oct 23, 2026 at 12:52 PM jian he
<jian(dot)universality(at)gmail(dot)com> wrote:
> user-defined range and multirange types as mutable too. Their conversion uses a
> cast to json function if exists, looked up at runtime, so creating or dropping
> such a cast after CREATE INDEX changes the output.
I tested v4 on master and REL_19_STABLE. It applies cleanly, builds
without warnings, and make check passes on both. My range-over-enum
case is rejected now, and so are your myr demo and shihao's float8 and
float4 case on master. int4range and int4multirange are still
accepted. v4 covers the range case, so my diff from upthread is no
longer needed.
Compared with 18.6, the only indexes in my sweep that v4 rejects and
18 accepts are json_array() over an enum or a user range that has an
IMMUTABLE cast to json, plus float4/float8 on master, where f::text is
already rejected without v4.
One case still gets through, and it is new in 19: an array of a
user-defined base type. 18 rejects every array. 19 recurses into the
element, and for a user-defined element the check still uses the cast
it finds at CREATE INDEX time, so a cast created afterwards changes
the indexed value:
CREATE TYPE mytext;
CREATE FUNCTION mytext_in(cstring) RETURNS mytext
LANGUAGE internal IMMUTABLE STRICT AS 'textin';
CREATE FUNCTION mytext_out(mytext) RETURNS cstring
LANGUAGE internal IMMUTABLE STRICT AS 'textout';
CREATE TYPE mytext (INPUT = mytext_in, OUTPUT = mytext_out,
LIKE = text);
CREATE TABLE t (v mytext[]);
INSERT INTO t VALUES (ARRAY['a']::mytext[]);
CREATE INDEX t_i ON t ((json_array(v returning jsonb)));
CREATE FUNCTION mytext_json(mytext) RETURNS json IMMUTABLE
LANGUAGE sql AS $$ SELECT '"x"'::json $$;
CREATE CAST (mytext AS json) WITH FUNCTION mytext_json(mytext);
SELECT count(*) FROM t
WHERE json_array(v returning jsonb) =
json_array(ARRAY['a']::mytext[] returning jsonb);
The index scan returns 0 and a seq scan returns 1 (REINDEX restores
1) on both branches, with and without v4; 18.6 rejects the index.
Without the array, or through a domain, this is older: 17.11 and 18.6
accept those indexes and return the same wrong count after CREATE CAST
or DROP CAST. Measured with citext, hstore, ltree, cube, isn and seg,
it is the same for contrib types, so marking every user-defined base
type as mutable would reject indexes that work today. That is the
missing dependency on the cast you mentioned; I have a prototype that
records it (DROP CAST then fails without CASCADE, though it can't help
with a cast created later) if it's useful to you.
The attached nocfbot diff treats an array as mutable when its element
is a user-defined base type or a domain over one, the same way user
ranges are treated now. It goes on top of v4 and applies to both
branches. With it the repro is rejected, as in 18; in my sweep only
such arrays change (for those contrib types too, all rejected by 18),
and check-world passes on both.
regards,
Manu
| Attachment | Content-Type | Size |
|---|---|---|
| nocfbot-fix-array-on-v4.diff.txt | text/plain | 896 bytes |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Manu | 2026-10-24 00:19:59 | Re: [PG19] Promotion hangs behind a backend blocked on a stuck client |
| Previous Message | Peter Eisentraut | 2026-10-23 22:15:07 | Re: Add compiler option -fstrict-flex-arrays=1 |