On Wed, Jun 29, 2022 at 01:17:33PM +0900, Michael Paquier wrote:
> On Sat, Jun 25, 2022 at 11:04:37AM -0500, Justin Pryzby wrote:
> 
> > I'll concede that a cluster which has no tables sounds a lot like a toy, 
> > but I
> > find it disturbing that nothing prevents running the process twice, up to 
> > the
> > point that it's evidently corrupted the catalog.
> 
> I have heard of cases where instances were only used with a set of
> foreign tables, for example.  Not sure that this is spread enough to
> worry about, but this would fail as much as your case.

foreign tables have OIDs too.

ts=# SELECT * FROM pg_class WHERE relkind ='f';
oid                 | 1554544611

> > While looking at this, I noticed that starting postgres --single immediately
> > after initdb allows creating objects with OIDs below FirstNormalObjectId
> > (thereby defeating pg_upgrade's check).  I'm not familiar with the 
> > behavioral
> > differences of single user mode, and couldn't find anything in the
> > documentation.
> 
> This one comes from NextOID in the control data file after a fresh
> initdb, and GetNewObjectId() would enforce that in a postmaster
> environment to be FirstNormalObjectId when assigning the first user
> OID.  Would you imply an extra step at the end of initdb to update the
> control data file of the new cluster to reflect FirstNormalObjectId?

I added a call to reset xlog, similar to what's in pg_upgrade.
Unfortunately, I don't see an easy way to silence it.

-- 
Justin
>From bb8133a01b61e2b3b1ee123bafc4a59b9f4a0c70 Mon Sep 17 00:00:00 2001
From: Justin Pryzby <pryz...@telsasoft.com>
Date: Wed, 6 Jul 2022 08:55:11 -0500
Subject: [PATCH] wip: initdb should advance the OID counter to FirstNormal

Otherwise, a cluster started in single-user mode immediately after initdb can
create objects in the range of system OIDs.
---
 src/backend/access/transam/varsup.c |  5 ++---
 src/bin/initdb/initdb.c             |  9 +++++++++
 src/bin/pg_upgrade/controldata.c    | 17 +----------------
 src/bin/pg_upgrade/pg_upgrade.c     | 11 -----------
 src/bin/pg_upgrade/pg_upgrade.h     |  1 -
 5 files changed, 12 insertions(+), 31 deletions(-)

diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c
index 849a7ce9d6d..d93974fcaa5 100644
--- a/src/backend/access/transam/varsup.c
+++ b/src/backend/access/transam/varsup.c
@@ -543,8 +543,7 @@ GetNewObjectId(void)
 	 *
 	 * During initdb, we start the OID generator at FirstGenbkiObjectId, so we
 	 * only wrap if before that point when in bootstrap or standalone mode.
-	 * The first time through this routine after normal postmaster start, the
-	 * counter will be forced up to FirstNormalObjectId.  This mechanism
+	 * This mechanism
 	 * leaves the OIDs between FirstGenbkiObjectId and FirstNormalObjectId
 	 * available for automatic assignment during initdb, while ensuring they
 	 * will never conflict with user-assigned OIDs.
@@ -553,7 +552,7 @@ GetNewObjectId(void)
 	{
 		if (IsPostmasterEnvironment)
 		{
-			/* wraparound, or first post-initdb assignment, in normal mode */
+			/* wraparound */
 			ShmemVariableCache->nextOid = FirstNormalObjectId;
 			ShmemVariableCache->oidCount = 0;
 		}
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 89b888eaa5a..b3f248b649a 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -59,6 +59,7 @@
 #include "sys/mman.h"
 #endif
 
+#include "access/transam.h"
 #include "access/xlog_internal.h"
 #include "catalog/pg_authid_d.h"
 #include "catalog/pg_class_d.h" /* pgrminclude ignore */
@@ -2788,6 +2789,14 @@ initialize_data_directory(void)
 
 	PG_CMD_CLOSE;
 
+	/* Set FirstNormal OID */
+	snprintf(cmd, sizeof(cmd),
+			 "\"%s/pg_resetwal\" -o %u %s",
+			 bin_path, FirstNormalObjectId, pg_data);
+
+	PG_CMD_OPEN;
+	PG_CMD_CLOSE;
+
 	check_ok();
 }
 
diff --git a/src/bin/pg_upgrade/controldata.c b/src/bin/pg_upgrade/controldata.c
index 41b8f69b8cb..26b569f7102 100644
--- a/src/bin/pg_upgrade/controldata.c
+++ b/src/bin/pg_upgrade/controldata.c
@@ -41,7 +41,6 @@ get_control_data(ClusterInfo *cluster, bool live_check)
 	bool		got_log_id = false;
 	bool		got_log_seg = false;
 	bool		got_xid = false;
-	bool		got_oid = false;
 	bool		got_multi = false;
 	bool		got_oldestmulti = false;
 	bool		got_oldestxid = false;
@@ -291,17 +290,6 @@ get_control_data(ClusterInfo *cluster, bool live_check)
 			cluster->controldata.chkpnt_nxtxid = str2uint(p);
 			got_xid = true;
 		}
-		else if ((p = strstr(bufin, "Latest checkpoint's NextOID:")) != NULL)
-		{
-			p = strchr(p, ':');
-
-			if (p == NULL || strlen(p) <= 1)
-				pg_fatal("%d: controldata retrieval problem\n", __LINE__);
-
-			p++;				/* remove ':' char */
-			cluster->controldata.chkpnt_nxtoid = str2uint(p);
-			got_oid = true;
-		}
 		else if ((p = strstr(bufin, "Latest checkpoint's NextMultiXactId:")) != NULL)
 		{
 			p = strchr(p, ':');
@@ -555,7 +543,7 @@ get_control_data(ClusterInfo *cluster, bool live_check)
 	}
 
 	/* verify that we got all the mandatory pg_control data */
-	if (!got_xid || !got_oid ||
+	if (!got_xid ||
 		!got_multi || !got_oldestxid ||
 		(!got_oldestmulti &&
 		 cluster->controldata.cat_ver >= MULTIXACT_FORMATCHANGE_CAT_VER) ||
@@ -577,9 +565,6 @@ get_control_data(ClusterInfo *cluster, bool live_check)
 		if (!got_xid)
 			pg_log(PG_REPORT, "  checkpoint next XID\n");
 
-		if (!got_oid)
-			pg_log(PG_REPORT, "  latest checkpoint next OID\n");
-
 		if (!got_multi)
 			pg_log(PG_REPORT, "  latest checkpoint next MultiXactId\n");
 
diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c
index 265d8294906..785fe8dd18d 100644
--- a/src/bin/pg_upgrade/pg_upgrade.c
+++ b/src/bin/pg_upgrade/pg_upgrade.c
@@ -168,17 +168,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)
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index 50dfe9e81c1..7062da0ceb1 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -200,7 +200,6 @@ typedef struct
 	char		nextxlogfile[25];
 	uint32		chkpnt_nxtxid;
 	uint32		chkpnt_nxtepoch;
-	uint32		chkpnt_nxtoid;
 	uint32		chkpnt_nxtmulti;
 	uint32		chkpnt_nxtmxoff;
 	uint32		chkpnt_oldstMulti;
-- 
2.17.1

Reply via email to