From 0e1753613897e12abd9d246176dfc0c83cdcece6 Mon Sep 17 00:00:00 2001
From: Jakub Wartak <jakub.wartak@enterprisedb.com>
Date: Fri, 5 Jan 2024 08:33:45 +0100
Subject: [PATCH v3 3/4] Add --copy-file-range to pg_upgrade using
 pg_copyfile_offload(). Original patch author is Thomas.

Co-authored-by: Thomas Munro <thomas.munro@gmail.com>

Discussion: https://www.postgresql.org/message-id/flat/CA%2BhUKGJvLLNQtzb%3DZWcTsYF8kv8cR_%3DH17CX-eL8qNixeC4DAw%40mail.gmail.com#ce606227e39df74c6b2abf80b8eab04a
---
 src/bin/pg_upgrade/check.c      | 409 ++++++++++++++++----------------
 src/bin/pg_upgrade/file.c       |  37 ++-
 src/bin/pg_upgrade/option.c     | 158 ++++++------
 src/bin/pg_upgrade/pg_upgrade.h | 150 ++++++------
 4 files changed, 401 insertions(+), 353 deletions(-)

diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c
index 87c06628c6..3e6922f3fb 100644
--- a/src/bin/pg_upgrade/check.c
+++ b/src/bin/pg_upgrade/check.c
@@ -38,7 +38,6 @@ static void check_new_cluster_subscription_configuration(void);
 static void check_old_cluster_for_valid_slots(bool live_check);
 static void check_old_cluster_subscription_state(void);
 
-
 /*
  * fix_path_separator
  * For non-Windows, just return the argument.
@@ -72,19 +71,16 @@ output_check_banner(bool live_check)
 {
 	if (user_opts.check && live_check)
 	{
-		pg_log(PG_REPORT,
-			   "Performing Consistency Checks on Old Live Server\n"
+		pg_log(PG_REPORT, "Performing Consistency Checks on Old Live Server\n"
 			   "------------------------------------------------");
 	}
 	else
 	{
-		pg_log(PG_REPORT,
-			   "Performing Consistency Checks\n"
+		pg_log(PG_REPORT, "Performing Consistency Checks\n"
 			   "-----------------------------");
 	}
 }
 
-
 void
 check_and_dump_old_cluster(bool live_check)
 {
@@ -103,7 +99,6 @@ check_and_dump_old_cluster(bool live_check)
 
 	get_loadable_libraries();
 
-
 	/*
 	 * Check for various failure cases
 	 */
@@ -218,7 +213,6 @@ check_and_dump_old_cluster(bool live_check)
 		stop_postmaster(false);
 }
 
-
 void
 check_new_cluster(void)
 {
@@ -238,6 +232,9 @@ check_new_cluster(void)
 		case TRANSFER_MODE_LINK:
 			check_hard_link();
 			break;
+		case TRANSFER_MODE_COPY_FILE_RANGE:
+			check_copy_file_range();
+			break;
 	}
 
 	check_is_install_user(&new_cluster);
@@ -251,7 +248,6 @@ check_new_cluster(void)
 	check_new_cluster_subscription_configuration();
 }
 
-
 void
 report_clusters_compatible(void)
 {
@@ -265,12 +261,12 @@ report_clusters_compatible(void)
 		exit(0);
 	}
 
-	pg_log(PG_REPORT, "\n"
+	pg_log(PG_REPORT,
+		   "\n"
 		   "If pg_upgrade fails after this point, you must re-initdb the\n"
 		   "new cluster before continuing.");
 }
 
-
 void
 issue_warnings_and_set_wal_level(void)
 {
@@ -291,7 +287,6 @@ issue_warnings_and_set_wal_level(void)
 	stop_postmaster(false);
 }
 
-
 void
 output_completion_banner(char *deletion_script_file_name)
 {
@@ -308,7 +303,8 @@ output_completion_banner(char *deletion_script_file_name)
 	pg_log(PG_REPORT,
 		   "Optimizer statistics are not transferred by pg_upgrade.\n"
 		   "Once you start the new server, consider running:\n"
-		   "    %s/vacuumdb %s--all --analyze-in-stages", new_cluster.bindir, user_specification.data);
+		   "    %s/vacuumdb %s--all --analyze-in-stages",
+		   new_cluster.bindir, user_specification.data);
 
 	if (deletion_script_file_name)
 		pg_log(PG_REPORT,
@@ -316,7 +312,8 @@ output_completion_banner(char *deletion_script_file_name)
 			   "    %s",
 			   deletion_script_file_name);
 	else
-		pg_log(PG_REPORT,
+		pg_log(
+			   PG_REPORT,
 			   "Could not create a script to delete the old cluster's data files\n"
 			   "because user-defined tablespaces or the new cluster's data directory\n"
 			   "exist in the old cluster directory.  The old cluster's contents must\n"
@@ -325,7 +322,6 @@ output_completion_banner(char *deletion_script_file_name)
 	termPQExpBuffer(&user_specification);
 }
 
-
 void
 check_cluster_versions(void)
 {
@@ -341,11 +337,13 @@ check_cluster_versions(void)
 	 */
 
 	if (GET_MAJOR_VERSION(old_cluster.major_version) < 902)
-		pg_fatal("This utility can only upgrade from PostgreSQL version %s and later.",
+		pg_fatal(
+				 "This utility can only upgrade from PostgreSQL version %s and later.",
 				 "9.2");
 
 	/* Only current PG version is supported as a target */
-	if (GET_MAJOR_VERSION(new_cluster.major_version) != GET_MAJOR_VERSION(PG_VERSION_NUM))
+	if (GET_MAJOR_VERSION(new_cluster.major_version) !=
+		GET_MAJOR_VERSION(PG_VERSION_NUM))
 		pg_fatal("This utility can only upgrade to PostgreSQL version %s.",
 				 PG_MAJORVERSION);
 
@@ -355,20 +353,22 @@ check_cluster_versions(void)
 	 * older versions.
 	 */
 	if (old_cluster.major_version > new_cluster.major_version)
-		pg_fatal("This utility cannot be used to downgrade to older major PostgreSQL versions.");
+		pg_fatal("This utility cannot be used to downgrade to older major "
+				 "PostgreSQL versions.");
 
 	/* Ensure binaries match the designated data directories */
 	if (GET_MAJOR_VERSION(old_cluster.major_version) !=
 		GET_MAJOR_VERSION(old_cluster.bin_version))
-		pg_fatal("Old cluster data and binary directories are from different major versions.");
+		pg_fatal("Old cluster data and binary directories are from different major "
+				 "versions.");
 	if (GET_MAJOR_VERSION(new_cluster.major_version) !=
 		GET_MAJOR_VERSION(new_cluster.bin_version))
-		pg_fatal("New cluster data and binary directories are from different major versions.");
+		pg_fatal("New cluster data and binary directories are from different major "
+				 "versions.");
 
 	check_ok();
 }
 
-
 void
 check_cluster_compatibility(bool live_check)
 {
@@ -382,7 +382,6 @@ check_cluster_compatibility(bool live_check)
 				 "the old and new port numbers must be different.");
 }
 
-
 static void
 check_new_cluster_is_empty(void)
 {
@@ -393,15 +392,14 @@ check_new_cluster_is_empty(void)
 		int			relnum;
 		RelInfoArr *rel_arr = &new_cluster.dbarr.dbs[dbnum].rel_arr;
 
-		for (relnum = 0; relnum < rel_arr->nrels;
-			 relnum++)
+		for (relnum = 0; relnum < rel_arr->nrels; relnum++)
 		{
 			/* pg_largeobject and its index should be skipped */
 			if (strcmp(rel_arr->rels[relnum].nspname, "pg_catalog") != 0)
-				pg_fatal("New cluster database \"%s\" is not empty: found relation \"%s.%s\"",
+				pg_fatal("New cluster database \"%s\" is not empty: found relation "
+						 "\"%s.%s\"",
 						 new_cluster.dbarr.dbs[dbnum].db_name,
-						 rel_arr->rels[relnum].nspname,
-						 rel_arr->rels[relnum].relname);
+						 rel_arr->rels[relnum].nspname, rel_arr->rels[relnum].relname);
 		}
 	}
 }
