From 4ff66eb7870ee3de1809083eeb14c4adad2dc4b1 Mon Sep 17 00:00:00 2001 From: shihao zhong Date: Mon, 5 Oct 2026 11:44:08 -0400 Subject: [PATCH v1 1/2] Fix JSON keys of COPY (query) TO with FORMAT json CopyToJsonOneRow() passed the slot through with its own row type unless that was RECORD. A scan that does not project returns the table's row type, so the keys were the table's column names, not the query's. Always form the tuple with the query's descriptor. --- src/backend/commands/copyto.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c index 5850608a3fb..992592b1868 100644 --- a/src/backend/commands/copyto.c +++ b/src/backend/commands/copyto.c @@ -398,10 +398,11 @@ CopyToJsonOneRow(CopyToState cstate, TupleTableSlot *slot) * Full table or query without column list. For queries, the slot's * TupleDesc may carry RECORDOID, which is not registered in the type * cache and would cause composite_to_json's lookup_rowtype_tupdesc - * call to fail. Build a HeapTuple stamped with the blessed - * descriptor so the type can be looked up correctly. + * call to fail, or the row type of a scanned table, whose column + * names can differ from the query's. Always build a HeapTuple + * stamped with the blessed descriptor. */ - if (!cstate->rel && slot->tts_tupleDescriptor->tdtypeid == RECORDOID) + if (!cstate->rel) { HeapTuple tup = heap_form_tuple(cstate->tupDesc, slot->tts_values, -- 2.37.1 (Apple Git-137.1)