Hi Jian, Manu,

v3 with Manu's diff fixes my case, and all tests pass.

float8out is STABLE on master now, but v3 still lists FLOAT4OID
and FLOAT8OID as immutable. So this is accepted:

  CREATE INDEX ON tf ((json_array(f returning jsonb)));  -- f float8

and gives wrong results after SET extra_float_digits = 0. Dropping
those two case labels fixes it on master and changes nothing on 19.

Thanks,
Shihao

On Thu, Oct 22, 2026 at 11:51 AM Manu <[email protected]> wrote:

> Hi Jian,
>
> On Thu, Oct 22, 2026 at 9:12 PM jian he
> <[email protected]> wrote:
> > The attached patch should resolve these issues.
>
> It does. v3 applies cleanly to master and REL_19_STABLE, and make
> check passes. Every case from my earlier matrix is now rejected at
> CREATE INDEX, as in 18: ADD / RENAME / DROP ATTRIBUTE, the table
> rowtype, nested composites, domains over composites, arrays of
> composites, JSON_OBJECT, RETURNING json, and the unique, partial,
> generated column and partition key forms. Anonymous ROW(), record[]
> and JSON_SCALAR are rejected too.
>
> One case still gets through, in the range branch. A range is printed
> by range_out, which calls the subtype's output function and never a
> cast to json. But when the range has no cast of its own,
> json_check_mutability() recurses into the subtype and judges the
> subtype's cast to json instead. So an immutable cast on an enum makes
> a range over that enum look immutable, while what actually prints it
> is enum_out:
>
>   CREATE TYPE e AS ENUM ('a', 'b');
>   CREATE FUNCTION e_json(e) RETURNS json IMMUTABLE LANGUAGE sql
>     AS $$ SELECT '"x"'::json $$;
>   CREATE CAST (e AS json) WITH FUNCTION e_json(e);
>   CREATE TYPE er AS RANGE (subtype = e);
>   CREATE TABLE t (v er);
>   INSERT INTO t VALUES (er('a', 'b'));
>   CREATE INDEX t_i ON t ((json_array(v returning jsonb)));
>   ALTER TYPE e RENAME VALUE 'a' TO 'z';
>   SELECT count(*) FROM t
>     WHERE json_array(v returning jsonb) =
>           json_array(er('z', 'b') returning jsonb);
>
> The index scan returns 0 and a seq scan returns 1; REINDEX restores 1.
> Without the cast on the enum the CREATE INDEX is rejected, and 18
> rejects it either way. The multirange behaves the same. Master has
> this without v3 as well.
>
> The attached diff, on top of v3, stops looking up casts once the
> recursion is below a range or multirange. With it both cases are
> rejected, nothing else in my matrix changes (int4range is still
> accepted), and make check passes. It's named .txt so it doesn't
> disturb the CF bot; feel free to fold it into v4 if you agree.
>
> regards,
> Manu
>

Reply via email to