From f83a0a9f80614e18b780e7636e5c2e567b2f701e Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Sun, 30 Apr 2023 15:36:20 +1200
Subject: [PATCH 08/11] Teach copy_file() to concatenate segmented files.

This means that relations are automatically converted to large file
format during COPY DATABASE ... STRATEGY=FILE_COPY and ALTER TABLE ...
SET TABLESPACE operations.
---
 src/backend/storage/file/copydir.c | 43 +++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/src/backend/storage/file/copydir.c b/src/backend/storage/file/copydir.c
index 497d357d8c..0b472f1ac2 100644
--- a/src/backend/storage/file/copydir.c
+++ b/src/backend/storage/file/copydir.c
@@ -71,7 +71,19 @@ copydir(const char *fromdir, const char *todir, bool recurse)
 				copydir(fromfile, tofile, true);
 		}
 		else if (xlde_type == PGFILETYPE_REG)
+		{
+			const char *s;
+
+			/*
+			 * Skip legacy segment files ending in ".N".  copy_file() will deal
+			 * with those.
+			 */
+			s = strrchr(fromfile, '.');
+			if (s && strspn(s + 1, "0123456789") == strlen(s + 1))
+				continue;
+
 			copy_file(fromfile, tofile);
+		}
 	}
 	FreeDir(xldir);
 
@@ -117,6 +129,7 @@ void
 copy_file(const char *fromfile, const char *tofile)
 {
 	char	   *buffer;
+	int			segno;
 	int			srcfd;
 	int			dstfd;
 	int			nbytes;
@@ -154,6 +167,8 @@ copy_file(const char *fromfile, const char *tofile)
 	buffer = palloc(COPY_BUF_SIZE);
 #endif
 
+	segno = 0;
+
 	/*
 	 * Open the files
 	 */
@@ -248,8 +263,34 @@ copy_file(const char *fromfile, const char *tofile)
 			}
 		}
 
+		/*
+		 * If we ran out of source data on the expected boundary of a legacy
+		 * relation file segment, try opening the next segment.
+		 */
 		if (nbytes == 0)
-			break;
+		{
+			char		nextpath[MAXPGPATH];
+			int			nextfd;
+
+			if (offset % (RELSEG_SIZE * BLCKSZ) != 0)
+				break;
+
+			snprintf(nextpath, sizeof(nextpath), "%s.%d", fromfile, ++segno);
+			nextfd = OpenTransientFile(nextpath, O_RDONLY | PG_BINARY);
+			if (nextfd < 0)
+			{
+				if (errno == ENOENT)
+					break;
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not open file \"%s\": %m", nextpath)));
+			}
+			if (CloseTransientFile(srcfd) != 0)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not close file \"%s\": %m", fromfile)));
+			srcfd = nextfd;
+		}
 	}
 
 	if (offset > flush_offset)
-- 
2.40.1