@@ -428,8 +426,7 @@ check_for_new_tablespace_dir(void)
 		struct stat statbuf;
 
 		snprintf(new_tablespace_dir, MAXPGPATH, "%s%s",
-				 os_info.old_tablespaces[tblnum],
-				 new_cluster.tablespace_suffix);
+				 os_info.old_tablespaces[tblnum], new_cluster.tablespace_suffix);
 
 		if (stat(new_tablespace_dir, &statbuf) == 0 || errno != ENOENT)
 			pg_fatal("new cluster tablespace directory already exists: \"%s\"",
@@ -452,8 +449,8 @@ create_script_for_old_cluster_deletion(char **deletion_script_file_name)
 	char		old_cluster_pgdata[MAXPGPATH],
 				new_cluster_pgdata[MAXPGPATH];
 
-	*deletion_script_file_name = psprintf("%sdelete_old_cluster.%s",
-										  SCRIPT_PREFIX, SCRIPT_EXT);
+	*deletion_script_file_name =
+		psprintf("%sdelete_old_cluster.%s", SCRIPT_PREFIX, SCRIPT_EXT);
 
 	strlcpy(old_cluster_pgdata, old_cluster.pgdata, MAXPGPATH);
 	canonicalize_path(old_cluster_pgdata);
@@ -465,7 +462,9 @@ create_script_for_old_cluster_deletion(char **deletion_script_file_name)
 	if (path_is_prefix_of_path(old_cluster_pgdata, new_cluster_pgdata))
 	{
 		pg_log(PG_WARNING,
-			   "\nWARNING:  new data directory should not be inside the old data directory, i.e. %s", old_cluster_pgdata);
+			   "\nWARNING:  new data directory should not be inside the old data "
+			   "directory, i.e. %s",
+			   old_cluster_pgdata);
 
 		/* Unlink file in case it is left over from a previous run. */
 		unlink(*deletion_script_file_name);
@@ -489,7 +488,9 @@ create_script_for_old_cluster_deletion(char **deletion_script_file_name)
 		{
 			/* reproduce warning from CREATE TABLESPACE that is in the log */
 			pg_log(PG_WARNING,
-				   "\nWARNING:  user-defined tablespace locations should not be inside the data directory, i.e. %s", old_tablespace_dir);
+				   "\nWARNING:  user-defined tablespace locations should not be "
+				   "inside the data directory, i.e. %s",
+				   old_tablespace_dir);
 
 			/* Unlink file in case it is left over from a previous run. */
 			unlink(*deletion_script_file_name);
@@ -502,8 +503,8 @@ create_script_for_old_cluster_deletion(char **deletion_script_file_name)
 	prep_status("Creating script to delete old cluster");
 
 	if ((script = fopen_priv(*deletion_script_file_name, "w")) == NULL)
-		pg_fatal("could not open file \"%s\": %s",
-				 *deletion_script_file_name, strerror(errno));
+		pg_fatal("could not open file \"%s\": %s", *deletion_script_file_name,
+				 strerror(errno));
 
 #ifndef WIN32
 	/* add shebang header */
@@ -560,7 +561,6 @@ create_script_for_old_cluster_deletion(char **deletion_script_file_name)
 	check_ok();
 }
 
-
 /*
  *	check_is_install_user()
  *
@@ -576,8 +576,7 @@ check_is_install_user(ClusterInfo *cluster)
 	prep_status("Checking database user is the install user");
 
 	/* Can't use pg_authid because only superusers can view it. */
-	res = executeQueryOrDie(conn,
-							"SELECT rolsuper, oid "
+	res = executeQueryOrDie(conn, "SELECT rolsuper, oid "
 							"FROM pg_catalog.pg_roles "
 							"WHERE rolname = current_user "
 							"AND rolname !~ '^pg_'");
@@ -589,13 +588,11 @@ check_is_install_user(ClusterInfo *cluster)
 	 */
 	if (PQntuples(res) != 1 ||
 		atooid(PQgetvalue(res, 0, 1)) != BOOTSTRAP_SUPERUSERID)
-		pg_fatal("database user \"%s\" is not the install user",
-				 os_info.user);
+		pg_fatal("database user \"%s\" is not the install user", os_info.user);
 
 	PQclear(res);
 
-	res = executeQueryOrDie(conn,
-							"SELECT COUNT(*) "
+	res = executeQueryOrDie(conn, "SELECT COUNT(*) "
 							"FROM pg_catalog.pg_roles "
 							"WHERE rolname !~ '^pg_'");
 
@@ -617,7 +614,6 @@ check_is_install_user(ClusterInfo *cluster)
 	check_ok();
 }
 
-
 /*
  *	check_proper_datallowconn
  *
@@ -639,16 +635,15 @@ check_proper_datallowconn(ClusterInfo *cluster)
 
 	prep_status("Checking database connection settings");
 
-	snprintf(output_path, sizeof(output_path), "%s/%s",
-			 log_opts.basedir,
+	snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir,
 			 "databases_with_datallowconn_false.txt");
 
 	conn_template1 = connectToServer(cluster, "template1");
 
 	/* get database names */
-	dbres = executeQueryOrDie(conn_template1,
-							  "SELECT	datname, datallowconn "
-							  "FROM	pg_catalog.pg_database");
+	dbres =
+		executeQueryOrDie(conn_template1, "SELECT	datname, datallowconn "
+						  "FROM	pg_catalog.pg_database");
 
 	i_datname = PQfnumber(dbres, "datname");
 	i_datallowconn = PQfnumber(dbres, "datallowconn");
@@ -675,8 +670,8 @@ check_proper_datallowconn(ClusterInfo *cluster)
 			if (strcmp(datallowconn, "f") == 0)
 			{
 				if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
-					pg_fatal("could not open file \"%s\": %s",
-							 output_path, strerror(errno));
+					pg_fatal("could not open file \"%s\": %s", output_path,
+							 strerror(errno));
 
 				fprintf(script, "%s\n", datname);
 			}
@@ -691,19 +686,20 @@ check_proper_datallowconn(ClusterInfo *cluster)
 	{
 		fclose(script);
 		pg_log(PG_REPORT, "fatal");
-		pg_fatal("All non-template0 databases must allow connections, i.e. their\n"
+		pg_fatal(
+				 "All non-template0 databases must allow connections, i.e. their\n"
 				 "pg_database.datallowconn must be true.  Your installation contains\n"
 				 "non-template0 databases with their pg_database.datallowconn set to\n"
 				 "false.  Consider allowing connection for all non-template0 databases\n"
 				 "or drop the databases which do not allow connections.  A list of\n"
 				 "databases with the problem is in the file:\n"
-				 "    %s", output_path);
+				 "    %s",
+				 output_path);
 	}
 	else
 		check_ok();
 }
 
-
 /*
  *	check_for_prepared_transactions()
  *
@@ -718,8 +714,7 @@ check_for_prepared_transactions(ClusterInfo *cluster)
 
 	prep_status("Checking for prepared transactions");
 
-	res = executeQueryOrDie(conn,
-							"SELECT * "
+	res = executeQueryOrDie(conn, "SELECT * "
 							"FROM pg_catalog.pg_prepared_xacts");
 
 	if (PQntuples(res) != 0)
@@ -737,7 +732,6 @@ check_for_prepared_transactions(ClusterInfo *cluster)
 	check_ok();
 }
 
-
 /*
  *	check_for_isn_and_int8_passing_mismatch()
  *
@@ -762,8 +756,7 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
 		return;
 	}
 
-	snprintf(output_path, sizeof(output_path), "%s/%s",
-			 log_opts.basedir,
+	snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir,
 			 "contrib_isn_and_int8_pass_by_value.txt");
 
 	for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
@@ -778,8 +771,7 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
 		PGconn	   *conn = connectToServer(cluster, active_db->db_name);
 
 		/* Find any functions coming from contrib/isn */
