blob: 0b79d4a9d463f2d13b29b780633df07a6c2d75f3 [file] [log] [blame]
/*-------------------------------------------------------------------------
*
* archive.c
* Common WAL archive routines
*
* Portions Copyright (c) 1996-2021, 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"
#include "cdb/cdbvars.h"
extern void pg_ltoa(int32 value, char *a);
/*
* 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;
#ifndef FRONTEND
char contentid[12]; /* sign, 10 digits and '\0' */
#endif
/*
* 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;
#ifndef FRONTEND
/* GPDB_13_MERGE_FIXME: How to set GpIdentity for frontend?
* Discussion: https://postgr.es/m/a3acff50-5a0d-9a2c-b3b2-ee36168955c1@postgrespro.ru
* */
case 'c':
/* GPDB: %c: contentId of segment */
Assert(GpIdentity.segindex != UNINITIALIZED_GP_IDENTITY_VALUE);
sp++;
pg_ltoa(GpIdentity.segindex, contentid);
appendStringInfoString(&result, contentid);
break;
#endif
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;
}