From a63cc9c2e6bbd95f753794237489b5dc5e36b40d Mon Sep 17 00:00:00 2001
From: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Date: Fri, 13 Oct 2023 05:34:08 +0000
Subject: [PATCH v2] pg_upgrade: use upgrade function to restore OID

Previously, the OID counter is restored by invoking pg_resetwal with the -o
option, at the end of upgrade. This is not problematic for now, but WAL removals
are not happy if we want to uprade logical replication slot. Therefore, a new
upgrade function is introduced to reset next OID.

Note that we only update the on-memory data to avoid concurrent update of
control with the chekpointer. It is harmless becasue the value would be set at
shutdown checkpoint.
---
 src/backend/access/transam/varsup.c        | 12 ++++----
 src/backend/utils/adt/pg_upgrade_support.c | 12 ++++++++
 src/bin/pg_upgrade/check.c                 | 34 ++++++++++++++++++----
 src/bin/pg_upgrade/pg_upgrade.c            | 13 +--------
 src/bin/pg_upgrade/pg_upgrade.h            |  2 +-
 src/include/access/transam.h               |  1 +
 src/include/catalog/pg_proc.dat            |  4 +++
 7 files changed, 54 insertions(+), 24 deletions(-)

diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c
index 334adac09e..d18ef4c7cf 100644
--- a/src/backend/access/transam/varsup.c
+++ b/src/backend/access/transam/varsup.c
@@ -589,20 +589,20 @@ GetNewObjectId(void)
 /*
  * SetNextObjectId
  *
- * This may only be called during initdb; it advances the OID counter
- * to the specified value.
+ * This may only be called during initdb or pg_upgrade; it advances the OID
+ * counter to the specified value.
  */
-static void
+void
 SetNextObjectId(Oid nextOid)
 {
-	/* Safety check, this is only allowable during initdb */
-	if (IsPostmasterEnvironment)
+	/* Safety check, this is only allowable during initdb or pg_upgrade */
+	if (!IsBinaryUpgrade && IsPostmasterEnvironment)
 		elog(ERROR, "cannot advance OID counter anymore");
 
 	/* Taking the lock is, therefore, just pro forma; but do it anyway */
 	LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
 
-	if (ShmemVariableCache->nextOid > nextOid)
+	if (!IsBinaryUpgrade && ShmemVariableCache->nextOid > nextOid)
 		elog(ERROR, "too late to advance OID counter to %u, it is now %u",
 			 nextOid, ShmemVariableCache->nextOid);
 
diff --git a/src/backend/utils/adt/pg_upgrade_support.c b/src/backend/utils/adt/pg_upgrade_support.c
index 0186636d9f..0695564ea4 100644
--- a/src/backend/utils/adt/pg_upgrade_support.c
+++ b/src/backend/utils/adt/pg_upgrade_support.c
@@ -261,3 +261,15 @@ binary_upgrade_set_missing_value(PG_FUNCTION_ARGS)
 
 	PG_RETURN_VOID();
 }
+
+Datum
+binary_upgrade_set_next_oid(PG_FUNCTION_ARGS)
+{
+	Oid			nextOid = PG_GETARG_OID(0);
+
+	CHECK_IS_BINARY_UPGRADE;
+
+	SetNextObjectId(nextOid);
+
+	PG_RETURN_VOID();
+}
diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c
index 21a0ff9e42..9aa0051941 100644
--- a/src/bin/pg_upgrade/check.c
+++ b/src/bin/pg_upgrade/check.c
@@ -245,17 +245,41 @@ report_clusters_compatible(void)
 }
 
 
+static void
+set_next_oid_to_new_cluster(Oid next_oid)
+{
+	DbInfo	   *db = &new_cluster.dbarr.dbs[0];
+	PGconn	   *conn;
+
+	prep_status("Setting next OID for new cluster");
+
+	conn = connectToServer(&new_cluster, db->db_name);
+
+	PQclear(executeQueryOrDie(conn, "SELECT binary_upgrade_set_next_oid(%u);",
+							  next_oid));
+	PQfinish(conn);
+
+	check_ok();
+}
+
+
 void
