On Tue, Jan 16, 2024 at 11:46 AM jian he <jian.universal...@gmail.com> wrote: > > > I think the reason is maybe related to the function copy_dest_startup. I was wrong about this sentence.
in the function CopyOneRowTo `if (!cstate->opts.json_mode)` else branch change to the following: else { Datum rowdata; StringInfo result; if (slot->tts_tupleDescriptor->natts == 1) { /* Flat-copy the attribute array */ memcpy(TupleDescAttr(slot->tts_tupleDescriptor, 0), TupleDescAttr(cstate->queryDesc->tupDesc, 0), 1 * sizeof(FormData_pg_attribute)); } BlessTupleDesc(slot->tts_tupleDescriptor); rowdata = ExecFetchSlotHeapTupleDatum(slot); result = makeStringInfo(); composite_to_json(rowdata, result, false); if (json_row_delim_needed && cstate->opts.force_array) { CopySendChar(cstate, ','); } else if (cstate->opts.force_array) { /* first row needs no delimiter */ CopySendChar(cstate, ' '); json_row_delim_needed = true; } CopySendData(cstate, result->data, result->len); } all the cases work, more like a hack. because I cannot fully explain it to you why it works. ------------------------------------------------------------------------------- demo drop function if exists execute_into_test cascade; NOTICE: function execute_into_test() does not exist, skipping DROP FUNCTION drop type if exists execute_into_test cascade; NOTICE: type "execute_into_test" does not exist, skipping DROP TYPE create type eitype as (i integer, y integer); CREATE TYPE create or replace function execute_into_test() returns eitype as $$ declare _v eitype; begin execute 'select 1,2' into _v; return _v; end; $$ language plpgsql; CREATE FUNCTION COPY (SELECT 1 from generate_series(1,1) g) TO stdout WITH (format json); {"?column?":1} COPY (SELECT g from generate_series(1,1) g) TO stdout WITH (format json); {"g":1} COPY (SELECT g,1 from generate_series(1,1) g) TO stdout WITH (format json); {"g":1,"?column?":1} COPY (select * from execute_into_test()) TO stdout WITH (format json); {"i":1,"y":2} COPY (select * from execute_into_test() sub) TO stdout WITH (format json); {"i":1,"y":2} COPY (select sub from execute_into_test() sub) TO stdout WITH (format json); {"sub":{"i":1,"y":2}} COPY (select sub.i from execute_into_test() sub) TO stdout WITH (format json); {"i":1} COPY (select sub.y from execute_into_test() sub) TO stdout WITH (format json); {"y":2} COPY (VALUES (1), (2)) TO stdout WITH (format json); {"column1":1} {"column1":2} COPY (SELECT 1 UNION ALL SELECT 2) TO stdout WITH (format json); {"?column?":1} {"?column?":2}