From fa48e39526b8d1cdc5b6e86074d6a3149fbd059b Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Tue, 8 Sep 2026 11:12:36 -0700 Subject: [PATCH] Fix tablesync failure for partitioned tables on older publishers. Commit 266543a made initial table synchronization use "COPY table TO" for a partitioned table, but decided that from the relation kind alone. A partitioned table is only accepted there since v19, so a v19 subscriber replicating from an older publisher with publish_via_partition_root failed at table sync. Check the publisher version, and fall back to the "COPY (SELECT ...) TO" variant otherwise. Backpatch to v19, where 266543a changed the initial table synchronization. Reported-by: Noah Misch Reviewed-by: Noah Misch Discussion: https://postgr.es/m/20260905040020.57.noahmisch@microsoft.com Backpatch-through: 19 --- src/backend/replication/logical/tablesync.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c index e5101997cd3..4015e861a64 100644 --- a/src/backend/replication/logical/tablesync.c +++ b/src/backend/replication/logical/tablesync.c @@ -1084,6 +1084,7 @@ copy_table(Relation rel) ParseState *pstate; List *options = NIL; bool gencol_published = false; + int server_version = walrcv_server_version(LogRepWorkerWalRcvConn); /* Get the publisher relation info. */ fetch_remote_table_info(get_namespace_name(RelationGetNamespace(rel)), @@ -1100,9 +1101,14 @@ copy_table(Relation rel) /* Start copy on the publisher. */ initStringInfo(&cmd); - /* Regular or partitioned table with no row filter or generated columns */ - if ((lrel.relkind == RELKIND_RELATION || lrel.relkind == RELKIND_PARTITIONED_TABLE) - && qual == NIL && !gencol_published) + /* + * Regular or partitioned table with no row filter or generated columns. + * + * "COPY table TO" on a partitioned table is supported since v19. + */ + if ((lrel.relkind == RELKIND_RELATION || + (lrel.relkind == RELKIND_PARTITIONED_TABLE && server_version >= 190000)) && + qual == NIL && !gencol_published) { appendStringInfo(&cmd, "COPY %s", quote_qualified_identifier(lrel.nspname, lrel.relname)); @@ -1182,8 +1188,7 @@ copy_table(Relation rel) * Prior to v16, initial table synchronization will use text format even * if the binary option is enabled for a subscription. */ - if (walrcv_server_version(LogRepWorkerWalRcvConn) >= 160000 && - MySubscription->binary) + if (server_version >= 160000 && MySubscription->binary) { appendStringInfoString(&cmd, " WITH (FORMAT binary)"); options = list_make1(makeDefElem("format",