From 7448f487868b34bb333faaa278985721786b9a0e Mon Sep 17 00:00:00 2001
From: Rui Zhao <xiyuan.zr@alibaba-inc.com>
Date: Fri, 18 Aug 2023 22:31:03 +0800
Subject: [PATCH] Fix pg_upgrade with in-place tablespaces.

---
 src/bin/pg_upgrade/t/002_pg_upgrade.pl | 44 ++++++++++++++++++++++++++
 src/bin/pg_upgrade/tablespace.c        | 23 ++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/src/bin/pg_upgrade/t/002_pg_upgrade.pl b/src/bin/pg_upgrade/t/002_pg_upgrade.pl
index a5688a1cf2..1521bb7bb7 100644
--- a/src/bin/pg_upgrade/t/002_pg_upgrade.pl
+++ b/src/bin/pg_upgrade/t/002_pg_upgrade.pl
@@ -371,6 +371,50 @@ $oldnode->start;
 $oldnode->safe_psql('postgres', 'DROP DATABASE regression_invalid');
 $oldnode->stop;
 
+# Create an in-place tablespace, will be deleted below
+$oldnode->start;
+$oldnode->safe_psql('postgres', qq(
+	SET allow_in_place_tablespaces = on;
+	CREATE TABLESPACE space_test LOCATION '';
+));
+$oldnode->stop;
+
+# Check that pg_upgrade fails without allow_in_place_tablespaces option
+command_checks_all(
+	[
+		'pg_upgrade', '--no-sync', '-d', $oldnode->data_dir,
+		'-D', $newnode->data_dir, '-b', $oldbindir,
+		'-B', $newbindir, '-s', $newnode->host,
+		'-p', $oldnode->port, '-P', $newnode->port,
+		$mode, '--check',
+	],
+	1,
+	[qr/Disable to upgrade with in-place tablespaces, you can enable it with --old-options="-c allow_in_place_tablespaces=on"/],
+	[qr//],
+	'fail to upgrade with in-place tablespaces');
+ok(-d $newnode->data_dir . "/pg_upgrade_output.d",
+	"pg_upgrade_output.d/ not removed after pg_upgrade failure");
+rmtree($newnode->data_dir . "/pg_upgrade_output.d");
+
+# Check that pg_upgrade succeeds with allow_in_place_tablespaces option
+command_ok(
+	[
+		'pg_upgrade', '--no-sync', '-d', $oldnode->data_dir,
+		'-D', $newnode->data_dir, '-b', $oldbindir,
+		'-B', $newbindir, '-s', $newnode->host,
+		'-p', $oldnode->port, '-P', $newnode->port,
+		'-o', '-c allow_in_place_tablespaces=on',
+		$mode, '--check',
+	],
+	'succeed to upgrade with in-place tablespaces');
+ok(!-d $newnode->data_dir . "/pg_upgrade_output.d",
+	"pg_upgrade_output.d/ removed after pg_upgrade --check success");
+
+# And drop in-place tablespace, so we can continue
+$oldnode->start;
+$oldnode->safe_psql('postgres', 'DROP TABLESPACE space_test');
+$oldnode->stop;
+
 # --check command works here, cleans up pg_upgrade_output.d.
 command_ok(
 	[
diff --git a/src/bin/pg_upgrade/tablespace.c b/src/bin/pg_upgrade/tablespace.c
index 69cef7fa6b..945391c8b1 100644
--- a/src/bin/pg_upgrade/tablespace.c
+++ b/src/bin/pg_upgrade/tablespace.c
@@ -44,6 +44,15 @@ get_tablespace_paths(void)
 	int			tblnum;
 	int			i_spclocation;
 	char		query[QUERY_ALLOC];
+	bool		allow_in_place_tablespaces;
+
+	snprintf(query, sizeof(query),
+			 "SELECT setting FROM pg_settings WHERE "
+			 "name = 'allow_in_place_tablespaces'");
+
+	res = executeQueryOrDie(conn, "%s", query);
+	allow_in_place_tablespaces = (strcmp(PQgetvalue(res, 0, 0), "on") == 0);
+	PQclear(res);
 
 	snprintf(query, sizeof(query),
 			 "SELECT pg_catalog.pg_tablespace_location(oid) AS spclocation "
@@ -51,6 +60,14 @@ get_tablespace_paths(void)
 			 "WHERE	spcname != 'pg_default' AND "
 			 "		spcname != 'pg_global'");
 
+	/*
+	 * No need to check in-place tablespaces when allow_in_place_tablespaces is
+	 * on because they are part of the data folder.
+	 */
+	if (allow_in_place_tablespaces)
+		snprintf(query, sizeof(query),
+				 "%s AND pg_catalog.pg_tablespace_location(oid) != 'pg_tblspc/' || oid", query);
+
 	res = executeQueryOrDie(conn, "%s", query);
 
 	if ((os_info.num_old_tablespaces = PQntuples(res)) != 0)
@@ -67,6 +84,12 @@ get_tablespace_paths(void)
 
 		os_info.old_tablespaces[tblnum] = pg_strdup(PQgetvalue(res, tblnum, i_spclocation));
 
+		if (!is_absolute_path(os_info.old_tablespaces[tblnum]))
+			report_status(PG_FATAL,
+						  "Disable to upgrade with in-place tablespaces, "
+						  "you can enable it with "
+						  "--old-options=\"-c allow_in_place_tablespaces=on\"");
+
 		/*
 		 * Check that the tablespace path exists and is a directory.
 		 * Effectively, this is checking only for tables/indexes in
-- 
2.32.0.3.g01195cf9f

