diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c index 943d80470bf..73edcf2dc3e 100644 --- a/src/backend/replication/basebackup.c +++ b/src/backend/replication/basebackup.c @@ -32,6 +32,14 @@ #include "utils/memutils.h" #include "utils/ps_status.h" +typedef struct +{ + const char *label; + bool progress; + bool fastcheckpoint; +} basebackup_options; + + static int64 sendDir(char *path, int basepathlen, bool sizeonly); static void sendFile(char *path, int basepathlen, struct stat * statbuf); static void _tarWriteHeader(char *filename, char *linktarget, @@ -40,7 +48,8 @@ static void send_int8_string(StringInfoData *buf, int64 intval); static void SendBackupHeader(List *tablespaces); static void SendBackupDirectory(char *location, char *spcoid); static void base_backup_cleanup(int code, Datum arg); -static void perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir, bool fastcheckpoint); +static void perform_base_backup(basebackup_options *opt, DIR *tblspcdir); +static void parse_basebackup_options(List *options, basebackup_options *opt); typedef struct { @@ -67,9 +76,9 @@ base_backup_cleanup(int code, Datum arg) * clobbered by longjmp" from stupider versions of gcc. */ static void -perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir, bool fastcheckpoint) +perform_base_backup(basebackup_options *opt, DIR *tblspcdir) { - do_pg_start_backup(backup_label, fastcheckpoint); + do_pg_start_backup(opt->label, opt->fastcheckpoint); PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0); { @@ -81,7 +90,7 @@ perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir, boo /* Add a node for the base directory */ ti = palloc0(sizeof(tablespaceinfo)); - ti->size = progress ? sendDir(".", 1, true) : -1; + ti->size = opt->progress ? sendDir(".", 1, true) : -1; tablespaces = lappend(tablespaces, ti); /* Collect information about all tablespaces */ @@ -107,7 +116,7 @@ perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir, boo ti = palloc(sizeof(tablespaceinfo)); ti->oid = pstrdup(de->d_name); ti->path = pstrdup(linkpath); - ti->size = progress ? sendDir(linkpath, strlen(linkpath), true) : -1; + ti->size = opt->progress ? sendDir(linkpath, strlen(linkpath), true) : -1; tablespaces = lappend(tablespaces, ti); } @@ -128,6 +137,58 @@ perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir, boo do_pg_stop_backup(); } +/* + * Parse the base backup options passed down by the parser + */ +static void +parse_basebackup_options(List *options, basebackup_options *opt) +{ + ListCell *lopt; + bool o_label = false; + bool o_progress = false; + bool o_fast = false; + + MemSet(opt, 0, sizeof(opt)); + foreach(lopt, options) + { + DefElem *defel = (DefElem *) lfirst(lopt); + + if (strcmp(defel->defname, "label") == 0) + { + if (o_label) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("duplicate option \"%s\"", defel->defname))); + opt->label = strVal(defel->arg); + o_label = true; + } + else if (strcmp(defel->defname, "progress") == 0) + { + if (o_progress) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("duplicate option \"%s\"", defel->defname))); + opt->progress = true; + o_progress = true; + } + else if (strcmp(defel->defname, "fast") == 0) + { + if (o_fast) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("duplicate option \"%s\"", defel->defname))); + opt->fastcheckpoint = true; + o_fast = true; + } + else + elog(ERROR, "option \"%s\" not recognized", + defel->defname); + } + if (opt->label == NULL) + opt->label = "base backup"; +} + + /* * SendBaseBackup() - send a complete base backup. * @@ -135,11 +196,14 @@ perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir, boo * pg_stop_backup() for the user. */ void -SendBaseBackup(const char *backup_label, bool progress, bool fastcheckpoint) +SendBaseBackup(BaseBackupCmd *cmd) { DIR *dir; MemoryContext backup_context; MemoryContext old_context; + basebackup_options opt; + + parse_basebackup_options(cmd->options, &opt); backup_context = AllocSetContextCreate(CurrentMemoryContext, "Streaming base backup context", @@ -150,15 +214,12 @@ SendBaseBackup(const char *backup_label, bool progress, bool fastcheckpoint) WalSndSetState(WALSNDSTATE_BACKUP); - if (backup_label == NULL) - backup_label = "base backup"; - if (update_process_title) { char activitymsg[50]; snprintf(activitymsg, sizeof(activitymsg), "sending backup \"%s\"", - backup_label); + opt.label); set_ps_display(activitymsg, false); } @@ -168,7 +229,7 @@ SendBaseBackup(const char *backup_label, bool progress, bool fastcheckpoint) ereport(ERROR, (errmsg("unable to open directory pg_tblspc: %m"))); - perform_base_backup(backup_label, progress, dir, fastcheckpoint); + perform_base_backup(&opt, dir); FreeDir(dir); diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y index e4f4c4742f6..879a0bd7db0 100644 --- a/src/backend/replication/repl_gram.y +++ b/src/backend/replication/repl_gram.y @@ -15,6 +15,8 @@ #include "postgres.h" +#include "nodes/makefuncs.h" +#include "nodes/parsenodes.h" #include "replication/replnodes.h" #include "replication/walsender.h" @@ -55,6 +57,8 @@ Node *replication_parse_result; XLogRecPtr recptr; Node *node; + List *list; + DefElem *defelt; } /* Non-keyword tokens */ @@ -71,9 +75,8 @@ Node *replication_parse_result; %type command %type base_backup start_replication identify_system -%type opt_progress opt_fast -%type opt_label - +%type base_backup_opt_list +%type base_backup_opt %% firstcmd: command opt_semicolon @@ -106,28 +109,34 @@ identify_system: * BASE_BACKUP [LABEL