-issue_warnings_and_set_wal_level(void)
+issue_warnings_and_set_next_oid(void)
 {
 	/*
-	 * We unconditionally start/stop the new server because pg_resetwal -o set
-	 * wal_level to 'minimum'.  If the user is upgrading standby servers using
-	 * the rsync instructions, they will need pg_upgrade to write its final
-	 * WAL record showing wal_level as 'replica'.
+	 * We unconditionally start/stop the new server because the OID counter
+	 * will be restored from the old server.
 	 */
 	start_postmaster(&new_cluster, true);
 
+	/*
+	 * Assuming OIDs are only used in system tables, there is no need to
+	 * restore the OID counter because we have not transferred any OIDs from
+	 * the old system, but we do it anyway just in case.  We do it late here
+	 * because there is no need to have the schema load use new oids.
+	 */
+	set_next_oid_to_new_cluster(old_cluster.controldata.chkpnt_nxtoid);
+
 	/* Reindex hash indexes for old < 10.0 */
 	if (GET_MAJOR_VERSION(old_cluster.major_version) <= 906)
 		old_9_6_invalidate_hash_indexes(&new_cluster, false);
diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c
index 96bfb67167..f406306139 100644
--- a/src/bin/pg_upgrade/pg_upgrade.c
+++ b/src/bin/pg_upgrade/pg_upgrade.c
@@ -175,17 +175,6 @@ main(int argc, char **argv)
 	transfer_all_new_tablespaces(&old_cluster.dbarr, &new_cluster.dbarr,
 								 old_cluster.pgdata, new_cluster.pgdata);
 
-	/*
-	 * Assuming OIDs are only used in system tables, there is no need to
-	 * restore the OID counter because we have not transferred any OIDs from
-	 * the old system, but we do it anyway just in case.  We do it late here
-	 * because there is no need to have the schema load use new oids.
-	 */
-	prep_status("Setting next OID for new cluster");
-	exec_prog(UTILITY_LOG_FILE, NULL, true, true,
-			  "\"%s/pg_resetwal\" -o %u \"%s\"",
-			  new_cluster.bindir, old_cluster.controldata.chkpnt_nxtoid,
-			  new_cluster.pgdata);
 	check_ok();
 
 	if (user_opts.do_sync)
@@ -201,7 +190,7 @@ main(int argc, char **argv)
 
 	create_script_for_old_cluster_deletion(&deletion_script_file_name);
 
-	issue_warnings_and_set_wal_level();
+	issue_warnings_and_set_next_oid();
 
 	pg_log(PG_REPORT,
 		   "\n"
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index 842f3b6cd3..cb924c7be7 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -345,7 +345,7 @@ void		output_check_banner(bool live_check);
 void		check_and_dump_old_cluster(bool live_check);
 void		check_new_cluster(void);
 void		report_clusters_compatible(void);
-void		issue_warnings_and_set_wal_level(void);
+void		issue_warnings_and_set_next_oid(void);
 void		output_completion_banner(char *deletion_script_file_name);
 void		check_cluster_versions(void);
 void		check_cluster_compatibility(bool live_check);
diff --git a/src/include/access/transam.h b/src/include/access/transam.h
index f5af6d3055..33d329ccce 100644
--- a/src/include/access/transam.h
+++ b/src/include/access/transam.h
@@ -294,6 +294,7 @@ extern void AdvanceOldestClogXid(TransactionId oldest_datfrozenxid);
 extern bool ForceTransactionIdLimitUpdate(void);
 extern Oid	GetNewObjectId(void);
 extern void StopGeneratingPinnedObjectIds(void);
+extern void SetNextObjectId(Oid nextOid);
 
 #ifdef USE_ASSERT_CHECKING
 extern void AssertTransactionIdInAllowableRange(TransactionId xid);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 72ea4aa8b8..1f0d1bddc2 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -11379,6 +11379,10 @@
   proname => 'binary_upgrade_set_next_pg_tablespace_oid', provolatile => 'v',
   proparallel => 'u', prorettype => 'void', proargtypes => 'oid',
   prosrc => 'binary_upgrade_set_next_pg_tablespace_oid' },
+{ oid => '8046', descr => 'for use by pg_upgrade',
+  proname => 'binary_upgrade_set_next_oid', provolatile => 'v',
+  proparallel => 'u', prorettype => 'void', proargtypes => 'oid',
+  prosrc => 'binary_upgrade_set_next_oid' },
 
 # conversion functions
 { oid => '4302',
-- 
2.27.0

