On Tue, Mar 10, 2020 at 12:39:53PM -0300, Alvaro Herrera wrote:
> Another option is to return the command as a palloc'ed string (per
> psprintf), instead of using a caller-stack-allocated variable.  Passing
> the buffer len is widely used, but more error prone (and I think getting
> this one wrong might be more catastrophic than a mistake elsewhere.)
> This is not a performance-critical path enough that we *need* the
> optimization that avoids the palloc is important.  (Failure can be
> reported by returning NULL.)

That's a better approach here.

> Also, I think the function comment could stand some more detailing.

What kind of additional information would you like to add on top of
what the updated version attached does?

> Also, I think Msvcbuild.pm could follow Makefile's ideas of one line per
> file.  Maybe no need to fix all of that in this patch, but let's start
> by adding the new file it its own line rather than reflowing two
> adjacent lines (oh wait ... does perltidy put it that way?  if so,
> nevermind.)

Good idea.  It happens that perltidy does not care about that, but I
would rather keep that stuff for a separate patch/thread.
--
Michael
From 33d9a6837f2435966006947dad18c21e40e0c271 Mon Sep 17 00:00:00 2001
From: Michael Paquier <mich...@paquier.xyz>
Date: Wed, 11 Mar 2020 12:25:18 +0900
Subject: [PATCH v3] Move routine generating restore_command to src/common/

restore_command has only been used until now by the backend, but there
is a pending patch for pg_rewind to make use of that in the frontend.

Author: Alexey Kondratov
Reviewed-by: Andrey Borodin, Andres Freund, Alvaro Herrera, Alexander
Korotkov, Michael Paquier
Discussion: https://postgr.es/m/a3acff50-5a0d-9a2c-b3b2-ee3616895...@postgrespro.ru
---
 src/include/common/archive.h             |  27 +++++
 src/backend/access/transam/xlogarchive.c |  66 ++-----------
 src/common/Makefile                      |   1 +
 src/common/archive.c                     | 119 +++++++++++++++++++++++
 src/tools/msvc/Mkvcbuild.pm              |   4 +-
 5 files changed, 159 insertions(+), 58 deletions(-)
 create mode 100644 src/include/common/archive.h
 create mode 100644 src/common/archive.c

diff --git a/src/include/common/archive.h b/src/include/common/archive.h
new file mode 100644
index 0000000000..8af0b4566f
--- /dev/null
+++ b/src/include/common/archive.h
@@ -0,0 +1,27 @@
+/*-------------------------------------------------------------------------
+ *
+ * archive.h
+ *	  Common WAL archive routines
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/common/archive.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef ARCHIVE_H
+#define ARCHIVE_H
+
+/*
+ * Routine to build a restore command to retrieve WAL segments from a WAL
+ * archive.  This uses the arguments given by the caller to replace the
+ * corresponding alias fields as defined in the GUC parameter
+ * restore_command.
+ */
+extern char *BuildRestoreCommand(const char *restoreCommand,
+								 const char *xlogpath,	/* %p */
+								 const char *xlogfname, /* %f */
+								 const char *lastRestartPointFname);	/* %r */
+
+#endif							/* ARCHIVE_H */
diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c
index 188b73e752..914ad340ea 100644
--- a/src/backend/access/transam/xlogarchive.c
+++ b/src/backend/access/transam/xlogarchive.c
@@ -21,6 +21,7 @@
 
 #include "access/xlog.h"
 #include "access/xlog_internal.h"
+#include "common/archive.h"
 #include "miscadmin.h"
 #include "postmaster/startup.h"
 #include "replication/walsender.h"
