BUG #19824: OMIT QUOTES breaks non-string results: array / composite / array-domain coercions in JSON_QUERY / JS

From: PG Bug reporting form <noreply(at)postgresql(dot)org>
To: pgsql-bugs(at)lists(dot)postgresql(dot)org
Cc: 303677365(at)qq(dot)com
Subject: BUG #19824: OMIT QUOTES breaks non-string results: array / composite / array-domain coercions in JSON_QUERY / JS
Date: 2026-11-01 08:07:24
Message-ID: 19824-6b112e27c335304a@postgresql.org
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

The following bug has been logged on the website:

Bug reference: 19824
Logged by: chunling qin
Email address: 303677365(at)qq(dot)com
PostgreSQL version: 18.6
Operating system: Linux (TencentOS 4.4, x86_64)
Description:

Hello,

Per the documentation, OMIT QUOTES only affects scalar *string* results.
In practice the flag is applied to non-scalar results as well, so
coercions to array / composite types break. Two shapes of damage:
with ERROR ON ERROR the statement fails with a "malformed literal"
error; with the default NULL ON ERROR the value silently becomes NULL.

Reproducer (self-contained, on 18.6 and on 20devel):

CREATE TYPE comp AS (a int, b int);
CREATE DOMAIN d_arr AS int[];
CREATE DOMAIN dcomp3 AS comp CHECK ((VALUE).a > 0);

-- the same query, three quote modes -- only OMIT QUOTES breaks:
SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING int[] KEEP QUOTES ERROR
ON ERROR); -- {1,2}
SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING int[] ERROR
ON ERROR); -- {1,2}
SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING int[] OMIT QUOTES ERROR
ON ERROR);
-- ERROR: malformed array literal: "[1, 2]"
SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING int[] OMIT QUOTES);
-- (NULL) <- silently dropped under the default NULL ON ERROR

-- domains over arrays, composites, and domain-over-composite likewise:
SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING d_arr OMIT QUOTES ERROR
ON ERROR);
-- ERROR: malformed array literal
SELECT JSON_QUERY(jsonb '{"a":1,"b":2}', '$' RETURNING comp OMIT QUOTES
ERROR ON ERROR);
-- ERROR: malformed record literal: "{"a": 1, "b": 2}"
SELECT JSON_QUERY(jsonb '{"a":1,"b":2}', '$' RETURNING dcomp3 OMIT
QUOTES ERROR ON ERROR);
-- ERROR: malformed record literal

-- JSON_TABLE columns behave identically:
SELECT * FROM JSON_TABLE(jsonb '[1,2]', '$' COLUMNS (x int[] PATH '$'));
-- {1,2}
SELECT * FROM JSON_TABLE(jsonb '[1,2]', '$' COLUMNS (x int[] PATH '$'
OMIT QUOTES)); -- NULL

Expected: OMIT QUOTES should only strip quotes from scalar strings; for
array / object results it should be a no-op, so "OMIT QUOTES" must agree
with "KEEP QUOTES" and with the default ({1,2}, (1,2), ...).

Actual: every non-string target type (int[], text[], int[][], domains
over arrays, composite types, domains over composites) either fails with
a malformed-literal error or silently loses the value. The silent-NULL
shape also corrupts filtering: "WHERE <the extracted column> ..." then
returns the wrong row set (verified separately).

Root cause pointers: json_populate_type()
(src/backend/utils/adt/jsonfuncs.c, around lines 3386-3396) applies
JsonbUnquote() (src/backend/utils/adt/jsonb.c:2028) to non-scalars too;
transformJsonFuncExpr() (src/backend/parser/parse_expr.c:4675) sets the
flag based solely on "quotes == JS_QUOTES_OMIT".

Reproduced on:
- PostgreSQL 18.6 (REL_18_STABLE, self-built, snapshot 2026-10-26)
- PostgreSQL 20devel (snapshot of 2026-10-29)

Regards,
Chunling Qin

Browse pgsql-bugs by date

  From Date Subject
Next Message Nidal FAKIH 2026-11-01 09:27:43 Wrong result: count(DISTINCT x COLLATE "C") with GROUP BY x on a nondeterministic collation
Previous Message PG Bug reporting form 2026-11-01 08:06:12 BUG #19823: JSON_VALUE(... RETURNING jsonb) silently returns NULL for PASSING values of NaN / Infinity; the expo