From 1ca15dcd52fd77a70a596a944becb62a366e6cbe Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Fri, 6 Sep 2024 10:32:24 +1200
Subject: [PATCH v3 2/3] Introduce GetRelationPathInPlace().

This is like GetRelationPath(), but writes the result into a
caller-supplied buffer.  This variant can be used in a critical section,
because it doesn't allocate memory.

Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/18146-04e908c662113ad5%40postgresql.org
---
 src/common/relpath.c         | 57 ++++++++++++++++++++++++++++--------
 src/include/common/relpath.h |  3 ++
 2 files changed, 48 insertions(+), 12 deletions(-)

diff --git a/src/common/relpath.c b/src/common/relpath.c
index 9f2e00e83e4..f880ea4d0ba 100644
--- a/src/common/relpath.c
+++ b/src/common/relpath.c
@@ -142,7 +142,32 @@ char *
 GetRelationPath(Oid dbOid, Oid spcOid, RelFileNumber relNumber,
 				int procNumber, ForkNumber forkNumber)
 {
-	char	   *path;
+	char		path[MAXPGPATH];
+	char	   *result;
+	size_t		size;
+
+	size = GetRelationPathInPlace(path, dbOid, spcOid, relNumber, procNumber, forkNumber);
+
+	/* String plus NUL terminator. */
+	result = palloc(size + 1);
+	memcpy(result, path, size + 1);
+
+	return result;
+}
+
+/*
+ * GetRelationPathInPlace - construct path to a relation's file
+ *
+ * Result is written to path, which must have space for MAXPGPATH characters.
+ * The size of the string is returned.  If it is >= MAXPGPATH, the path has
+ * been truncated due to lack of space.
+ */
+size_t
+GetRelationPathInPlace(char *path,
+					   Oid dbOid, Oid spcOid, RelFileNumber relNumber,
+					   int procNumber, ForkNumber forkNumber)
+{
+	size_t		size;
 
 	if (spcOid == GLOBALTABLESPACE_OID)
 	{
@@ -150,10 +175,10 @@ GetRelationPath(Oid dbOid, Oid spcOid, RelFileNumber relNumber,
 		Assert(dbOid == 0);
 		Assert(procNumber == INVALID_PROC_NUMBER);
 		if (forkNumber != MAIN_FORKNUM)
-			path = psprintf("global/%u_%s",
+			size = snprintf(path, MAXPGPATH, "global/%u_%s",
 							relNumber, forkNames[forkNumber]);
 		else
-			path = psprintf("global/%u", relNumber);
+			size = snprintf(path, MAXPGPATH, "global/%u", relNumber);
 	}
 	else if (spcOid == DEFAULTTABLESPACE_OID)
 	{
@@ -161,21 +186,25 @@ GetRelationPath(Oid dbOid, Oid spcOid, RelFileNumber relNumber,
 		if (procNumber == INVALID_PROC_NUMBER)
 		{
 			if (forkNumber != MAIN_FORKNUM)
-				path = psprintf("base/%u/%u_%s",
+				size = snprintf(path, MAXPGPATH,
+								"base/%u/%u_%s",
 								dbOid, relNumber,
 								forkNames[forkNumber]);
 			else
-				path = psprintf("base/%u/%u",
+				size = snprintf(path, MAXPGPATH,
+								"base/%u/%u",
 								dbOid, relNumber);
 		}
 		else
 		{
 			if (forkNumber != MAIN_FORKNUM)
-				path = psprintf("base/%u/t%d_%u_%s",
+				size = snprintf(path, MAXPGPATH,
+								"base/%u/t%d_%u_%s",
 								dbOid, procNumber, relNumber,
 								forkNames[forkNumber]);
 			else
-				path = psprintf("base/%u/t%d_%u",
+				size = snprintf(path, MAXPGPATH,
+								"base/%u/t%d_%u",
 								dbOid, procNumber, relNumber);
 		}
 	}
@@ -185,13 +214,15 @@ GetRelationPath(Oid dbOid, Oid spcOid, RelFileNumber relNumber,
 		if (procNumber == INVALID_PROC_NUMBER)
 		{
 			if (forkNumber != MAIN_FORKNUM)
-				path = psprintf("%s/%u/%s/%u/%u_%s",
+				size = snprintf(path, MAXPGPATH,
+								"%s/%u/%s/%u/%u_%s",
 								PG_TBLSPC_DIR, spcOid,
 								TABLESPACE_VERSION_DIRECTORY,
 								dbOid, relNumber,
 								forkNames[forkNumber]);
 			else
-				path = psprintf("%s/%u/%s/%u/%u",
+				size = snprintf(path, MAXPGPATH,
+								"%s/%u/%s/%u/%u",
 								PG_TBLSPC_DIR, spcOid,
 								TABLESPACE_VERSION_DIRECTORY,
 								dbOid, relNumber);
@@ -199,17 +230,19 @@ GetRelationPath(Oid dbOid, Oid spcOid, RelFileNumber relNumber,
 		else
 		{
 			if (forkNumber != MAIN_FORKNUM)
-				path = psprintf("%s/%u/%s/%u/t%d_%u_%s",
+				size = snprintf(path, MAXPGPATH,
+								"%s/%u/%s/%u/t%d_%u_%s",
 								PG_TBLSPC_DIR, spcOid,
 								TABLESPACE_VERSION_DIRECTORY,
 								dbOid, procNumber, relNumber,
 								forkNames[forkNumber]);
 			else
-				path = psprintf("%s/%u/%s/%u/t%d_%u",
+				size = snprintf(path, MAXPGPATH,
+								"%s/%u/%s/%u/t%d_%u",
 								PG_TBLSPC_DIR, spcOid,
 								TABLESPACE_VERSION_DIRECTORY,
 								dbOid, procNumber, relNumber);
 		}
 	}
-	return path;
+	return size;
 }
diff --git a/src/include/common/relpath.h b/src/include/common/relpath.h
index 2dabbe01ecd..ec21ecab9ee 100644
--- a/src/include/common/relpath.h
+++ b/src/include/common/relpath.h
@@ -84,6 +84,9 @@ extern char *GetDatabasePath(Oid dbOid, Oid spcOid);
 
 extern char *GetRelationPath(Oid dbOid, Oid spcOid, RelFileNumber relNumber,
 							 int procNumber, ForkNumber forkNumber);
+extern size_t GetRelationPathInPlace(char *path,
+									 Oid dbOid, Oid spcOid, RelFileNumber relNumber,
+									 int procNumber, ForkNumber forkNumber);
 
 /*
  * Wrapper macros for GetRelationPath.  Beware of multiple
-- 
2.46.0

