Re: Emitting JSON to file using COPY TO
jian he <jian.universality@gmail.com>
From: jian he <jian.universality@gmail.com>
To: Andrew Dunstan <andrew@dunslane.net>
Cc: Joe Conway <mail@joeconway.com>, Junwang Zhao <zhjwpku@gmail.com>, Florents Tselai <florents.tselai@gmail.com>,
"Andrey M. Borodin" <x4mmm@yandex-team.ru>, Dean Rasheed <dean.a.rasheed@gmail.com>,
Daniel Verite <daniel@manitou-mail.org>, Davin Shearer <davin@apache.org>,
PostgreSQL-development <pgsql-hackers@postgresql.org>
Date: 2026-03-08T16:16:08Z
Lists: pgsql-hackers, pgsql-general
Attachments
- v28-0002-json-format-for-COPY-TO.patch (text/x-patch) patch v28-0002
- v28-0001-introduce-CopyFormat-refactor-CopyFormatOptions.patch (text/x-patch) patch v28-0001
- v28-0003-Add-option-force_array-for-COPY-JSON-FORMAT.patch (text/x-patch) patch v28-0003
- v28-0004-COPY-TO-JSON-support-column-lists.patch (text/x-patch) patch v28-0004
- copyto_json_perfomance_test.nocfbot (application/octet-stream)
hi.
V27-0002 is still not bullet-proof.
drop table if exists t1;
create table t1(a int);
insert into t1 values (1);
copy (select * from t1) to stdout json;
{"a":1}
WARNING: resource was not closed: TupleDesc 0x7171d0ca3440 (18239,-1)
Also see ExecAssignScanProjectionInfo->ExecConditionalAssignProjectionInfo
So in v28-0002, I changed to
+ /*
+ * composite_to_json() requires a stable TupleDesc. Since the slot's
+ * descriptor (slot->tts_tupleDescriptor) can change during the execution
+ * of a SELECT query, we use cstate->queryDesc->tupDesc instead. This
+ * precaution is only necessary when the output slot's TupleDesc is of
+ * type RECORDOID.
+ */
+ if (!cstate->rel && slot->tts_tupleDescriptor->tdtypeid == RECORDOID)
+ slot->tts_tupleDescriptor = cstate->queryDesc->tupDesc;
+ cstate->json_projvalues = (Datum *) palloc(natts * sizeof(Datum));
+ cstate->json_projnulls = (bool *) palloc(natts * sizeof(bool));
I changed it to
+ cstate->json_projvalues = palloc_array(Datum, natts);
+ cstate->json_projnulls = palloc_array(bool, natts);
+ rowdata = HeapTupleHeaderGetDatum(tup->t_data);
I changed it to
+ rowdata = HeapTupleGetDatum(tup);
Patch v28-0004 adds the json_projvalues and json_projnulls pointers to struct
CopyToStateData. I wondered if adding these would slow the COPY TO with TEXT and
CSV format, so I ran a quick test using a 36-column table.
Surprisingly, v28 actually make COPY TO with TEXT and CSV performs a little bit
faster. But I didn't find out why.
You may also try the attached test script: copyto_json_perfomance_test.nocfbot.
--
jian
https://www.enterprisedb.com/
Commits
-
Add option force_array for COPY JSON FORMAT
- 4c0390ac53b7 19 (unreleased) landed
-
json format for COPY TO
- 7dadd38cda95 19 (unreleased) landed
-
introduce CopyFormat, refactor CopyFormatOptions
- a2145605ee3d 19 (unreleased) landed
-
Doc: add IDs to copy.sgml's <varlistentry> and <refsect1>
- e4018f891dec 19 (unreleased) cited
-
Refactor COPY TO to use format callback functions.
- 2e4127b6d2d8 18.0 cited