Logical replication fails when partition column order differs from parent

From: Вадим Ковтун <kovtunvadim(at)gmail(dot)com>
To: pgsql-bugs(at)lists(dot)postgresql(dot)org
Subject: Logical replication fails when partition column order differs from parent
Date: 2025-10-13 12:07:03
Message-ID: CAHb3yJOPoSsXV6UCpjT5rRDUeJvDNBX+U3hsKdetBkC9v8Q26A@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

This issue occurs regardless of the publish_via_partition_root=true

*Description:*
PostgreSQL allows partitions to have a different column ordinal_position
than their parent table. PostgreSQL itself handles this correctly
internally. However, when using *logical replication* (e.g., pgoutput),
some replication clients assume partitions share the same column order as
the parent. This can lead to incorrect value-to-column mapping and runtime
errors on the subscriber side.

*Does it reproduce on the most recent release?*
Yes, PostgreSQL 18

*Steps to Reproduce (PostgreSQL logical replication):*

1.

Create a table that will become a partition (columns ordered ip_state
before http_code):

CREATE TABLE payment.payment_orders_partition_test (
id BIGSERIAL,
at DATE NOT NULL,
ip_state VARCHAR(10),
http_code INT,
PRIMARY KEY (id, at)
);
INSERT INTO payment.payment_orders_partition_test (id, at, ip_state,
http_code)VALUES (1, '2025-01-01', 'AI', 5);

2.

Create a parent partitioned table with a different column order (
http_code before ip_state):

CREATE TABLE payment.payment_orders_test (
id BIGSERIAL,
at DATE NOT NULL,
http_code INT,
ip_state VARCHAR(10),
PRIMARY KEY (id, at)
) PARTITION BY RANGE (at);

3.

Attach the existing table as a partition:

ALTER TABLE payment.payment_orders_test
ATTACH PARTITION payment.payment_orders_partition_testFOR VALUES FROM
('2025-01-01') TO ('2025-12-31');

4.

Insert another row into the partition:

INSERT INTO payment.payment_orders_partition_test (id, at, ip_state,
http_code)VALUES (6, '2025-01-01', 'IA', 5);

*Diagnostic Query (compare parent vs partition column order):*

WITH parent AS (
SELECT ordinal_position, column_name, data_type
FROM information_schema.columns
WHERE table_schema = 'payment' AND table_name = 'payment_orders_test'
),
part AS (
SELECT ordinal_position, column_name, data_type
FROM information_schema.columns
WHERE table_schema = 'payment' AND table_name =
'payment_orders_partition_test'
)SELECT p.ordinal_position AS parent_pos,
p.column_name AS parent_col,
p.data_type AS parent_type,
c.ordinal_position AS part_pos,
c.column_name AS part_col,
c.data_type AS part_typeFROM parent pFULL JOIN part c ON
p.ordinal_position = c.ordinal_positionWHERE
COALESCE(p.column_name,'') <> COALESCE(c.column_name,'')ORDER BY
parent_pos;

Browse pgsql-bugs by date

  From Date Subject
Next Message PG Bug reporting form 2025-10-13 12:18:21 BUG #19083: Foreign inner join is the case for char() keys but not for varchar()
Previous Message Etsuro Fujita 2025-10-12 18:05:58 Re: TRAP: failed Assert("outerPlan != NULL") in postgres_fdw.c