v2-0001-Preserve-replication-origin-OIDs-in-pg_upgrade.patch
application/octet-stream
Filename: v2-0001-Preserve-replication-origin-OIDs-in-pg_upgrade.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v2-0001
Subject: Preserve replication origin OIDs in pg_upgrade
| File | + | − |
|---|---|---|
| src/backend/commands/subscriptioncmds.c | 8 | 2 |
| src/backend/replication/logical/origin.c | 72 | 0 |
| src/backend/utils/adt/pg_upgrade_support.c | 76 | 0 |
| src/bin/pg_dump/pg_dumpall.c | 66 | 0 |
| src/bin/pg_dump/pg_dump.c | 35 | 0 |
| src/bin/pg_dump/pg_dump.h | 1 | 0 |
| src/bin/pg_upgrade/check.c | 5 | 6 |
| src/bin/pg_upgrade/info.c | 10 | 1 |
| src/bin/pg_upgrade/pg_upgrade.h | 1 | 0 |
| src/bin/pg_upgrade/t/004_subscription.pl | 32 | 0 |
| src/include/catalog/binary_upgrade.h | 2 | 0 |
| src/include/catalog/pg_proc.dat | 11 | 0 |
| src/include/replication/origin.h | 1 | 0 |
From 0961f835e70d1ee4fa784927e9d9c91f213e5a99 Mon Sep 17 00:00:00 2001
From: Ajin Cherian <itsajin@gmail.com>
Date: Wed, 22 Apr 2026 18:27:45 +1000
Subject: [PATCH v2] Preserve replication origin OIDs in pg_upgrade
Migrate all replication origins during pg_upgrade with special handling
of replication origins of subscribers.
When pg_upgrade migrates a subscriber, the replication origin OIDs
(roident) assigned to subscriptions can change across the upgrade.
This is a problem because commit-timestamp records embed roident and
are copied directly from the old cluster's pg_commit_ts directory,
causing spurious "update_origin_differs" conflicts after the upgrade.
Fix this by skipping replorigin_create() in CreateSubscription() during
binary-upgrade mode, and instead adding a new helper function
binary_upgrade_set_next_replorigin_oid(oid, subname) that creates the
replication origin with the preserved roident from the old cluster.
pg_dump is extended to emit this call before the existing
binary_upgrade_replorigin_advance() in the binary-upgrade script.
---
src/backend/commands/subscriptioncmds.c | 10 ++-
src/backend/replication/logical/origin.c | 72 ++++++++++++++++++++
src/backend/utils/adt/pg_upgrade_support.c | 76 ++++++++++++++++++++++
src/bin/pg_dump/pg_dump.c | 35 ++++++++++
src/bin/pg_dump/pg_dump.h | 1 +
src/bin/pg_dump/pg_dumpall.c | 66 +++++++++++++++++++
src/bin/pg_upgrade/check.c | 11 ++--
src/bin/pg_upgrade/info.c | 11 +++-
src/bin/pg_upgrade/pg_upgrade.h | 1 +
src/bin/pg_upgrade/t/004_subscription.pl | 32 +++++++++
src/include/catalog/binary_upgrade.h | 2 +
src/include/catalog/pg_proc.dat | 11 ++++
src/include/replication/origin.h | 1 +
13 files changed, 320 insertions(+), 9 deletions(-)
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index d512e87cfe3..3788671506c 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -846,9 +846,15 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt,
* apply workers initialization, and to handle origin creation dynamically
* when tables are added to the subscription. It is not clear whether
* preventing creation of origins is worth additional complexity.
+ *
+ * In binary-upgrade mode, skip origin creation here. This is required to
+ * preserve the roident from the old cluster for this subscription.
*/
- ReplicationOriginNameForLogicalRep(subid, InvalidOid, originname, sizeof(originname));
- replorigin_create(originname);
+ if (!IsBinaryUpgrade)
+ {
+ ReplicationOriginNameForLogicalRep(subid, InvalidOid, originname, sizeof(originname));
+ replorigin_create(originname);
+ }
/*
* Connect to remote side to execute requested commands and fetch table
diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index c9dfb094c2b..3c5c2246df3 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -379,6 +379,78 @@ replorigin_create(const char *roname)
return roident;
}
+/*
+ * TODO: unify with replorigin_create().
+ *
+ * XXX: Should we put this function in pg_upgrade_support.c, because it's
+ * usable only while upgrading?
+ */
+ReplOriginId
+replorigin_create_with_reploriginid(ReplOriginId node, const char *roname)
+{
+ HeapTuple tuple = NULL;
+ Relation rel;
+ Datum roname_d;
+ SysScanDesc scan;
+ ScanKeyData key;
+ bool nulls[Natts_pg_replication_origin];
+ Datum values[Natts_pg_replication_origin];
+ bool collides;
+
+ Assert(node != InvalidReplOriginId);
+
+ /*
+ * To avoid needing a TOAST table for pg_replication_origin, we limit
+ * replication origin names to 512 bytes. This should be more than enough
+ * for all practical use.
+ */
+ if (strlen(roname) > MAX_RONAME_LEN)
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("replication origin name is too long"),
+ errdetail("Replication origin names must be no longer than %d bytes.",
+ MAX_RONAME_LEN)));
+
+ roname_d = CStringGetTextDatum(roname);
+
+ Assert(IsTransactionState());
+
+ rel = table_open(ReplicationOriginRelationId, ExclusiveLock);
+
+ Assert(!OidIsValid(rel->rd_rel->reltoastrelid));
+
+ ScanKeyInit(&key,
+ Anum_pg_replication_origin_roident,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(node));
+ scan = systable_beginscan(rel, ReplicationOriginIdentIndex,
+ true /* indexOK */ ,
+ SnapshotSelf,
+ 1, &key);
+ collides = HeapTupleIsValid(systable_getnext(scan));
+
+ if (collides)
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("replication origin ID %d already exists", node)));
+
+ systable_endscan(scan);
+
+ memset(&nulls, 0, sizeof(nulls));
+
+ values[Anum_pg_replication_origin_roident - 1] = ObjectIdGetDatum(node);
+ values[Anum_pg_replication_origin_roname - 1] = roname_d;
+
+ tuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
+ CatalogTupleInsert(rel, tuple);
+ CommandCounterIncrement();
+
+ table_close(rel, ExclusiveLock);
+
+ heap_freetuple(tuple);
+ return node;
+}
+
/*
* Helper function to drop a replication origin.
*/
diff --git a/src/backend/utils/adt/pg_upgrade_support.c b/src/backend/utils/adt/pg_upgrade_support.c
index b505a6b4fee..06cb1465b20 100644
--- a/src/backend/utils/adt/pg_upgrade_support.c
+++ b/src/backend/utils/adt/pg_upgrade_support.c
@@ -28,6 +28,7 @@
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
+#include "utils/syscache.h"
#include "utils/pg_lsn.h"
@@ -181,6 +182,48 @@ binary_upgrade_set_next_pg_authid_oid(PG_FUNCTION_ARGS)
PG_RETURN_VOID();
}
+/*
+ * binary_upgrade_set_next_replorigin_oid
+ *
+ * Create the replication origin with the oid specified, preserving the
+ * origin id of the subscription from the old cluster.
+ * This must be called before binary_upgrade_replorigin_advance() for the
+ * same subscription. CreateSubscription() skips replorigin_create() in
+ * binary upgrade mode specifically to allow this function to control the
+ * roident.
+ */
+Datum
+binary_upgrade_set_next_replorigin_oid(PG_FUNCTION_ARGS)
+{
+ ReplOriginId next_oid;
+ char *subname;
+ Oid subid;
+ char originname[NAMEDATALEN];
+
+ CHECK_IS_BINARY_UPGRADE;
+
+ if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
+ elog(ERROR,
+ "null argument to binary_upgrade_set_next_replorigin_oid is not allowed");
+
+ next_oid = (ReplOriginId) PG_GETARG_OID(0);
+ subname = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+ if (next_oid == InvalidReplOriginId)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("replication origin OID must be valid")));
+
+ subid = get_subscription_oid(subname, false);
+ ReplicationOriginNameForLogicalRep(subid, InvalidOid, originname,
+ sizeof(originname));
+
+ /* Create the origin with the preserved OID from the old cluster */
+ replorigin_create_with_reploriginid(next_oid, originname);
+
+ PG_RETURN_VOID();
+}
+
Datum
binary_upgrade_create_empty_extension(PG_FUNCTION_ARGS)
{
@@ -435,3 +478,36 @@ binary_upgrade_create_conflict_detection_slot(PG_FUNCTION_ARGS)
PG_RETURN_VOID();
}
+
+Datum
+binary_upgrade_create_replication_origin(PG_FUNCTION_ARGS)
+{
+ ReplOriginId node;
+ Name originname;
+
+ CHECK_IS_BINARY_UPGRADE;
+
+ /* NULL node id and origin name are not allowed */
+ if (PG_ARGISNULL(0) ||
+ PG_ARGISNULL(1))
+ elog(ERROR, "null argument to binary_upgrade_create_replication_origin is not allowed");
+
+ node = PG_GETARG_OID(0);
+ originname = PG_GETARG_NAME(1);
+
+ replorigin_create_with_reploriginid(node, NameStr(*originname));
+
+ if (!PG_ARGISNULL(2))
+ {
+ XLogRecPtr remote_commit = PG_GETARG_LSN(2);
+
+ /* Lock to prevent the replication origin from vanishing */
+ LockRelationOid(ReplicationOriginRelationId, RowExclusiveLock);
+ replorigin_advance(node, remote_commit, InvalidXLogRecPtr,
+ false /* backward */ ,
+ false /* WAL log */ );
+ UnlockRelationOid(ReplicationOriginRelationId, RowExclusiveLock);
+ }
+
+ PG_RETURN_VOID();
+}
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index d56dcc701ce..94699b60677 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -5180,6 +5180,7 @@ getSubscriptions(Archive *fout)
int i_subpublications;
int i_suborigin;
int i_suboriginremotelsn;
+ int i_suboriginoid;
int i_subenabled;
int i_subfailover;
int i_subretaindeadtuples;
@@ -5254,6 +5255,11 @@ getSubscriptions(Archive *fout)
appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
" false AS subenabled,\n");
+ if (dopt->binary_upgrade && fout->remoteVersion >= 190000)
+ appendPQExpBufferStr(query, " ro.roident AS suboriginoid,\n");
+ else
+ appendPQExpBufferStr(query, " NULL AS suboriginoid,\n");
+
if (fout->remoteVersion >= 170000)
appendPQExpBufferStr(query,
" s.subfailover,\n");
@@ -5299,6 +5305,11 @@ getSubscriptions(Archive *fout)
"LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
" ON o.external_id = 'pg_' || s.oid::text \n");
+ if (dopt->binary_upgrade && fout->remoteVersion >= 190000)
+ appendPQExpBufferStr(query,
+ "LEFT JOIN pg_catalog.pg_replication_origin ro \n"
+ " ON ro.roname = 'pg_' || s.oid::text \n");
+
appendPQExpBufferStr(query,
"WHERE s.subdbid = (SELECT oid FROM pg_database\n"
" WHERE datname = current_database())");
@@ -5333,6 +5344,7 @@ getSubscriptions(Archive *fout)
i_subpublications = PQfnumber(res, "subpublications");
i_suborigin = PQfnumber(res, "suborigin");
i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
+ i_suboriginoid = PQfnumber(res, "suboriginoid");
subinfo = pg_malloc_array(SubscriptionInfo, ntups);
@@ -5390,6 +5402,11 @@ getSubscriptions(Archive *fout)
else
subinfo[i].suboriginremotelsn =
pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
+ if (PQgetisnull(res, i, i_suboriginoid))
+ subinfo[i].suboriginoid = NULL;
+ else
+ subinfo[i].suboriginoid =
+ pg_strdup(PQgetvalue(res, i, i_suboriginoid));
/* Decide whether we want to dump it */
selectDumpableObject(&(subinfo[i].dobj), fout);
@@ -5662,6 +5679,23 @@ dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
*/
if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
{
+ /*
+ * Pin the replication origin OID and create the origin.
+ * CreateSubscription() skips replorigin_create() in binary upgrade
+ * mode to allow us to control the roident and is preserved after
+ * upgrade.
+ */
+ if (subinfo->suboriginoid)
+ {
+ appendPQExpBufferStr(query,
+ "\n-- For binary upgrade, must preserve the replication origin OID.\n");
+ appendPQExpBufferStr(query,
+ "SELECT pg_catalog.binary_upgrade_set_next_replorigin_oid(");
+ appendPQExpBuffer(query, "%s::pg_catalog.oid, ", subinfo->suboriginoid);
+ appendStringLiteralAH(query, subinfo->dobj.name, fout);
+ appendPQExpBufferStr(query, ");\n");
+ }
+
if (subinfo->suboriginremotelsn)
{
/*
@@ -5675,6 +5709,7 @@ dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
*/
appendPQExpBufferStr(query,
"\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
+
appendPQExpBufferStr(query,
"SELECT pg_catalog.binary_upgrade_replorigin_advance(");
appendStringLiteralAH(query, subinfo->dobj.name, fout);
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 5a6726d8b12..71cc66d75bc 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -730,6 +730,7 @@ typedef struct _SubscriptionInfo
char *subpublications;
char *suborigin;
char *suboriginremotelsn;
+ char *suboriginoid;
} SubscriptionInfo;
/*
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index 9e904f76baa..9f6498948f8 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -25,6 +25,7 @@
#include <time.h>
#include <unistd.h>
+#include "access/xlogdefs.h"
#include "catalog/pg_authid_d.h"
#include "common/connect.h"
#include "common/file_perm.h"
@@ -76,6 +77,7 @@ static void dropDBs(PGconn *conn);
static void dumpUserConfig(PGconn *conn, const char *username);
static void dumpDatabases(PGconn *conn);
static void dumpTimestamp(const char *msg);
+static void dumpReplicationOrigins(PGconn *conn);
static int runPgDump(const char *dbname, const char *create_opts, char *dbfile);
static void buildShSecLabels(PGconn *conn,
const char *catalog_name, Oid objectId,
@@ -813,6 +815,10 @@ main(int argc, char *argv[])
/* Dump role GUC privileges */
if (server_version >= 150000 && !skip_acls)
dumpRoleGUCPrivs(conn);
+
+ /* Dump replication origins */
+ if (server_version >= 190000 && binary_upgrade && archDumpFormat == archNull)
+ dumpReplicationOrigins(conn);
}
/* Dump tablespaces */
@@ -2339,6 +2345,66 @@ dumpTimestamp(const char *msg)
fprintf(OPF, "-- %s %s\n\n", msg, buf);
}
+static void
+dumpReplicationOrigins(PGconn *conn)
+{
+ PQExpBuffer buf = createPQExpBuffer();
+ PGresult *res;
+ int i_roident;
+ int i_roname;
+ int i_remotelsn;
+
+ /* Get replication origins in current database. */
+ appendPQExpBufferStr(buf,
+ "SELECT o.*, os.remote_lsn "
+ "FROM pg_catalog.pg_replication_origin o "
+ "LEFT OUTER JOIN pg_catalog.pg_replication_origin_status os ON o.roident = os.local_id "
+ "WHERE NOT EXISTS ("
+ " SELECT 1 FROM pg_catalog.pg_subscription s"
+ " WHERE o.roname = 'pg_' || s.oid::text);");
+
+ res = executeQuery(conn, buf->data);
+
+ i_roident = PQfnumber(res, "roident");
+ i_roname = PQfnumber(res, "roname");
+ i_remotelsn = PQfnumber(res, "remote_lsn");
+
+ if (PQntuples(res) > 0 && archDumpFormat == archNull)
+ fprintf(OPF, "--\n-- Replication Origins \n--\n\n");
+
+ for (int i = 0; i < PQntuples(res); i++)
+ {
+ ReplOriginId roident;
+ const char *roname;
+
+ roident = atooid(PQgetvalue(res, i, i_roident));
+ roname = PQgetvalue(res, i, i_roname);
+
+ resetPQExpBuffer(buf);
+
+ appendPQExpBufferStr(buf, "\n-- For binary upgrade, must preserve replication origin roident and remote_lsn\n");
+ appendPQExpBuffer(buf,
+ "SELECT pg_catalog.binary_upgrade_create_replication_origin('%u'::pg_catalog.oid, '%s'::pg_catalog.text",
+ roident, roname);
+
+ if (!PQgetisnull(res, i, i_remotelsn))
+ {
+ appendPQExpBuffer(buf, ", '%s'::pg_catalog.pg_lsn",
+ PQgetvalue(res, i, i_remotelsn));
+ }
+ else
+ appendPQExpBufferStr(buf, ", NULL");
+
+ appendPQExpBuffer(buf, ");\n");
+
+ fprintf(OPF, "%s", buf->data);
+ }
+
+ PQclear(res);
+ destroyPQExpBuffer(buf);
+}
+
+
/*
* read_dumpall_filters - retrieve database identifier patterns from file
*
diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c
index 5a7afe62eab..5180c281dcc 100644
--- a/src/bin/pg_upgrade/check.c
+++ b/src/bin/pg_upgrade/check.c
@@ -2306,8 +2306,7 @@ check_new_cluster_replication_slots(void)
* check_new_cluster_subscription_configuration()
*
* Verify that the max_active_replication_origins configuration specified is
- * enough for creating the subscriptions. This is required to create the
- * replication origin for each subscription.
+ * enough for creating all the replication origins.
*/
static void
check_new_cluster_subscription_configuration(void)
@@ -2320,8 +2319,8 @@ check_new_cluster_subscription_configuration(void)
if (GET_MAJOR_VERSION(old_cluster.major_version) < 1700)
return;
- /* Quick return if there are no subscriptions to be migrated. */
- if (old_cluster.nsubs == 0)
+ /* Quick return if there are no origins to be migrated. */
+ if (old_cluster.nrepl_origins == 0)
return;
prep_status("Checking for new cluster configuration for subscriptions");
@@ -2335,10 +2334,10 @@ check_new_cluster_subscription_configuration(void)
pg_fatal("could not determine parameter settings on new cluster");
max_active_replication_origins = atoi(PQgetvalue(res, 0, 0));
- if (old_cluster.nsubs > max_active_replication_origins)
+ if (old_cluster.nrepl_origins > max_active_replication_origins)
pg_fatal("\"max_active_replication_origins\" (%d) must be greater than or equal to the number of "
"subscriptions (%d) on the old cluster",
- max_active_replication_origins, old_cluster.nsubs);
+ max_active_replication_origins, old_cluster.nrepl_origins);
PQclear(res);
PQfinish(conn);
diff --git a/src/bin/pg_upgrade/info.c b/src/bin/pg_upgrade/info.c
index 8c5679b8097..f9359bd214b 100644
--- a/src/bin/pg_upgrade/info.c
+++ b/src/bin/pg_upgrade/info.c
@@ -834,7 +834,7 @@ count_old_cluster_logical_slots(void)
/*
* get_subscription_info()
*
- * Gets the information of subscriptions in the cluster.
+ * Gets the information of subscriptions and replication origins in the cluster.
*/
void
get_subscription_info(ClusterInfo *cluster)
@@ -842,6 +842,7 @@ get_subscription_info(ClusterInfo *cluster)
PGconn *conn;
PGresult *res;
int i_nsub;
+ int i_nrepl_origins;
int i_retain_dead_tuples;
conn = connectToServer(cluster, "template1");
@@ -861,6 +862,14 @@ get_subscription_info(ClusterInfo *cluster)
cluster->sub_retain_dead_tuples = (strcmp(PQgetvalue(res, 0, i_retain_dead_tuples), "t") == 0);
PQclear(res);
+
+ res = executeQueryOrDie(conn,
+ "SELECT count(*) AS nrepl_origins "
+ "FROM pg_catalog.pg_replication_origin");
+ i_nrepl_origins = PQfnumber(res, "nrepl_origins");
+ cluster->nrepl_origins = atoi(PQgetvalue(res, 0, i_nrepl_origins));
+ PQclear(res);
+
PQfinish(conn);
}
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index 1d767bbda2d..1d15700a886 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -311,6 +311,7 @@ typedef struct
int num_tablespaces;
const char *tablespace_suffix; /* directory specification */
int nsubs; /* number of subscriptions */
+ int nrepl_origins; /* number of replication origins */
bool sub_retain_dead_tuples; /* whether a subscription enables
* retain_dead_tuples. */
} ClusterInfo;
diff --git a/src/bin/pg_upgrade/t/004_subscription.pl b/src/bin/pg_upgrade/t/004_subscription.pl
index f68821df2a3..43322fb0596 100644
--- a/src/bin/pg_upgrade/t/004_subscription.pl
+++ b/src/bin/pg_upgrade/t/004_subscription.pl
@@ -303,6 +303,24 @@ is($result, qq(t), "Check that the table is in init state");
my $remote_lsn = $old_sub->safe_psql('postgres',
"SELECT remote_lsn FROM pg_replication_origin_status os, pg_subscription s WHERE os.external_id = 'pg_' || s.oid AND s.subname = 'regress_sub4'"
);
+
+# Get the replication origin OIDs (roident) for all subscriptions, keyed by
+# subscription name (which is stable across upgrade, unlike suboid). These
+# must be preserved after upgrade. A mismatch would cause spurious
+# update_origin_differs conflicts.
+my %pre_upgrade_roident;
+my $roident_rows = $old_sub->safe_psql('postgres',
+ "SELECT s.subname, o.roident
+ FROM pg_subscription s
+ JOIN pg_replication_origin o ON o.roname = 'pg_' || s.oid::text
+ ORDER BY s.subname"
+);
+for my $row (split /\n/, $roident_rows)
+{
+ my ($subname, $roident) = split /\|/, $row;
+ $pre_upgrade_roident{$subname} = $roident;
+}
+
# Have the subscription in disabled state before upgrade
$old_sub->safe_psql('postgres', "ALTER SUBSCRIPTION regress_sub5 DISABLE");
@@ -371,6 +389,20 @@ regress_sub5|f|f|f),
"check that the subscription's running status, failover, and retain_dead_tuples are preserved"
);
+# Verify that replication origin OIDs are preserved after upgrade.
+my $post_roident_rows = $new_sub->safe_psql('postgres',
+ "SELECT s.subname, o.roident
+ FROM pg_subscription s
+ JOIN pg_replication_origin o ON o.roname = 'pg_' || s.oid::text
+ ORDER BY s.subname"
+);
+for my $row (split /\n/, $post_roident_rows)
+{
+ my ($subname, $roident) = split /\|/, $row;
+ is($roident, $pre_upgrade_roident{$subname},
+ "roident preserved for subscription '$subname' after upgrade");
+}
+
# Subscription relations should be preserved
$result = $new_sub->safe_psql('postgres',
"SELECT srrelid, srsubstate FROM pg_subscription_rel ORDER BY srrelid");
diff --git a/src/include/catalog/binary_upgrade.h b/src/include/catalog/binary_upgrade.h
index 7bf7ae44385..27f6f0befff 100644
--- a/src/include/catalog/binary_upgrade.h
+++ b/src/include/catalog/binary_upgrade.h
@@ -14,8 +14,10 @@
#ifndef BINARY_UPGRADE_H
#define BINARY_UPGRADE_H
+#include "access/xlogdefs.h"
#include "common/relpath.h"
+
extern PGDLLIMPORT Oid binary_upgrade_next_pg_tablespace_oid;
extern PGDLLIMPORT Oid binary_upgrade_next_pg_type_oid;
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index fa9ae79082b..392ca481f46 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -12024,6 +12024,17 @@
proname => 'binary_upgrade_create_conflict_detection_slot', proisstrict => 'f',
provolatile => 'v', proparallel => 'u', prorettype => 'void',
proargtypes => '', prosrc => 'binary_upgrade_create_conflict_detection_slot' },
+{ oid => '9160', descr => 'for use by pg_upgrade (replication origin)',
+ proname => 'binary_upgrade_create_replication_origin', proisstrict => 'f',
+ provolatile => 'v', proparallel => 'u', prorettype => 'void',
+ proargtypes => 'oid name pg_lsn', prosrc => 'binary_upgrade_create_replication_origin' },
+{ oid => '9161',
+ descr => 'for use by pg_upgrade only: set next replication origin OID and create origin',
+ proname => 'binary_upgrade_set_next_replorigin_oid',
+ provolatile => 'v', proretset => 'f', prosecdef => 'f',
+ proisstrict => 'f', prorettype => 'void',
+ proargtypes => 'oid text',
+ prosrc => 'binary_upgrade_set_next_replorigin_oid' },
# conversion functions
{ oid => '4310', descr => 'internal conversion function for KOI8R to WIN1251',
diff --git a/src/include/replication/origin.h b/src/include/replication/origin.h
index a69faf6eaaf..8f6b0d0635b 100644
--- a/src/include/replication/origin.h
+++ b/src/include/replication/origin.h
@@ -55,6 +55,7 @@ extern PGDLLIMPORT int max_active_replication_origins;
/* API for querying & manipulating replication origins */
extern ReplOriginId replorigin_by_name(const char *roname, bool missing_ok);
extern ReplOriginId replorigin_create(const char *roname);
+extern ReplOriginId replorigin_create_with_reploriginid(ReplOriginId node, const char *roname);
extern void replorigin_drop_by_name(const char *name, bool missing_ok, bool nowait);
extern bool replorigin_by_oid(ReplOriginId roident, bool missing_ok,
char **roname);
--
2.47.3