-		res = executeQueryOrDie(conn,
-								"SELECT n.nspname, p.proname "
+		res = executeQueryOrDie(conn, "SELECT n.nspname, p.proname "
 								"FROM	pg_catalog.pg_proc p, "
 								"		pg_catalog.pg_namespace n "
 								"WHERE	p.pronamespace = n.oid AND "
@@ -791,15 +783,14 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
 		for (rowno = 0; rowno < ntups; rowno++)
 		{
 			if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
-				pg_fatal("could not open file \"%s\": %s",
-						 output_path, strerror(errno));
+				pg_fatal("could not open file \"%s\": %s", output_path,
+						 strerror(errno));
 			if (!db_used)
 			{
 				fprintf(script, "In database: %s\n", active_db->db_name);
 				db_used = true;
 			}
-			fprintf(script, "  %s.%s\n",
-					PQgetvalue(res, rowno, i_nspname),
+			fprintf(script, "  %s.%s\n", PQgetvalue(res, rowno, i_nspname),
 					PQgetvalue(res, rowno, i_proname));
 		}
 
@@ -812,13 +803,17 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
 	{
 		fclose(script);
 		pg_log(PG_REPORT, "fatal");
-		pg_fatal("Your installation contains \"contrib/isn\" functions which rely on the\n"
+		pg_fatal(
+				 "Your installation contains \"contrib/isn\" functions which rely on "
+				 "the\n"
 				 "bigint data type.  Your old and new clusters pass bigint values\n"
 				 "differently so this cluster cannot currently be upgraded.  You can\n"
 				 "manually dump databases in the old cluster that use \"contrib/isn\"\n"
-				 "facilities, drop them, perform the upgrade, and then restore them.  A\n"
+				 "facilities, drop them, perform the upgrade, and then restore them.  "
+				 "A\n"
 				 "list of the problem functions is in the file:\n"
-				 "    %s", output_path);
+				 "    %s",
+				 output_path);
 	}
 	else
 		check_ok();
@@ -836,8 +831,7 @@ check_for_user_defined_postfix_ops(ClusterInfo *cluster)
 
 	prep_status("Checking for user-defined postfix operators");
 
-	snprintf(output_path, sizeof(output_path), "%s/%s",
-			 log_opts.basedir,
+	snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir,
 			 "postfix_ops.txt");
 
 	/* Find any user defined postfix operators */
@@ -861,8 +855,7 @@ check_for_user_defined_postfix_ops(ClusterInfo *cluster)
 		 * #define is ever changed, the cutoff we want to use is the value
 		 * used by pre-version 14 servers, not that of some future version.
 		 */
-		res = executeQueryOrDie(conn,
-								"SELECT o.oid AS oproid, "
+		res = executeQueryOrDie(conn, "SELECT o.oid AS oproid, "
 								"       n.nspname AS oprnsp, "
 								"       o.oprname, "
 								"       tn.nspname AS typnsp, "
@@ -884,20 +877,18 @@ check_for_user_defined_postfix_ops(ClusterInfo *cluster)
 		i_typname = PQfnumber(res, "typname");
 		for (rowno = 0; rowno < ntups; rowno++)
 		{
-			if (script == NULL &&
-				(script = fopen_priv(output_path, "w")) == NULL)
-				pg_fatal("could not open file \"%s\": %s",
-						 output_path, strerror(errno));
+			if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
+				pg_fatal("could not open file \"%s\": %s", output_path,
+						 strerror(errno));
 			if (!db_used)
 			{
 				fprintf(script, "In database: %s\n", active_db->db_name);
 				db_used = true;
 			}
-			fprintf(script, "  (oid=%s) %s.%s (%s.%s, NONE)\n",
-					PQgetvalue(res, rowno, i_oproid),
-					PQgetvalue(res, rowno, i_oprnsp),
-					PQgetvalue(res, rowno, i_oprname),
-					PQgetvalue(res, rowno, i_typnsp),
+			fprintf(
+					script, "  (oid=%s) %s.%s (%s.%s, NONE)\n",
+					PQgetvalue(res, rowno, i_oproid), PQgetvalue(res, rowno, i_oprnsp),
+					PQgetvalue(res, rowno, i_oprname), PQgetvalue(res, rowno, i_typnsp),
 					PQgetvalue(res, rowno, i_typname));
 		}
 
@@ -910,11 +901,14 @@ check_for_user_defined_postfix_ops(ClusterInfo *cluster)
 	{
 		fclose(script);
 		pg_log(PG_REPORT, "fatal");
-		pg_fatal("Your installation contains user-defined postfix operators, which are not\n"
-				 "supported anymore.  Consider dropping the postfix operators and replacing\n"
+		pg_fatal("Your installation contains user-defined postfix operators, which "
+				 "are not\n"
+				 "supported anymore.  Consider dropping the postfix operators and "
+				 "replacing\n"
 				 "them with prefix operators or function calls.\n"
 				 "A list of user-defined postfix operators is in the file:\n"
-				 "    %s", output_path);
+				 "    %s",
+				 output_path);
 	}
 	else
 		check_ok();
@@ -936,8 +930,7 @@ check_for_incompatible_polymorphics(ClusterInfo *cluster)
 
 	prep_status("Checking for incompatible polymorphic functions");
 
-	snprintf(output_path, sizeof(output_path), "%s/%s",
-			 log_opts.basedir,
+	snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir,
 			 "incompatible_polymorphics.txt");
 
 	/* The set of problematic functions varies a bit in different versions */
@@ -975,7 +968,8 @@ check_for_incompatible_polymorphics(ClusterInfo *cluster)
 		 * #define is ever changed, the cutoff we want to use is the value
 		 * used by pre-version 14 servers, not that of some future version.
 		 */
-		res = executeQueryOrDie(conn,
+		res = executeQueryOrDie(
+								conn,
 		/* Aggregate transition functions */
 								"SELECT 'aggregate' AS objkind, p.oid::regprocedure::text AS objname "
 								"FROM pg_proc AS p "
@@ -1002,9 +996,7 @@ check_for_incompatible_polymorphics(ClusterInfo *cluster)
 								"WHERE op.oid >= 16384 "
 								"AND oprcode = ANY(ARRAY[%s]::regprocedure[]) "
 								"AND oprleft = ANY(ARRAY['anyarray', 'anyelement']::regtype[]);",
-								old_polymorphics.data,
-								old_polymorphics.data,
-								old_polymorphics.data);
+								old_polymorphics.data, old_polymorphics.data, old_polymorphics.data);
 
 		ntups = PQntuples(res);
 
@@ -1013,18 +1005,16 @@ check_for_incompatible_polymorphics(ClusterInfo *cluster)
 
 		for (int rowno = 0; rowno < ntups; rowno++)
 		{
-			if (script == NULL &&
-				(script = fopen_priv(output_path, "w")) == NULL)
-				pg_fatal("could not open file \"%s\": %s",
-						 output_path, strerror(errno));
+			if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
+				pg_fatal("could not open file \"%s\": %s", output_path,
+						 strerror(errno));
 			if (!db_used)
 			{
 				fprintf(script, "In database: %s\n", active_db->db_name);
 				db_used = true;
 			}
 
-			fprintf(script, "  %s: %s\n",
-					PQgetvalue(res, rowno, i_objkind),
+			fprintf(script, "  %s: %s\n", PQgetvalue(res, rowno, i_objkind),
 					PQgetvalue(res, rowno, i_objname));
 		}
 
@@ -1036,13 +1026,18 @@ check_for_incompatible_polymorphics(ClusterInfo *cluster)
 	{
 		fclose(script);
 		pg_log(PG_REPORT, "fatal");
-		pg_fatal("Your installation contains user-defined objects that refer to internal\n"
-				 "polymorphic functions with arguments of type \"anyarray\" or \"anyelement\".\n"
-				 "These user-defined objects must be dropped before upgrading and restored\n"
-				 "afterwards, changing them to refer to the new corresponding functions with\n"
+		pg_fatal("Your installation contains user-defined objects that refer to "
+				 "internal\n"
+				 "polymorphic functions with arguments of type \"anyarray\" or "
+				 "\"anyelement\".\n"
+				 "These user-defined objects must be dropped before upgrading and "
+				 "restored\n"
+				 "afterwards, changing them to refer to the new corresponding "
+				 "functions with\n"
 				 "arguments of type \"anycompatiblearray\" and \"anycompatible\".\n"
 				 "A list of the problematic objects is in the file:\n"
-				 "    %s", output_path);
+				 "    %s",
+				 output_path);
 	}
 	else
 		check_ok();
@@ -1062,8 +1057,7 @@ check_for_tables_with_oids(ClusterInfo *cluster)
 
 	prep_status("Checking for tables WITH OIDS");
 
-	snprintf(output_path, sizeof(output_path), "%s/%s",
-			 log_opts.basedir,
+	snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir,
 			 "tables_with_oids.txt");
 
 	/* Find any tables declared WITH OIDS */
@@ -1078,8 +1072,7 @@ check_for_tables_with_oids(ClusterInfo *cluster)
 		DbInfo	   *active_db = &cluster->dbarr.dbs[dbnum];
 		PGconn	   *conn = connectToServer(cluster, active_db->db_name);
 
-		res = executeQueryOrDie(conn,
-								"SELECT n.nspname, c.relname "
+		res = executeQueryOrDie(conn, "SELECT n.nspname, c.relname "
 								"FROM	pg_catalog.pg_class c, "
 								"		pg_catalog.pg_namespace n "
 								"WHERE	c.relnamespace = n.oid AND "
@@ -1092,15 +1085,14 @@ check_for_tables_with_oids(ClusterInfo *cluster)
 		for (rowno = 0; rowno < ntups; rowno++)
 		{
 			if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
-				pg_fatal("could not open file \"%s\": %s",
-						 output_path, strerror(errno));
+				pg_fatal("could not open file \"%s\": %s", output_path,
+						 strerror(errno));
 			if (!db_used)
 			{
 				fprintf(script, "In database: %s\n", active_db->db_name);
 				db_used = true;
 			}
-			fprintf(script, "  %s.%s\n",
-					PQgetvalue(res, rowno, i_nspname),
+			fprintf(script, "  %s.%s\n", PQgetvalue(res, rowno, i_nspname),
 					PQgetvalue(res, rowno, i_relname));
 		}
 
@@ -1113,17 +1105,18 @@ check_for_tables_with_oids(ClusterInfo *cluster)
 	{
 		fclose(script);
 		pg_log(PG_REPORT, "fatal");
-		pg_fatal("Your installation contains tables declared WITH OIDS, which is not\n"
+		pg_fatal(
+				 "Your installation contains tables declared WITH OIDS, which is not\n"
 				 "supported anymore.  Consider removing the oid column using\n"
 				 "    ALTER TABLE ... SET WITHOUT OIDS;\n"
 				 "A list of tables with the problem is in the file:\n"
-				 "    %s", output_path);
+				 "    %s",
+				 output_path);
 	}
 	else
 		check_ok();
 }
 
-
 /*
  * check_for_composite_data_type_usage()
  *	Check for system-defined composite types used in user tables.
@@ -1143,8 +1136,7 @@ check_for_composite_data_type_usage(ClusterInfo *cluster)
 
 	prep_status("Checking for system-defined composite types in user tables");
 
-	snprintf(output_path, sizeof(output_path), "%s/%s",
-			 log_opts.basedir,
+	snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir,
 			 "tables_using_composite.txt");
 
 	/*
@@ -1160,7 +1152,8 @@ check_for_composite_data_type_usage(ClusterInfo *cluster)
 	 */
 	firstUserOid = 16384;
 
-	base_query = psprintf("SELECT t.oid FROM pg_catalog.pg_type t "
+	base_query = psprintf(
+						  "SELECT t.oid FROM pg_catalog.pg_type t "
 						  "LEFT JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid "
 						  " WHERE typtype = 'c' AND (t.oid < %u OR nspname = 'information_schema')",
 						  firstUserOid);
@@ -1172,12 +1165,14 @@ check_for_composite_data_type_usage(ClusterInfo *cluster)
 	if (found)
 	{
 		pg_log(PG_REPORT, "fatal");
-		pg_fatal("Your installation contains system-defined composite types in user tables.\n"
+		pg_fatal("Your installation contains system-defined composite types in "
+				 "user tables.\n"
 				 "These type OIDs are not stable across PostgreSQL versions,\n"
 				 "so this cluster cannot currently be upgraded.  You can\n"
 				 "drop the problem columns and restart the upgrade.\n"
 				 "A list of the problem columns is in the file:\n"
-				 "    %s", output_path);
+				 "    %s",
+				 output_path);
 	}
 	else
 		check_ok();
@@ -1202,15 +1197,15 @@ check_for_reg_data_type_usage(ClusterInfo *cluster)
 
 	prep_status("Checking for reg* data types in user tables");
 
-	snprintf(output_path, sizeof(output_path), "%s/%s",
-			 log_opts.basedir,
+	snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir,
 			 "tables_using_reg.txt");
 
 	/*
 	 * Note: older servers will not have all of these reg* types, so we have
 	 * to write the query like this rather than depending on casts to regtype.
 	 */
-	found = check_for_data_types_usage(cluster,
+	found = check_for_data_types_usage(
+									   cluster,
 									   "SELECT oid FROM pg_catalog.pg_type t "
 									   "WHERE t.typnamespace = "
 									   "        (SELECT oid FROM pg_catalog.pg_namespace "
@@ -1233,12 +1228,15 @@ check_for_reg_data_type_usage(ClusterInfo *cluster)
 	if (found)
 	{
 		pg_log(PG_REPORT, "fatal");
-		pg_fatal("Your installation contains one of the reg* data types in user tables.\n"
+		pg_fatal(
+				 "Your installation contains one of the reg* data types in user "
+				 "tables.\n"
 				 "These data types reference system OIDs that are not preserved by\n"
 				 "pg_upgrade, so this cluster cannot currently be upgraded.  You can\n"
 				 "drop the problem columns and restart the upgrade.\n"
 				 "A list of the problem columns is in the file:\n"
-				 "    %s", output_path);
+				 "    %s",
+				 output_path);
 	}
 	else
 		check_ok();
@@ -1262,12 +1260,14 @@ check_for_aclitem_data_type_usage(ClusterInfo *cluster)
 	if (check_for_data_type_usage(cluster, "pg_catalog.aclitem", output_path))
 	{
 		pg_log(PG_REPORT, "fatal");
-		pg_fatal("Your installation contains the \"aclitem\" data type in user tables.\n"
+		pg_fatal(
+				 "Your installation contains the \"aclitem\" data type in user tables.\n"
 				 "The internal format of \"aclitem\" changed in PostgreSQL version 16\n"
 				 "so this cluster cannot currently be upgraded.  You can drop the\n"
 				 "problem columns and restart the upgrade.  A list of the problem\n"
 				 "columns is in the file:\n"
-				 "    %s", output_path);
+				 "    %s",
+				 output_path);
 	}
 	else
 		check_ok();
@@ -1280,34 +1280,34 @@ check_for_aclitem_data_type_usage(ClusterInfo *cluster)
  *	the exact list.
  */
 static void
-check_for_removed_data_type_usage(ClusterInfo *cluster, const char *version,
+check_for_removed_data_type_usage(ClusterInfo *cluster,
+								  const char *version,
 								  const char *datatype)
 {
 	char		output_path[MAXPGPATH];
 	char		typename[NAMEDATALEN];
 
-	prep_status("Checking for removed \"%s\" data type in user tables",
-				datatype);
+	prep_status("Checking for removed \"%s\" data type in user tables", datatype);
 
-	snprintf(output_path, sizeof(output_path), "tables_using_%s.txt",
-			 datatype);
+	snprintf(output_path, sizeof(output_path), "tables_using_%s.txt", datatype);
 	snprintf(typename, sizeof(typename), "pg_catalog.%s", datatype);
 
 	if (check_for_data_type_usage(cluster, typename, output_path))
 	{
 		pg_log(PG_REPORT, "fatal");
-		pg_fatal("Your installation contains the \"%s\" data type in user tables.\n"
+		pg_fatal(
+				 "Your installation contains the \"%s\" data type in user tables.\n"
 				 "The \"%s\" type has been removed in PostgreSQL version %s,\n"
 				 "so this cluster cannot currently be upgraded.  You can drop the\n"
 				 "problem columns, or change them to another data type, and restart\n"
 				 "the upgrade.  A list of the problem columns is in the file:\n"
-				 "    %s", datatype, datatype, version, output_path);
+				 "    %s",
+				 datatype, datatype, version, output_path);
 	}
 	else
 		check_ok();
 }
 
-
 /*
  * check_for_jsonb_9_4_usage()
  *
@@ -1320,19 +1320,20 @@ check_for_jsonb_9_4_usage(ClusterInfo *cluster)
 
 	prep_status("Checking for incompatible \"jsonb\" data type");
 
-	snprintf(output_path, sizeof(output_path), "%s/%s",
-			 log_opts.basedir,
+	snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir,
 			 "tables_using_jsonb.txt");
 
 	if (check_for_data_type_usage(cluster, "pg_catalog.jsonb", output_path))
 	{
 		pg_log(PG_REPORT, "fatal");
-		pg_fatal("Your installation contains the \"jsonb\" data type in user tables.\n"
+		pg_fatal(
+				 "Your installation contains the \"jsonb\" data type in user tables.\n"
 				 "The internal format of \"jsonb\" changed during 9.4 beta so this\n"
 				 "cluster cannot currently be upgraded.  You can\n"
 				 "drop the problem columns and restart the upgrade.\n"
 				 "A list of the problem columns is in the file:\n"
-				 "    %s", output_path);
+				 "    %s",
+				 output_path);
 	}
 	else
 		check_ok();
@@ -1356,12 +1357,10 @@ check_for_pg_role_prefix(ClusterInfo *cluster)
 
 	prep_status("Checking for roles starting with \"pg_\"");
 
-	snprintf(output_path, sizeof(output_path), "%s/%s",
-			 log_opts.basedir,
+	snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir,
 			 "pg_role_prefix.txt");
 
-	res = executeQueryOrDie(conn,
-							"SELECT oid AS roloid, rolname "
+	res = executeQueryOrDie(conn, "SELECT oid AS roloid, rolname "
 							"FROM pg_catalog.pg_roles "
 							"WHERE rolname ~ '^pg_'");
 
@@ -1371,10 +1370,8 @@ check_for_pg_role_prefix(ClusterInfo *cluster)
 	for (int rowno = 0; rowno < ntups; rowno++)
 	{
 		if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
-			pg_fatal("could not open file \"%s\": %s",
-					 output_path, strerror(errno));
-		fprintf(script, "%s (oid=%s)\n",
-				PQgetvalue(res, rowno, i_rolname),
+			pg_fatal("could not open file \"%s\": %s", output_path, strerror(errno));
+		fprintf(script, "%s (oid=%s)\n", PQgetvalue(res, rowno, i_rolname),
 				PQgetvalue(res, rowno, i_roloid));
 	}
 
@@ -1390,7 +1387,8 @@ check_for_pg_role_prefix(ClusterInfo *cluster)
 				 "\"pg_\" is a reserved prefix for system roles.  The cluster\n"
 				 "cannot be upgraded until these roles are renamed.\n"
 				 "A list of roles starting with \"pg_\" is in the file:\n"
-				 "    %s", output_path);
+				 "    %s",
+				 output_path);
 	}
 	else
 		check_ok();
@@ -1408,8 +1406,7 @@ check_for_user_defined_encoding_conversions(ClusterInfo *cluster)
 
 	prep_status("Checking for user-defined encoding conversions");
 
-	snprintf(output_path, sizeof(output_path), "%s/%s",
-			 log_opts.basedir,
+	snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir,
 			 "encoding_conversions.txt");
 
 	/* Find any user defined encoding conversions */
@@ -1431,29 +1428,27 @@ check_for_user_defined_encoding_conversions(ClusterInfo *cluster)
 		 * #define is ever changed, the cutoff we want to use is the value
 		 * used by pre-version 14 servers, not that of some future version.
 		 */
-		res = executeQueryOrDie(conn,
-								"SELECT c.oid as conoid, c.conname, n.nspname "
-								"FROM pg_catalog.pg_conversion c, "
-								"     pg_catalog.pg_namespace n "
-								"WHERE c.connamespace = n.oid AND "
-								"      c.oid >= 16384");
+		res =
+			executeQueryOrDie(conn, "SELECT c.oid as conoid, c.conname, n.nspname "
+							  "FROM pg_catalog.pg_conversion c, "
+							  "     pg_catalog.pg_namespace n "
+							  "WHERE c.connamespace = n.oid AND "
+							  "      c.oid >= 16384");
 		ntups = PQntuples(res);
 		i_conoid = PQfnumber(res, "conoid");
 		i_conname = PQfnumber(res, "conname");
 		i_nspname = PQfnumber(res, "nspname");
 		for (rowno = 0; rowno < ntups; rowno++)
 		{
-			if (script == NULL &&
-				(script = fopen_priv(output_path, "w")) == NULL)
-				pg_fatal("could not open file \"%s\": %s",
-						 output_path, strerror(errno));
+			if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
+				pg_fatal("could not open file \"%s\": %s", output_path,
+						 strerror(errno));
 			if (!db_used)
 			{
 				fprintf(script, "In database: %s\n", active_db->db_name);
 				db_used = true;
 			}
-			fprintf(script, "  (oid=%s) %s.%s\n",
-					PQgetvalue(res, rowno, i_conoid),
+			fprintf(script, "  (oid=%s) %s.%s\n", PQgetvalue(res, rowno, i_conoid),
 					PQgetvalue(res, rowno, i_nspname),
 					PQgetvalue(res, rowno, i_conname));
 		}
@@ -1467,12 +1462,14 @@ check_for_user_defined_encoding_conversions(ClusterInfo *cluster)
 	{
 		fclose(script);
 		pg_log(PG_REPORT, "fatal");
-		pg_fatal("Your installation contains user-defined encoding conversions.\n"
+		pg_fatal(
+				 "Your installation contains user-defined encoding conversions.\n"
 				 "The conversion function parameters changed in PostgreSQL version 14\n"
 				 "so this cluster cannot currently be upgraded.  You can remove the\n"
 				 "encoding conversions in the old cluster and restart the upgrade.\n"
 				 "A list of user-defined encoding conversions is in the file:\n"
-				 "    %s", output_path);
+				 "    %s",
+				 output_path);
 	}
 	else
 		check_ok();
@@ -1524,7 +1521,8 @@ check_new_cluster_logical_replication_slots(void)
 
 	PQclear(res);
 
-	res = executeQueryOrDie(conn, "SELECT setting FROM pg_settings "
+	res = executeQueryOrDie(
+							conn, "SELECT setting FROM pg_settings "
 							"WHERE name IN ('wal_level', 'max_replication_slots') "
 							"ORDER BY name DESC;");
 
@@ -1534,13 +1532,13 @@ check_new_cluster_logical_replication_slots(void)
 	wal_level = PQgetvalue(res, 0, 0);
 
 	if (strcmp(wal_level, "logical") != 0)
-		pg_fatal("wal_level must be \"logical\", but is set to \"%s\"",
-				 wal_level);
+		pg_fatal("wal_level must be \"logical\", but is set to \"%s\"", wal_level);
 
 	max_replication_slots = atoi(PQgetvalue(res, 1, 0));
 
 	if (nslots_on_old > max_replication_slots)
-		pg_fatal("max_replication_slots (%d) must be greater than or equal to the number of "
+		pg_fatal("max_replication_slots (%d) must be greater than or equal to the "
+				 "number of "
 				 "logical replication slots (%d) on the old cluster",
 				 max_replication_slots, nslots_on_old);
 
@@ -1587,7 +1585,8 @@ check_new_cluster_subscription_configuration(void)
 
 	max_replication_slots = atoi(PQgetvalue(res, 0, 0));
 	if (nsubs_on_old > max_replication_slots)
-		pg_fatal("max_replication_slots (%d) must be greater than or equal to the number of "
+		pg_fatal("max_replication_slots (%d) must be greater than or equal to the "
+				 "number of "
 				 "subscriptions (%d) on the old cluster",
 				 max_replication_slots, nsubs_on_old);
 
@@ -1611,8 +1610,7 @@ check_old_cluster_for_valid_slots(bool live_check)
 
 	prep_status("Checking for valid logical replication slots");
 
-	snprintf(output_path, sizeof(output_path), "%s/%s",
-			 log_opts.basedir,
+	snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir,
 			 "invalid_logical_slots.txt");
 
 	for (int dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
@@ -1626,13 +1624,11 @@ check_old_cluster_for_valid_slots(bool live_check)
 			/* Is the slot usable? */
 			if (slot->invalid)
 			{
-				if (script == NULL &&
-					(script = fopen_priv(output_path, "w")) == NULL)
-					pg_fatal("could not open file \"%s\": %s",
-							 output_path, strerror(errno));
+				if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
+					pg_fatal("could not open file \"%s\": %s", output_path,
+							 strerror(errno));
 
-				fprintf(script, "The slot \"%s\" is invalid\n",
-						slot->slotname);
+				fprintf(script, "The slot \"%s\" is invalid\n", slot->slotname);
 
 				continue;
 			}
@@ -1646,13 +1642,11 @@ check_old_cluster_for_valid_slots(bool live_check)
 			 */
 			if (!live_check && !slot->caught_up)
 			{
-				if (script == NULL &&
-					(script = fopen_priv(output_path, "w")) == NULL)
-					pg_fatal("could not open file \"%s\": %s",
-							 output_path, strerror(errno));
+				if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
+					pg_fatal("could not open file \"%s\": %s", output_path,
+							 strerror(errno));
 
-				fprintf(script,
-						"The slot \"%s\" has not consumed the WAL yet\n",
+				fprintf(script, "The slot \"%s\" has not consumed the WAL yet\n",
 						slot->slotname);
 			}
 		}
@@ -1663,11 +1657,14 @@ check_old_cluster_for_valid_slots(bool live_check)
 		fclose(script);
 
 		pg_log(PG_REPORT, "fatal");
-		pg_fatal("Your installation contains logical replication slots that can't be upgraded.\n"
-				 "You can remove invalid slots and/or consume the pending WAL for other slots,\n"
+		pg_fatal("Your installation contains logical replication slots that can't "
+				 "be upgraded.\n"
+				 "You can remove invalid slots and/or consume the pending WAL for "
+				 "other slots,\n"
 				 "and then restart the upgrade.\n"
 				 "A list of the problematic slots is in the file:\n"
-				 "    %s", output_path);
+				 "    %s",
+				 output_path);
 	}
 
 	check_ok();
@@ -1689,8 +1686,7 @@ check_old_cluster_subscription_state(void)
 
 	prep_status("Checking for subscription state");
 
-	snprintf(output_path, sizeof(output_path), "%s/%s",
-			 log_opts.basedir,
+	snprintf(output_path, sizeof(output_path), "%s/%s", log_opts.basedir,
 			 "subs_invalid.txt");
 	for (int dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
 	{
@@ -1705,8 +1701,8 @@ check_old_cluster_subscription_state(void)
 			 * Check that all the subscriptions have their respective
 			 * replication origin.
 			 */
-			res = executeQueryOrDie(conn,
-									"SELECT d.datname, s.subname "
+			res = executeQueryOrDie(
+									conn, "SELECT d.datname, s.subname "
 									"FROM pg_catalog.pg_subscription s "
 									"LEFT OUTER JOIN pg_catalog.pg_replication_origin o "
 									"	ON o.roname = 'pg_' || s.oid "
@@ -1718,11 +1714,12 @@ check_old_cluster_subscription_state(void)
 			for (int i = 0; i < ntup; i++)
 			{
 				if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
-					pg_fatal("could not open file \"%s\": %s",
-							 output_path, strerror(errno));
-				fprintf(script, "The replication origin is missing for database:\"%s\" subscription:\"%s\"\n",
-						PQgetvalue(res, i, 0),
-						PQgetvalue(res, i, 1));
+					pg_fatal("could not open file \"%s\": %s", output_path,
+							 strerror(errno));
+				fprintf(script,
+						"The replication origin is missing for database:\"%s\" "
+						"subscription:\"%s\"\n",
+						PQgetvalue(res, i, 0), PQgetvalue(res, i, 1));
 			}
 			PQclear(res);
 		}
@@ -1755,8 +1752,8 @@ check_old_cluster_subscription_state(void)
 		 * SUBREL_STATE_UNKNOWN: These states are not stored in the catalog,
 		 * so we need not allow these states.
 		 */
-		res = executeQueryOrDie(conn,
-								"SELECT r.srsubstate, s.subname, n.nspname, c.relname "
+		res = executeQueryOrDie(
+								conn, "SELECT r.srsubstate, s.subname, n.nspname, c.relname "
 								"FROM pg_catalog.pg_subscription_rel r "
 								"LEFT JOIN pg_catalog.pg_subscription s"
 								"	ON r.srsubid = s.oid "
@@ -1771,15 +1768,14 @@ check_old_cluster_subscription_state(void)
 		for (int i = 0; i < ntup; i++)
 		{
 			if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
-				pg_fatal("could not open file \"%s\": %s",
-						 output_path, strerror(errno));
-
-			fprintf(script, "The table sync state \"%s\" is not allowed for database:\"%s\" subscription:\"%s\" schema:\"%s\" relation:\"%s\"\n",
-					PQgetvalue(res, i, 0),
-					active_db->db_name,
-					PQgetvalue(res, i, 1),
-					PQgetvalue(res, i, 2),
-					PQgetvalue(res, i, 3));
+				pg_fatal("could not open file \"%s\": %s", output_path,
+						 strerror(errno));
+
+			fprintf(script,
+					"The table sync state \"%s\" is not allowed for database:\"%s\" "
+					"subscription:\"%s\" schema:\"%s\" relation:\"%s\"\n",
+					PQgetvalue(res, i, 0), active_db->db_name, PQgetvalue(res, i, 1),
+					PQgetvalue(res, i, 2), PQgetvalue(res, i, 3));
 		}
 
 		PQclear(res);
@@ -1790,10 +1786,13 @@ check_old_cluster_subscription_state(void)
 	{
 		fclose(script);
 		pg_log(PG_REPORT, "fatal");
-		pg_fatal("Your installation contains subscriptions without origin or having relations not in i (initialize) or r (ready) state.\n"
-				 "You can allow the initial sync to finish for all relations and then restart the upgrade.\n"
+		pg_fatal("Your installation contains subscriptions without origin or "
+				 "having relations not in i (initialize) or r (ready) state.\n"
+				 "You can allow the initial sync to finish for all relations and "
+				 "then restart the upgrade.\n"
 				 "A list of the problematic subscriptions is in the file:\n"
-				 "    %s", output_path);
+				 "    %s",
+				 output_path);
 	}
 	else
 		check_ok();
diff --git a/src/bin/pg_upgrade/file.c b/src/bin/pg_upgrade/file.c
index f91cc548ce..7272c7fdb7 100644
--- a/src/bin/pg_upgrade/file.c
+++ b/src/bin/pg_upgrade/file.c
@@ -37,6 +37,23 @@ cloneFile(const char *src, const char *dst, const char *schemaName,
 	pg_copyfile_offload(src, dst, action, PG_COPYFILE_IOCTL_FICLONE);
 }
 
+/*
+ * copyFileByRange()
+ *
+ * Copies a relation file from src to dst.
+ * schemaName/relName are relation's SQL name (used for error messages only).
+ */
+void
+copyFileByRange(const char *src, const char *dst, const char *schemaName,
+				const char *relName)
+{
+	char		action[1024];
+
+	snprintf(action, sizeof(action) - 1, "relation \"%s.%s\"", schemaName,
+			 relName);
+	pg_copyfile_offload(src, dst, action, PG_COPYFILE_COPY_FILE_RANGE);
+}
+
 /*
  * copyFile()
  *
@@ -264,6 +281,23 @@ check_file_clone(void)
 								  PG_COPYFILE_IOCTL_FICLONE);
 }
 
+void
+check_copy_file_range(void)
+{
+	char		existing_file[MAXPGPATH];
+	char		new_link_file[MAXPGPATH];
+
+	snprintf(existing_file, sizeof(existing_file), "%s/PG_VERSION",
+			 old_cluster.pgdata);
+	snprintf(new_link_file, sizeof(new_link_file),
+			 "%s/PG_VERSION.copy_file_range_test", new_cluster.pgdata);
+	unlink(new_link_file);		/* might fail */
+
+	/* will throw error in case it is not supported */
+	pg_copyfile_offload_supported(existing_file, new_link_file, NULL,
+								  PG_COPYFILE_COPY_FILE_RANGE);
+}
+
 void
 check_hard_link(void)
 {
@@ -278,7 +312,8 @@ check_hard_link(void)
 
 	if (link(existing_file, new_link_file) < 0)
 		pg_fatal(
-				 "could not create hard link between old and new data directories: %s\n"
+				 "could not create hard link between old and new data directories: "
+				 "%s\n"
 				 "In link mode the old and new data directories must be on the same "
 				 "file system.",
 				 strerror(errno));
diff --git a/src/bin/pg_upgrade/option.c b/src/bin/pg_upgrade/option.c
index b9d900d0db..9e992c7bbf 100644
--- a/src/bin/pg_upgrade/option.c
+++ b/src/bin/pg_upgrade/option.c
@@ -20,16 +20,13 @@
 #include "utils/pidfile.h"
 
 static void usage(void);
-static void check_required_directory(char **dirpath,
-									 const char *envVarName, bool useCwd,
-									 const char *cmdLineOption, const char *description,
-									 bool missingOk);
+static void check_required_directory(char **dirpath, const char *envVarName,
+									 bool useCwd, const char *cmdLineOption,
+									 const char *description, bool missingOk);
 #define FIX_DEFAULT_READ_ONLY "-c default_transaction_read_only=false"
 
-
 UserOpts	user_opts;
 
-
 /*
  * parseCommandLine()
  *
@@ -59,9 +56,9 @@ parseCommandLine(int argc, char *argv[])
 		{"clone", no_argument, NULL, 1},
 		{"copy", no_argument, NULL, 2},
 		{"sync-method", required_argument, NULL, 3},
+		{"copy-file-range", no_argument, NULL, 3},
 
-		{NULL, 0, NULL, 0}
-	};
+	{NULL, 0, NULL, 0}};
 	int			option;			/* Command line option */
 	int			optindex = 0;	/* used by getopt_long */
 	int			os_user_effective_id;
@@ -73,8 +70,10 @@ parseCommandLine(int argc, char *argv[])
 	os_info.progname = get_progname(argv[0]);
 
 	/* Process libpq env. variables; load values here for usage() output */
-	old_cluster.port = getenv("PGPORTOLD") ? atoi(getenv("PGPORTOLD")) : DEF_PGUPORT;
-	new_cluster.port = getenv("PGPORTNEW") ? atoi(getenv("PGPORTNEW")) : DEF_PGUPORT;
+	old_cluster.port =
+		getenv("PGPORTOLD") ? atoi(getenv("PGPORTOLD")) : DEF_PGUPORT;
+	new_cluster.port =
+		getenv("PGPORTNEW") ? atoi(getenv("PGPORTNEW")) : DEF_PGUPORT;
 
 	os_user_effective_id = get_user_info(&os_info.user);
 	/* we override just the database user name;  we got the OS id above */
@@ -197,12 +196,13 @@ parseCommandLine(int argc, char *argv[])
 			case 1:
 				user_opts.transfer_mode = TRANSFER_MODE_CLONE;
 				break;
-
 			case 2:
 				user_opts.transfer_mode = TRANSFER_MODE_COPY;
 				break;
-
 			case 3:
+				user_opts.transfer_mode = TRANSFER_MODE_COPY_FILE_RANGE;
+				break;
+			case 4:
 				if (!parse_sync_method(optarg, &unused))
 					exit(1);
 				user_opts.sync_method = pg_strdup(optarg);
@@ -229,8 +229,8 @@ parseCommandLine(int argc, char *argv[])
 	/* Turn off read-only mode;  add prefix to PGOPTIONS? */
 	if (getenv("PGOPTIONS"))
 	{
-		char	   *pgoptions = psprintf("%s %s", FIX_DEFAULT_READ_ONLY,
-										 getenv("PGOPTIONS"));
+		char	   *pgoptions =
+			psprintf("%s %s", FIX_DEFAULT_READ_ONLY, getenv("PGOPTIONS"));
 
 		setenv("PGOPTIONS", pgoptions, 1);
 		pfree(pgoptions);
@@ -239,16 +239,16 @@ parseCommandLine(int argc, char *argv[])
 		setenv("PGOPTIONS", FIX_DEFAULT_READ_ONLY, 1);
 
 	/* Get values from env if not already set */
-	check_required_directory(&old_cluster.bindir, "PGBINOLD", false,
-							 "-b", _("old cluster binaries reside"), false);
-	check_required_directory(&new_cluster.bindir, "PGBINNEW", false,
-							 "-B", _("new cluster binaries reside"), true);
-	check_required_directory(&old_cluster.pgdata, "PGDATAOLD", false,
-							 "-d", _("old cluster data resides"), false);
-	check_required_directory(&new_cluster.pgdata, "PGDATANEW", false,
-							 "-D", _("new cluster data resides"), false);
-	check_required_directory(&user_opts.socketdir, "PGSOCKETDIR", true,
-							 "-s", _("sockets will be created"), false);
+	check_required_directory(&old_cluster.bindir, "PGBINOLD", false, "-b",
+							 _("old cluster binaries reside"), false);
+	check_required_directory(&new_cluster.bindir, "PGBINNEW", false, "-B",
+							 _("new cluster binaries reside"), true);
+	check_required_directory(&old_cluster.pgdata, "PGDATAOLD", false, "-d",
+							 _("old cluster data resides"), false);
+	check_required_directory(&new_cluster.pgdata, "PGDATANEW", false, "-D",
+							 _("new cluster data resides"), false);
+	check_required_directory(&user_opts.socketdir, "PGSOCKETDIR", true, "-s",
+							 _("sockets will be created"), false);
 
 #ifdef WIN32
 
@@ -268,47 +268,73 @@ parseCommandLine(int argc, char *argv[])
 			pg_fatal("could not determine current directory");
 		canonicalize_path(cwd);
 		if (path_is_prefix_of_path(new_cluster_pgdata, cwd))
-			pg_fatal("cannot run pg_upgrade from inside the new cluster data directory on Windows");
+			pg_fatal("cannot run pg_upgrade from inside the new cluster data "
+					 "directory on Windows");
 	}
 #endif
 }
 
-
 static void
 usage(void)
 {
-	printf(_("pg_upgrade upgrades a PostgreSQL cluster to a different major version.\n\n"));
+	printf(_("pg_upgrade upgrades a PostgreSQL cluster to a different major "
+			 "version.\n\n"));
 	printf(_("Usage:\n"));
 	printf(_("  pg_upgrade [OPTION]...\n\n"));
 	printf(_("Options:\n"));
-	printf(_("  -b, --old-bindir=BINDIR       old cluster executable directory\n"));
-	printf(_("  -B, --new-bindir=BINDIR       new cluster executable directory (default\n"
+	printf(
+		   _("  -b, --old-bindir=BINDIR       old cluster executable directory\n"));
+	printf(_("  -B, --new-bindir=BINDIR       new cluster executable directory "
+			 "(default\n"
 			 "                                same directory as pg_upgrade)\n"));
-	printf(_("  -c, --check                   check clusters only, don't change any data\n"));
+	printf(_("  -c, --check                   check clusters only, don't change "
+			 "any data\n"));
 	printf(_("  -d, --old-datadir=DATADIR     old cluster data directory\n"));
 	printf(_("  -D, --new-datadir=DATADIR     new cluster data directory\n"));
-	printf(_("  -j, --jobs=NUM                number of simultaneous processes or threads to use\n"));
-	printf(_("  -k, --link                    link instead of copying files to new cluster\n"));
-	printf(_("  -N, --no-sync                 do not wait for changes to be written safely to disk\n"));
-	printf(_("  -o, --old-options=OPTIONS     old cluster options to pass to the server\n"));
-	printf(_("  -O, --new-options=OPTIONS     new cluster options to pass to the server\n"));
-	printf(_("  -p, --old-port=PORT           old cluster port number (default %d)\n"), old_cluster.port);
-	printf(_("  -P, --new-port=PORT           new cluster port number (default %d)\n"), new_cluster.port);
-	printf(_("  -r, --retain                  retain SQL and log files after success\n"));
-	printf(_("  -s, --socketdir=DIR           socket directory to use (default current dir.)\n"));
-	printf(_("  -U, --username=NAME           cluster superuser (default \"%s\")\n"), os_info.user);
-	printf(_("  -v, --verbose                 enable verbose internal logging\n"));
-	printf(_("  -V, --version                 display version information, then exit\n"));
-	printf(_("  --clone                       clone instead of copying files to new cluster\n"));
-	printf(_("  --copy                        copy files to new cluster (default)\n"));
-	printf(_("  --sync-method=METHOD          set method for syncing files to disk\n"));
+	printf(_("  -j, --jobs=NUM                number of simultaneous processes "
+			 "or threads to use\n"));
+	printf(_("  -k, --link                    link instead of copying files to "
+			 "new cluster\n"));
+	printf(_("  -N, --no-sync                 do not wait for changes to be "
+			 "written safely to disk\n"));
+	printf(_("  -o, --old-options=OPTIONS     old cluster options to pass to the "
+			 "server\n"));
+	printf(_("  -O, --new-options=OPTIONS     new cluster options to pass to the "
+			 "server\n"));
+	printf(_("  -p, --old-port=PORT           old cluster port number (default "
+			 "%d)\n"),
+		   old_cluster.port);
+	printf(_("  -P, --new-port=PORT           new cluster port number (default "
+			 "%d)\n"),
+		   new_cluster.port);
+	printf(_("  -r, --retain                  retain SQL and log files after "
+			 "success\n"));
+	printf(_("  -s, --socketdir=DIR           socket directory to use (default "
+			 "current dir.)\n"));
+	printf(
+		   _("  -U, --username=NAME           cluster superuser (default \"%s\")\n"),
+		   os_info.user);
+	printf(
+		   _("  -v, --verbose                 enable verbose internal logging\n"));
+	printf(_("  -V, --version                 display version information, then "
+			 "exit\n"));
+	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(_("  --sync-method=METHOD          set method for syncing files to "
+			 "disk\n"));
 	printf(_("  -?, --help                    show this help, then exit\n"));
 	printf(_("\n"
 			 "Before running pg_upgrade you must:\n"
 			 "  create a new database cluster (using the new version of initdb)\n"
 			 "  shutdown the postmaster servicing the old cluster\n"
 			 "  shutdown the postmaster servicing the new cluster\n"));
-	printf(_("\n"
+	printf(
+		   _("\n"
 			 "When you run pg_upgrade, you must provide the following information:\n"
 			 "  the data directory for the old cluster  (-d DATADIR)\n"
 			 "  the data directory for the new cluster  (-D DATADIR)\n"
@@ -316,7 +342,8 @@ usage(void)
 			 "  the \"bin\" directory for the new version (-B BINDIR)\n"));
 	printf(_("\n"
 			 "For example:\n"
-			 "  pg_upgrade -d oldCluster/data -D newCluster/data -b oldCluster/bin -B newCluster/bin\n"
+			 "  pg_upgrade -d oldCluster/data -D newCluster/data -b "
+			 "oldCluster/bin -B newCluster/bin\n"
 			 "or\n"));
 #ifndef WIN32
 	printf(_("  $ export PGDATAOLD=oldCluster/data\n"
@@ -335,25 +362,25 @@ usage(void)
 	printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
 }
 
-
 /*
  * check_required_directory()
  *
  * Checks a directory option.
- *	dirpath		  - the directory name supplied on the command line, or NULL
- *	envVarName	  - the name of an environment variable to get if dirpath is NULL
- *	useCwd		  - true if OK to default to CWD
+ *	dirpath		  - the directory name supplied on the command line, or
+ *NULL envVarName	  - the name of an environment variable to get if
+ *dirpath is NULL useCwd		  - true if OK to default to CWD
  *	cmdLineOption - the command line option for this directory
  *	description   - a description of this directory option
- *	missingOk	  - true if OK that both dirpath and envVarName are not existing
+ *	missingOk	  - true if OK that both dirpath and envVarName are not
+ *existing
  *
  * We use the last two arguments to construct a meaningful error message if the
  * user hasn't provided the required directory name.
  */
 static void
-check_required_directory(char **dirpath, const char *envVarName, bool useCwd,
-						 const char *cmdLineOption, const char *description,
-						 bool missingOk)
+check_required_directory(char **dirpath, const char *envVarName,
+						 bool useCwd, const char *cmdLineOption,
+						 const char *description, bool missingOk)
 {
 	if (*dirpath == NULL || strlen(*dirpath) == 0)
 	{
@@ -373,7 +400,8 @@ check_required_directory(char **dirpath, const char *envVarName, bool useCwd,
 			return;
 		else
 			pg_fatal("You must identify the directory where the %s.\n"
-					 "Please use the %s command-line option or the %s environment variable.",
+					 "Please use the %s command-line option or the %s environment "
+					 "variable.",
 					 description, cmdLineOption, envVarName);
 	}
 
@@ -440,13 +468,12 @@ adjust_data_dir(ClusterInfo *cluster)
 
 	if ((output = popen(cmd, "r")) == NULL ||
 		fgets(cmd_output, sizeof(cmd_output), output) == NULL)
-		pg_fatal("could not get data directory using %s: %s",
-				 cmd, strerror(errno));
+		pg_fatal("could not get data directory using %s: %s", cmd, strerror(errno));
 
 	rc = pclose(output);
 	if (rc != 0)
-		pg_fatal("could not get data directory using %s: %s",
-				 cmd, wait_result_to_str(rc));
+		pg_fatal("could not get data directory using %s: %s", cmd,
+				 wait_result_to_str(rc));
 
 	/* strip trailing newline and carriage return */
 	(void) pg_strip_crlf(cmd_output);
@@ -456,7 +483,6 @@ adjust_data_dir(ClusterInfo *cluster)
 	check_ok();
 }
 
-
 /*
  * get_sock_dir
  *
@@ -483,19 +509,17 @@ get_sock_dir(ClusterInfo *cluster, bool live_check)
 		FILE	   *fp;
 		int			lineno;
 
-		snprintf(filename, sizeof(filename), "%s/postmaster.pid",
-				 cluster->pgdata);
+		snprintf(filename, sizeof(filename), "%s/postmaster.pid", cluster->pgdata);
 		if ((fp = fopen(filename, "r")) == NULL)
-			pg_fatal("could not open file \"%s\": %s",
-					 filename, strerror(errno));
+			pg_fatal("could not open file \"%s\": %s", filename, strerror(errno));
 
 		for (lineno = 1;
 			 lineno <= Max(LOCK_FILE_LINE_PORT, LOCK_FILE_LINE_SOCKET_DIR);
 			 lineno++)
 		{
 			if (fgets(line, sizeof(line), fp) == NULL)
-				pg_fatal("could not read line %d from file \"%s\": %s",
-						 lineno, filename, strerror(errno));
+				pg_fatal("could not read line %d from file \"%s\": %s", lineno,
+						 filename, strerror(errno));
 
 			/* potentially overwrite user-supplied value */
 			if (lineno == LOCK_FILE_LINE_PORT)
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index d63f13fffc..f993d7255e 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -5,10 +5,10 @@
  *	src/bin/pg_upgrade/pg_upgrade.h
  */
 
-#include <unistd.h>
 #include <assert.h>
 #include <sys/stat.h>
 #include <sys/time.h>
+#include <unistd.h>
 
 #include "common/relpath.h"
 #include "libpq-fe.h"
@@ -17,18 +17,18 @@
 #undef pg_fatal
 
 /* Use port in the private/dynamic port number range */
-#define DEF_PGUPORT			50432
+#define DEF_PGUPORT 50432
 
-#define MAX_STRING			1024
-#define QUERY_ALLOC			8192
+#define MAX_STRING 1024
+#define QUERY_ALLOC 8192
 
-#define MESSAGE_WIDTH		62
+#define MESSAGE_WIDTH 62
 
-#define GET_MAJOR_VERSION(v)	((v) / 100)
+#define GET_MAJOR_VERSION(v) ((v) / 100)
 
 /* contains both global db information and CREATE DATABASE commands */
-#define GLOBALS_DUMP_FILE	"pg_upgrade_dump_globals.sql"
-#define DB_DUMP_FILE_MASK	"pg_upgrade_dump_%u.custom"
+#define GLOBALS_DUMP_FILE "pg_upgrade_dump_globals.sql"
+#define DB_DUMP_FILE_MASK "pg_upgrade_dump_%u.custom"
 
 /*
  * Base directories that include all the files generated internally, from the
@@ -36,14 +36,14 @@
  * BASE_OUTPUTDIR/$timestamp/{LOG_OUTPUTDIR,DUMP_OUTPUTDIR} to ensure their
  * uniqueness in each run.
  */
-#define BASE_OUTPUTDIR		"pg_upgrade_output.d"
-#define LOG_OUTPUTDIR		 "log"
-#define DUMP_OUTPUTDIR		 "dump"
+#define BASE_OUTPUTDIR "pg_upgrade_output.d"
+#define LOG_OUTPUTDIR "log"
+#define DUMP_OUTPUTDIR "dump"
 
-#define DB_DUMP_LOG_FILE_MASK	"pg_upgrade_dump_%u.log"
-#define SERVER_LOG_FILE		"pg_upgrade_server.log"
-#define UTILITY_LOG_FILE	"pg_upgrade_utility.log"
-#define INTERNAL_LOG_FILE	"pg_upgrade_internal.log"
+#define DB_DUMP_LOG_FILE_MASK "pg_upgrade_dump_%u.log"
+#define SERVER_LOG_FILE "pg_upgrade_server.log"
+#define UTILITY_LOG_FILE "pg_upgrade_utility.log"
+#define INTERNAL_LOG_FILE "pg_upgrade_internal.log"
 
 extern char *output_files[];
 
@@ -64,44 +64,42 @@ extern char *output_files[];
  * the error message appropriately.
  */
 #ifndef WIN32
-#define SERVER_START_LOG_FILE	SERVER_LOG_FILE
-#define SERVER_STOP_LOG_FILE	SERVER_LOG_FILE
+#define SERVER_START_LOG_FILE SERVER_LOG_FILE
+#define SERVER_STOP_LOG_FILE SERVER_LOG_FILE
 #else
-#define SERVER_START_LOG_FILE	"pg_upgrade_server_start.log"
+#define SERVER_START_LOG_FILE "pg_upgrade_server_start.log"
 /*
  *	"pg_ctl start" keeps SERVER_START_LOG_FILE and SERVER_LOG_FILE open
  *	while the server is running, so we use UTILITY_LOG_FILE for "pg_ctl
  *	stop".
  */
-#define SERVER_STOP_LOG_FILE	UTILITY_LOG_FILE
+#define SERVER_STOP_LOG_FILE UTILITY_LOG_FILE
 #endif
 
-
 #ifndef WIN32
-#define pg_mv_file			rename
-#define PATH_SEPARATOR		'/'
-#define PATH_QUOTE	'\''
-#define RM_CMD				"rm -f"
-#define RMDIR_CMD			"rm -rf"
-#define SCRIPT_PREFIX		"./"
-#define SCRIPT_EXT			"sh"
-#define ECHO_QUOTE	"'"
-#define ECHO_BLANK	""
+#define pg_mv_file rename
+#define PATH_SEPARATOR '/'
+#define PATH_QUOTE '\''
+#define RM_CMD "rm -f"
+#define RMDIR_CMD "rm -rf"
+#define SCRIPT_PREFIX "./"
+#define SCRIPT_EXT "sh"
+#define ECHO_QUOTE "'"
+#define ECHO_BLANK ""
 #else
-#define pg_mv_file			pgrename
-#define PATH_SEPARATOR		'\\'
-#define PATH_QUOTE	'"'
+#define pg_mv_file pgrename
+#define PATH_SEPARATOR '\\'
+#define PATH_QUOTE '"'
 /* @ prefix disables command echo in .bat files */
-#define RM_CMD				"@DEL /q"
-#define RMDIR_CMD			"@RMDIR /s/q"
-#define SCRIPT_PREFIX		""
-#define SCRIPT_EXT			"bat"
-#define EXE_EXT				".exe"
-#define ECHO_QUOTE	""
-#define ECHO_BLANK	"."
+#define RM_CMD "@DEL /q"
+#define RMDIR_CMD "@RMDIR /s/q"
+#define SCRIPT_PREFIX ""
+#define SCRIPT_EXT "bat"
+#define EXE_EXT ".exe"
+#define ECHO_QUOTE ""
+#define ECHO_BLANK "."
 #endif
 
-
 /*
  * The format of visibility map was changed with this 9.6 commit.
  */
@@ -126,7 +124,6 @@ extern char *output_files[];
  */
 #define JSONB_FORMAT_CHANGE_CAT_VER 201409291
 
-
 /*
  * Each relation is represented by a relinfo structure.
  */
@@ -255,6 +252,7 @@ typedef enum
 	TRANSFER_MODE_CLONE,
 	TRANSFER_MODE_COPY,
 	TRANSFER_MODE_LINK,
+	TRANSFER_MODE_COPY_FILE_RANGE,
 } transferMode;
 
 /*
@@ -270,7 +268,6 @@ typedef enum
 	PG_FATAL,
 } eLogType;
 
-
 /*
  * cluster
  *
@@ -295,10 +292,9 @@ typedef struct
 	const char *tablespace_suffix;	/* directory specification */
 } ClusterInfo;
 
-
 /*
  *	LogOpts
-*/
+ */
 typedef struct
 {
 	FILE	   *internal;		/* internal log FILE */
@@ -312,10 +308,9 @@ typedef struct
 	bool		isatty;			/* is stdout a tty */
 } LogOpts;
 
-
 /*
  *	UserOpts
-*/
+ */
 typedef struct
 {
 	bool		check;			/* true -> ask user for permission to make
@@ -348,7 +343,6 @@ typedef struct
 	ClusterInfo *running_cluster;
 } OSInfo;
 
-
 /*
  * Global variables
  */
@@ -358,7 +352,6 @@ extern ClusterInfo old_cluster,
 			new_cluster;
 extern OSInfo os_info;
 
-
 /* check.c */
 
 void		output_check_banner(bool live_check);
@@ -371,44 +364,45 @@ void		check_cluster_versions(void);
 void		check_cluster_compatibility(bool live_check);
 void		create_script_for_old_cluster_deletion(char **deletion_script_file_name);
 
-
 /* controldata.c */
 
 void		get_control_data(ClusterInfo *cluster, bool live_check);
 void		check_control_data(ControlData *oldctrl, ControlData *newctrl);
 void		disable_old_cluster(void);
 
-
 /* dump.c */
 
 void		generate_old_dump(void);
 
-
 /* exec.c */
 
-#define EXEC_PSQL_ARGS "--echo-queries --set ON_ERROR_STOP=on --no-psqlrc --dbname=template1"
+#define EXEC_PSQL_ARGS                                                         \
+  "--echo-queries --set ON_ERROR_STOP=on --no-psqlrc --dbname=template1"
 
 bool		exec_prog(const char *log_filename, const char *opt_log_file,
-					  bool report_error, bool exit_on_error, const char *fmt,...) pg_attribute_printf(5, 6);
+					  bool report_error, bool exit_on_error, const char *fmt,...)
+			pg_attribute_printf(5, 6);
 void		verify_directories(void);
 bool		pid_lock_file_exists(const char *datadir);
 
-
 /* file.c */
 
-void		cloneFile(const char *src, const char *dst,
-					  const char *schemaName, const char *relName);
-void		copyFile(const char *src, const char *dst,
-					 const char *schemaName, const char *relName);
-void		linkFile(const char *src, const char *dst,
-					 const char *schemaName, const char *relName);
+void		cloneFile(const char *src, const char *dst, const char *schemaName,
+					  const char *relName);
+void		copyFile(const char *src, const char *dst, const char *schemaName,
+					 const char *relName);
+void		copyFileByRange(const char *src, const char *dst, const char *schemaName,
+							const char *relName);
+void		linkFile(const char *src, const char *dst, const char *schemaName,
+					 const char *relName);
 void		rewriteVisibilityMap(const char *fromfile, const char *tofile,
 								 const char *schemaName, const char *relName);
 void		check_file_clone(void);
+void		check_copy_file_range(void);
 void		check_hard_link(void);
 
 /* fopen_priv() is no longer different from fopen() */
-#define fopen_priv(path, mode)	fopen(path, mode)
+#define fopen_priv(path, mode) fopen(path, mode)
 
 /* function.c */
 
@@ -417,9 +411,8 @@ void		check_loadable_libraries(void);
 
 /* info.c */
 
-FileNameMap *gen_db_file_maps(DbInfo *old_db,
-							  DbInfo *new_db, int *nmaps, const char *old_pgdata,
-							  const char *new_pgdata);
+FileNameMap *gen_db_file_maps(DbInfo *old_db, DbInfo *new_db, int *nmaps,
+							  const char *old_pgdata, const char *new_pgdata);
 void		get_db_rel_and_slot_infos(ClusterInfo *cluster, bool live_check);
 int			count_old_cluster_logical_slots(void);
 int			count_old_cluster_subscriptions(void);
@@ -432,21 +425,21 @@ void		get_sock_dir(ClusterInfo *cluster, bool live_check);
 
 /* relfilenumber.c */
 
-void		transfer_all_new_tablespaces(DbInfoArr *old_db_arr,
-										 DbInfoArr *new_db_arr, char *old_pgdata, char *new_pgdata);
-void		transfer_all_new_dbs(DbInfoArr *old_db_arr,
-								 DbInfoArr *new_db_arr, char *old_pgdata, char *new_pgdata,
+void		transfer_all_new_tablespaces(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
+										 char *old_pgdata, char *new_pgdata);
+void		transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
+								 char *old_pgdata, char *new_pgdata,
 								 char *old_tablespace);
 
 /* tablespace.c */
 
 void		init_tablespaces(void);
 
-
 /* server.c */
 
 PGconn	   *connectToServer(ClusterInfo *cluster, const char *db_name);
-PGresult   *executeQueryOrDie(PGconn *conn, const char *fmt,...) pg_attribute_printf(2, 3);
+PGresult   *executeQueryOrDie(PGconn *conn, const char *fmt,...)
+			pg_attribute_printf(2, 3);
 
 char	   *cluster_conn_opts(ClusterInfo *cluster);
 
@@ -455,34 +448,31 @@ void		stop_postmaster(bool in_atexit);
 uint32		get_major_server_version(ClusterInfo *cluster);
 void		check_pghost_envvar(void);
 
-
 /* util.c */
 
 char	   *quote_identifier(const char *s);
 int			get_user_info(char **user_name_p);
 void		check_ok(void);
-void		report_status(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3);
+void		report_status(eLogType type, const char *fmt,...)
+			pg_attribute_printf(2, 3);
 void		pg_log(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3);
-void		pg_fatal(const char *fmt,...) pg_attribute_printf(1, 2) pg_attribute_noreturn();
+void		pg_fatal(const char *fmt,...) pg_attribute_printf(1, 2)
+			pg_attribute_noreturn();
 void		end_progress_output(void);
 void		cleanup_output_dirs(void);
 void		prep_status(const char *fmt,...) pg_attribute_printf(1, 2);
 void		prep_status_progress(const char *fmt,...) pg_attribute_printf(1, 2);
 unsigned int str2uint(const char *str);
 
-
 /* version.c */
 
-bool		check_for_data_types_usage(ClusterInfo *cluster,
-									   const char *base_query,
+bool		check_for_data_types_usage(ClusterInfo *cluster, const char *base_query,
 									   const char *output_path);
-bool		check_for_data_type_usage(ClusterInfo *cluster,
-									  const char *type_name,
+bool		check_for_data_type_usage(ClusterInfo *cluster, const char *type_name,
 									  const char *output_path);
 void		old_9_3_check_for_line_data_type_usage(ClusterInfo *cluster);
 void		old_9_6_check_for_unknown_data_type_usage(ClusterInfo *cluster);
-void		old_9_6_invalidate_hash_indexes(ClusterInfo *cluster,
-											bool check_mode);
+void		old_9_6_invalidate_hash_indexes(ClusterInfo *cluster, bool check_mode);
 
 void		old_11_check_for_sql_identifier_data_type_usage(ClusterInfo *cluster);
 void		report_extension_updates(ClusterInfo *cluster);
-- 
2.30.2

