Move routine building restore_command to src/common/
authorMichael Paquier <michael@paquier.xyz>
Tue, 24 Mar 2020 03:13:36 +0000 (12:13 +0900)
committerMichael Paquier <michael@paquier.xyz>
Tue, 24 Mar 2020 03:13:36 +0000 (12:13 +0900)
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-ee36168955c1@postgrespro.ru

src/backend/access/transam/xlogarchive.c
src/common/Makefile
src/common/archive.c [new file with mode: 0644]
src/include/common/archive.h [new file with mode: 0644]
src/tools/msvc/Mkvcbuild.pm

index 188b73e75269897c01b03fa0685f7696bc0198aa..914ad340eae664ede12d513c79c2e69c1f7652b3 100644 (file)
@@ -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)
    {
index ce01df68b975ec3ba4d4e2e29d235c2663774c9f..6939b9d08742685715da827ba1a4fdb9454c9bf1 100644 (file)
@@ -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 (file)
index 0000000..a94e4d0
--- /dev/null
@@ -0,0 +1,121 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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"
+#include "lib/stringinfo.h"
+
+/*
+ * BuildRestoreCommand
+ *
+ * Builds a restore command to retrieve a file 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)
+{
+   StringInfoData result;
+   const char *sp;
+
+   /*
+    * Build the command to be executed.
+    */
+   initStringInfo(&result);
+
+   for (sp = restoreCommand; *sp; sp++)
+   {
+       if (*sp == '%')
+       {
+           switch (sp[1])
+           {
+               case 'p':
+                   {
+                       char       *nativePath;
+
+                       /* %p: relative path of target file */
+                       if (xlogpath == NULL)
+                       {
+                           pfree(result.data);
+                           return NULL;
+                       }
+                       sp++;
+
+                       /*
+                        * This needs to use a placeholder to not modify the
+                        * input with the conversion done via
+                        * make_native_path().
+                        */
+                       nativePath = pstrdup(xlogpath);
+                       make_native_path(nativePath);
+                       appendStringInfoString(&result,
+                                              nativePath);
+                       pfree(nativePath);
+                       break;
+                   }
+               case 'f':
+                   /* %f: filename of desired file */
+                   if (xlogfname == NULL)
+                   {
+                       pfree(result.data);
+                       return NULL;
+                   }
+                   sp++;
+                   appendStringInfoString(&result, xlogfname);
+                   break;
+               case 'r':
+                   /* %r: filename of last restartpoint */
+                   if (lastRestartPointFname == NULL)
+                   {
+                       pfree(result.data);
+                       return NULL;
+                   }
+                   sp++;
+                   appendStringInfoString(&result,
+                                          lastRestartPointFname);
+                   break;
+               case '%':
+                   /* convert %% to a single % */
+                   sp++;
+                   appendStringInfoChar(&result, *sp);
+                   break;
+               default:
+                   /* otherwise treat the % as not special */
+                   appendStringInfoChar(&result, *sp);
+                   break;
+           }
+       }
+       else
+       {
+           appendStringInfoChar(&result, *sp);
+       }
+   }
+
+   return result.data;
+}
diff --git a/src/include/common/archive.h b/src/include/common/archive.h
new file mode 100644 (file)
index 0000000..b269910
--- /dev/null
@@ -0,0 +1,21 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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
+
+extern char *BuildRestoreCommand(const char *restoreCommand,
+                                const char *xlogpath,  /* %p */
+                                const char *xlogfname, /* %f */
+                                const char *lastRestartPointFname);    /* %r */
+
+#endif                         /* ARCHIVE_H */
index f89a8a4fdb711afe2689e233ee365905ea9ad3fb..636428b04482c3214d586838d25d2b65ee2a405f 100644 (file)
@@ -120,6 +120,7 @@ sub mkvcbuild
    }
 
    our @pgcommonallfiles = qw(
+     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