@@ -53,11 +54,8 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 					bool cleanupEnabled)
 {
 	char		xlogpath[MAXPGPATH];
-	char		xlogRestoreCmd[MAXPGPATH];
+	char	   *xlogRestoreCmd;
 	char		lastRestartPointFname[MAXPGPATH];
-	char	   *dp;
-	char	   *endp;
-	const char *sp;
 	int			rc;
 	struct stat stat_buf;
 	XLogSegNo	restartSegNo;
@@ -149,58 +147,13 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 	else
 		XLogFileName(lastRestartPointFname, 0, 0L, wal_segment_size);
 
-	/*
-	 * construct the command to be executed
-	 */
-	dp = xlogRestoreCmd;
-	endp = xlogRestoreCmd + MAXPGPATH - 1;
-	*endp = '\0';
-
-	for (sp = recoveryRestoreCommand; *sp; sp++)
-	{
-		if (*sp == '%')
-		{
-			switch (sp[1])
-			{
-				case 'p':
-					/* %p: relative path of target file */
-					sp++;
-					StrNCpy(dp, xlogpath, endp - dp);
-					make_native_path(dp);
-					dp += strlen(dp);
-					break;
-				case 'f':
-					/* %f: filename of desired file */
-					sp++;
-					StrNCpy(dp, xlogfname, endp - dp);
-					dp += strlen(dp);
-					break;
-				case 'r':
-					/* %r: filename of last restartpoint */
-					sp++;
-					StrNCpy(dp, lastRestartPointFname, endp - dp);
-					dp += strlen(dp);
-					break;
-				case '%':
-					/* convert %% to a single % */
-					sp++;
-					if (dp < endp)
-						*dp++ = *sp;
-					break;
-				default:
-					/* otherwise treat the % as not special */
-					if (dp < endp)
-						*dp++ = *sp;
-					break;
-			}
-		}
-		else
-		{
-			if (dp < endp)
-				*dp++ = *sp;
-		}
-	}
-	*dp = '\0';
+	/* Build the restore command to execute */
+	xlogRestoreCmd = BuildRestoreCommand(recoveryRestoreCommand,
+										 xlogpath, xlogfname,
+										 lastRestartPointFname);
+	if (xlogRestoreCmd == NULL)
+		elog(ERROR, "could not build restore command \"%s\"",
+			 recoveryRestoreCommand);
 
 	ereport(DEBUG3,
 			(errmsg_internal("executing restore command \"%s\"",
@@ -217,6 +170,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 	rc = system(xlogRestoreCmd);
 
 	PostRestoreCommand();
+	pfree(xlogRestoreCmd);
 
 	if (rc == 0)
 	{
diff --git a/src/common/Makefile b/src/common/Makefile
index ce01df68b9..6939b9d087 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -46,6 +46,7 @@ LIBS += $(PTHREAD_LIBS)
 # If you add objects here, see also src/tools/msvc/Mkvcbuild.pm
 
 OBJS_COMMON = \
+	archive.o \
 	base64.o \
 	config_info.o \
 	controldata_utils.o \
diff --git a/src/common/archive.c b/src/common/archive.c
new file mode 100644
index 0000000000..ef0ce532ed
--- /dev/null
+++ b/src/common/archive.c
@@ -0,0 +1,119 @@
+/*-------------------------------------------------------------------------
+ *
+ * archive.c
+ *	  Common WAL archive routines
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/common/archive.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include "common/archive.h"
+
+/*
+ * BuildRestoreCommand
+ *
+ * Builds a restore command to retrieve a WAL segment from WAL archives,
+ * replacing the supported aliases with values supplied by the caller as
+ * defined by the GUC parameter restore_command: xlogpath for %p,
+ * xlogfname for %f and lastRestartPointFname for %r.
+ *
+ * The result is a palloc'd string for the restore command built.  The
+ * caller is responsible for freeing it.  If any of the required arguments
+ * is NULL and that the corresponding alias is found in the command given
+ * by the caller, then NULL is returned.
+ */
+char *
+BuildRestoreCommand(const char *restoreCommand,
+					const char *xlogpath,
+					const char *xlogfname,
+					const char *lastRestartPointFname)
+{
+	char	   *dp;
+	char	   *endp;
+	char	   *result;
+	const char *sp;
+
+	result = palloc0(MAXPGPATH);
+
+	/*
+	 * Build the command to be executed.
+	 */
+	dp = result;
+	endp = result + MAXPGPATH - 1;
+	*endp = '\0';
+
+	for (sp = restoreCommand; *sp; sp++)
+	{
+		if (*sp == '%')
+		{
+			switch (sp[1])
+			{
+				case 'p':
+					/* %p: relative path of target file */
+					if (xlogpath == NULL)
+					{
+						pfree(result);
+						return NULL;
+					}
+					sp++;
+					StrNCpy(dp, xlogpath, endp - dp);
+					make_native_path(dp);
+					dp += strlen(dp);
+					break;
+				case 'f':
+					/* %f: filename of desired file */
+					if (xlogfname == NULL)
+					{
+						pfree(result);
+						return NULL;
+					}
+					sp++;
+					StrNCpy(dp, xlogfname, endp - dp);
+					dp += strlen(dp);
+					break;
+				case 'r':
+					/* %r: filename of last restartpoint */
+					if (lastRestartPointFname == NULL)
+					{
+						pfree(result);
+						return NULL;
+					}
+					sp++;
+					StrNCpy(dp, lastRestartPointFname, endp - dp);
+					dp += strlen(dp);
+					break;
+				case '%':
+					/* convert %% to a single % */
+					sp++;
+					if (dp < endp)
+						*dp++ = *sp;
+					break;
+				default:
+					/* otherwise treat the % as not special */
+					if (dp < endp)
+						*dp++ = *sp;
+					break;
+			}
+		}
+		else
+		{
+			if (dp < endp)
+				*dp++ = *sp;
+		}
+	}
+	*dp = '\0';
+
+	return result;
+}
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index f89a8a4fdb..c648078e20 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -120,8 +120,8 @@ sub mkvcbuild
 	}
 
 	our @pgcommonallfiles = qw(
-	  base64.c config_info.c controldata_utils.c d2s.c encnames.c exec.c
-	  f2s.c file_perm.c hashfn.c ip.c jsonapi.c
+	  archive.c base64.c config_info.c controldata_utils.c d2s.c encnames.c
+	  exec.c f2s.c file_perm.c hashfn.c ip.c jsonapi.c
 	  keywords.c kwlookup.c link-canary.c md5.c
 	  pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c
 	  saslprep.c scram-common.c string.c stringinfo.c unicode_norm.c username.c
-- 
2.25.1

Attachment: signature.asc
Description: PGP signature

Reply via email to