Re: [MASSMAIL] pg_stat_statements replaces SQL/JSON ON EMPTY / ON ERROR keywords with parameters

From: Staroverov Ilja <i(dot)staroverov(at)ftdata(dot)ru>
To: "pgsql-bugs(at)lists(dot)postgresql(dot)org" <pgsql-bugs(at)lists(dot)postgresql(dot)org>
Subject: Re: [MASSMAIL] pg_stat_statements replaces SQL/JSON ON EMPTY / ON ERROR keywords with parameters
Date: 2026-10-16 13:18:39
Message-ID: DFE8E2CE-7A51-447C-B600-7D3979E38F1B@localhost.localdomain
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

Hi,

While testing the above, I noticed a related and more serious problem:
apart from the number of columns, the column definitions of a
JSON_TABLE are not part of the query ID at all. On 18.6, these get the
same query ID, so pg_stat_statements merges them into one entry:

SELECT * FROM JSON_TABLE(jsonb '[{"a":1}]', '$[*]'
COLUMNS (a int PATH '$.a')) jt;
SELECT * FROM JSON_TABLE(jsonb '[{"a":1}]', '$[*]'
COLUMNS (a text PATH '$.a')) jt;
SELECT * FROM JSON_TABLE(jsonb '[{"a":1}]', '$[*]'
COLUMNS (a int PATH '$.b' DEFAULT 0 ON EMPTY)) jt;
SELECT * FROM JSON_TABLE(jsonb '[{"a":1}]', '$[*]'
COLUMNS (a int PATH '$.b' ERROR ON EMPTY)) jt;

The same goes for nested columns, and on master for the PLAN clause:
PLAN (p0 OUTER p1) and PLAN (p0 INNER p1) get the same query ID,
although they return different rows. The pg_stat_statements
documentation says that merging is expected for semantically
equivalent queries, which these are not. Also, the column paths of the
merged queries may differ, but the entry shows the literal paths of the
first one rather than parameter symbols.

The cause is that TableFunc.colvalexprs and TableFunc.plan, which hold
the column definitions and the NESTED PATH structure of a JSON_TABLE,
are marked query_jumble_ignore, like the other TableFunc fields that
query jumbling has always ignored for XMLTABLE. But for XMLTABLE, at
least the column expressions (colexprs) are jumbled, while JSON_TABLE
doesn't use colexprs, so nothing about its columns is.

The attached 0002 removes query_jumble_ignore from these two fields.
Column paths and other literals are still constants, so queries that
differ only in those are still merged, and they are now shown as
parameter symbols. For that, it also gives the Const for a NESTED PATH
expression the location of its literal, as column paths already have.
Note that column names become part of the query ID too, since
JsonExpr.column_name is jumbled, much like table aliases already are.
It adds a pg_stat_statements test, which fails without the fix.

0002 depends on 0001, which is unchanged from v1: once the column
definitions are jumbled, the behavior Consts of the columns would
otherwise show up as parameter symbols too, e.g. "NULL ON EMPTY" would
become "$4 ON EMPTY".

Unlike 0001, 0002 changes the query IDs of JSON_TABLE queries, so it
can't go into 17 or 18. But v19 is not released yet, so perhaps it can
still go there as well as master; the series applies to REL_19_STABLE,
and I've tested it there too.

XMLTABLE has a similar, but long-standing, issue: column types and
DEFAULT expressions have never been part of the query ID, so XMLTABLE
queries that differ only in column types are merged too. I left that
alone, since it's the original behavior, but I can add it to 0002 if
that's wanted for master.

--
Ilya Staroverov

Attachment Content-Type Size
v2-0001-Don-t-give-the-SQL-JSON-behavior-constants-a-loca.patch application/octet-stream 6.3 KB
v2-0002-Include-JSON_TABLE-column-definitions-in-query-ju.patch application/octet-stream 6.6 KB

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message George MacKerron 2026-10-16 14:35:33 Inconsistency in psql output with \d+x PATTERN
Previous Message Tender Wang 2026-10-16 13:11:03 Re: BUG #19765: Wrong result from a chain of LEFT JOINs since v16