Fix bug of COPY TO support partition table

From: Chao Li <li(dot)evan(dot)chao(at)gmail(dot)com>
To: PostgreSQL-development <pgsql-hackers(at)postgresql(dot)org>
Cc: Masahiko Sawada <sawada(dot)mshk(at)gmail(dot)com>, jian he <jian(dot)universality(at)gmail(dot)com>
Subject: Fix bug of COPY TO support partition table
Date: 2026-05-14 09:59:46
Message-ID: 85EA70F3-C3DB-477B-B856-EA569FDAAE7C@gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

I just tested the "Support COPY TO for partitioned tables" patch. While tracing a normal case, I noticed this suspicious code:
```
/*
* If we are exporting partition data here, we check if converting tuples
* to the root table's rowtype, because a partition might have column
* order different than its root table.
*/
if (root_rel != NULL)
{
root_slot = table_slot_create(root_rel, NULL);
map = build_attrmap_by_name_if_req(RelationGetDescr(root_rel), <<== input is root table
RelationGetDescr(rel), <== output is partition
false);
}

while (table_scan_getnextslot(scandesc, ForwardScanDirection, slot))
{
TupleTableSlot *copyslot;

CHECK_FOR_INTERRUPTS();

if (map != NULL)
copyslot = execute_attr_map_slot(map, slot, root_slot); <== input is partition, output is root table
else
{
/* Deconstruct the tuple */
slot_getallattrs(slot);
copyslot = slot;
}
```

The code comment says that partition tuples should be converted to the root table's rowtype before output. Also, `execute_attr_map_slot()` takes the partition slot as input and the root slot as output. However, the attribute map is built in the opposite direction, with the root relation as input and the partition relation as output.

In normal cases, partitions have the same attribute list as the root table, so this bug is not triggered. I built the following repro by dropping a column from the partition, which makes the partition’s physical tuple descriptor different from the root table's descriptor:
```
evantest=# create table p (a int, b int) partition by range (a);
CREATE TABLE
evantest=# create table c (x int, a int, b int);
CREATE TABLE
evantest=# alter table c drop column x;
ALTER TABLE
evantest=# alter table p attach partition c for values from (1) to (10);
ALTER TABLE
evantest=# insert into p values (1, 11), (2, 22);
INSERT 0 2
evantest=# copy p to stdout;
\N \N
\N \N
```

As shown above, COPY incorrectly outputs all NULLs.

The fix is straightforward, just reverse the order of `rel` and `root_rel` when calling `build_attrmap_by_name_if_req()`. After the fix, COPY works correctly:
```
evantest=# copy p to stdout;
1 11
2 22
```

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

Attachment Content-Type Size
v1-0001-Fix-COPY-TO-attribute-mapping-for-partitioned-tab.patch application/octet-stream 3.1 KB

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Nitin Motiani 2026-05-14 10:09:09 Re: Adding pg_dump flag for parallel export to pipes
Previous Message shveta malik 2026-05-14 09:25:27 Re: Proposal: Conflict log history table for Logical Replication