From 4d3d419a600520942baa76f359f4c8013b469a6f Mon Sep 17 00:00:00 2001
From: Jeevan Chalke <jeevan.chalke@enterprisedb.com>
Date: Wed, 24 Dec 2025 13:31:17 +0530
Subject: [PATCH v1 2/2] pg_upgrade: Add --extra-dependencies option

This commit adds a new --extra-dependencies command-line option to
pg_upgrade.  The option allows users to provide manual dependency
hints to control the order in which objects are dumped by pg_dump.

This is primarily intended to resolve upgrade failures where certain
extensions or complex schemas have functional dependencies that are
not explicitly tracked in pg_depend.

The option accepts a comma-separated list of pairs in the format
"table#referenced_table".  This value is passed directly to the
underlying pg_dump calls during the upgrade process.

Jeevan Chalke, per suggestion from Alvaro Herrera.
---
 doc/src/sgml/ref/pgupgrade.sgml | 17 +++++++++++++++++
 src/bin/pg_upgrade/dump.c       |  9 ++++++++-
 src/bin/pg_upgrade/option.c     |  7 +++++++
 src/bin/pg_upgrade/pg_upgrade.h |  1 +
 4 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml
index 38ca09b423c..46800322029 100644
--- a/doc/src/sgml/ref/pgupgrade.sgml
+++ b/doc/src/sgml/ref/pgupgrade.sgml
@@ -262,6 +262,23 @@ PostgreSQL documentation
       </listitem>
      </varlistentry>
 
+     <varlistentry>
+      <term><option>--extra-dependencies=<replaceable class="parameter">dependencylist</replaceable></option></term>
+      <listitem>
+       <para>
+        Use this option to specify additional dependencies when determining
+        the table dump order.  Each dependency must be provided in the format
+        <replaceable class="parameter">tablename#referredtablename</replaceable>,
+        with multiple pairs separated by commas.  This ensures that the
+        referred table is dumped and its data loaded immediately after its
+        creation.
+       </para>
+       <para>
+        This value is propagated unchanged to <application>pg_dump</application>.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry>
       <term><option>--no-statistics</option></term>
       <listitem>
diff --git a/src/bin/pg_upgrade/dump.c b/src/bin/pg_upgrade/dump.c
index 55f6e7b4d9c..6d9f27eefe5 100644
--- a/src/bin/pg_upgrade/dump.c
+++ b/src/bin/pg_upgrade/dump.c
@@ -39,6 +39,7 @@ generate_old_dump(void)
 		DbInfo	   *old_db = &old_cluster.dbarr.dbs[dbnum];
 		PQExpBufferData connstr,
 					escaped_connstr;
+		PQExpBufferData extra_dependencies;
 
 		initPQExpBuffer(&connstr);
 		appendPQExpBufferStr(&connstr, "dbname=");
@@ -46,6 +47,10 @@ generate_old_dump(void)
 		initPQExpBuffer(&escaped_connstr);
 		appendShellString(&escaped_connstr, connstr.data);
 		termPQExpBuffer(&connstr);
+		initPQExpBuffer(&extra_dependencies);
+		if (user_opts.extra_dependencies)
+			appendPQExpBuffer(&extra_dependencies, "--extra-dependencies='%s'",
+							  user_opts.extra_dependencies);
 
 		pg_log(PG_STATUS, "%s", old_db->db_name);
 		snprintf(sql_file_name, sizeof(sql_file_name), DB_DUMP_FILE_MASK, old_db->db_oid);
@@ -53,16 +58,18 @@ generate_old_dump(void)
 
 		parallel_exec_prog(log_file_name, NULL,
 						   "\"%s/pg_dump\" %s --no-data %s %s --quote-all-identifiers "
-						   "--binary-upgrade --format=custom %s --no-sync --file=\"%s/%s\" %s",
+						   "--binary-upgrade --format=custom %s %s --no-sync --file=\"%s/%s\" %s",
 						   new_cluster.bindir, cluster_conn_opts(&old_cluster),
 						   (user_opts.transfer_mode == TRANSFER_MODE_SWAP) ?
 						   "" : "--sequence-data",
 						   log_opts.verbose ? "--verbose" : "",
 						   user_opts.do_statistics ? "--statistics" : "--no-statistics",
+						   extra_dependencies.data,
 						   log_opts.dumpdir,
 						   sql_file_name, escaped_connstr.data);
 
 		termPQExpBuffer(&escaped_connstr);
+		termPQExpBuffer(&extra_dependencies);
 	}
 
 	/* reap all children */
diff --git a/src/bin/pg_upgrade/option.c b/src/bin/pg_upgrade/option.c
index 7fd7f1d33fc..55b23e0bec3 100644
--- a/src/bin/pg_upgrade/option.c
+++ b/src/bin/pg_upgrade/option.c
@@ -63,6 +63,7 @@ parseCommandLine(int argc, char *argv[])
 		{"no-statistics", no_argument, NULL, 5},
 		{"set-char-signedness", required_argument, NULL, 6},
 		{"swap", no_argument, NULL, 7},
+		{"extra-dependencies", required_argument, NULL, 8},
 
 		{NULL, 0, NULL, 0}
 	};
@@ -234,6 +235,10 @@ parseCommandLine(int argc, char *argv[])
 				user_opts.transfer_mode = TRANSFER_MODE_SWAP;
 				break;
 
+			case 8:
+				user_opts.extra_dependencies = pg_strdup(optarg);
+				break;
+
 			default:
 				fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 						os_info.progname);
@@ -328,6 +333,8 @@ usage(void)
 	printf(_("  --clone                       clone instead of copying files to new cluster\n"));
 	printf(_("  --copy                        copy files to new cluster (default)\n"));
 	printf(_("  --copy-file-range             copy files to new cluster with copy_file_range\n"));
+	printf(_("  --extra-dependencies=DEPENDENCYLIST\n"
+			 "                                consider these extra dependencies\n"));
 	printf(_("  --no-statistics               do not import statistics from old cluster\n"));
 	printf(_("  --set-char-signedness=OPTION  set new cluster char signedness to \"signed\" or\n"
 			 "                                \"unsigned\"\n"));
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index be30dceed5c..7aafc5ffd0e 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -349,6 +349,7 @@ typedef struct
 	int			char_signedness;	/* default char signedness: -1 for initial
 									 * value, 1 for "signed" and 0 for
 									 * "unsigned" */
+	char	   *extra_dependencies;	/* consider these extra dependencies */
 } UserOpts;
 
 typedef struct
-- 
2.43.0

