| From: | Hironobu SUZUKI <hironobu(at)interdb(dot)jp> |
|---|---|
| To: | pgsql-bugs(at)lists(dot)postgresql(dot)org |
| Subject: | EXPLAIN (ANALYZE, FORMAT JSON) emits invalid output for MERGE on a partitioned table |
| Date: | 2026-11-06 10:39:16 |
| Message-ID: | 7992298c-6f88-4784-bef7-94a860e3a706@interdb.jp |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-bugs |
Hi,
While testing, I noticed that EXPLAIN (ANALYZE, FORMAT JSON) of a MERGE
whose target is a partitioned table produces syntactically invalid JSON.
The MERGE tuple counters ("Tuples Inserted", etc.) are emitted inside
the "Target Tables" array, so a bare "key": value pair appears inside a
JSON array.
Reproducer:
CREATE TABLE t (id int) PARTITION BY RANGE (id);
CREATE TABLE t1 PARTITION OF t DEFAULT;
EXPLAIN (ANALYZE, FORMAT JSON)
MERGE INTO t USING (VALUES (1)) s(id) ON t.id = s.id
WHEN NOT MATCHED THEN INSERT VALUES (s.id);
Actual output (excerpt):
"Target Tables": [
{
"Relation Name": "t1",
"Alias": "t_1"
},
"Tuples Inserted": 1,
"Tuples Updated": 0,
"Tuples Deleted": 0,
"Tuples Skipped": 0
],
This is rejected by JSON parsers. With a non-partitioned target, "Target
Tables" is not emitted (labeltargets is false), so the counters appear
as ordinary properties of the Plan object and the output is valid.
I reproduced this on master (commit edbe7ffdc8), 19rc1, 18.6, 17.11,
16.16 and 15.19; the same code is present in all branches that have MERGE.
(Text format is unaffected.)
Cause:
In show_modifytable_info(), the "Target Tables" group is opened before
the loop over result relations but is only closed at the very end of the
function, after the ON CONFLICT and MERGE properties have been emitted.
Those properties belong to the ModifyTable node itself, not to the list
of target tables.
Patch:
The attached patch (against master) closes the "Target Tables" group
right after the loop over the target relations. With it, the output for
the same query becomes:
"Target Tables": [
{
"Relation Name": "t1",
"Alias": "t_1"
}
],
"Tuples Inserted": 1,
"Tuples Updated": 0,
"Tuples Deleted": 0,
"Tuples Skipped": 0,
I tested the patch on master, 19rc1, 18.6, 17.11, 16.16 and 15.19. It
applies to all of them with git apply without modification, the JSON
output of the reproducer is valid with it, and make check passes on each.
Since the same code is present in all of these branches, a back-patch
seems appropriate.
Regards,
Hironobu Suzuki
| Attachment | Content-Type | Size |
|---|---|---|
| v1-0001-Fix-EXPLAIN-output-of-MERGE-on-partitioned-tables.patch | text/plain | 1.9 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Fujii Masao | 2026-11-06 14:41:26 | Re: first_value()/nth_value() with IGNORE NULLS loop forever (EXCLUDE GROUP/TIES, frame past partition end, no ORDER BY) |
| Previous Message | Ayush Tiwari | 2026-11-06 09:56:46 | Re: BUG #19603: Vuln47: distance_taxicab and distance_chebyshev silently return 0 instead of NaN when a cube coordin |