repl_parser.patch
text/x-patch
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
| File | + | − |
|---|---|---|
| doc/src/sgml/protocol.sgml | 16 | 0 |
| src/backend/replication/basebackup.c | 2 | 0 |
| src/backend/replication/Makefile | 24 | 0 |
| src/backend/replication/repl_gram.y | 143 | 0 |
| src/backend/replication/repl_scanner.l | 165 | 0 |
| src/backend/replication/walsender.c | 167 | 0 |
| src/include/replication/basebackup.h | 1 | 1 |
| src/include/replication/replnodes.h | 63 | 0 |
| src/include/replication/walsender.h | 13 | 0 |
| src/tools/msvc/Mkvcbuild.pm | 1 | 0 |
| src/tools/msvc/pgbison.bat | 1 | 0 |
| src/tools/msvc/pgflex.bat | 1 | 0 |
*** a/doc/src/sgml/protocol.sgml
--- b/doc/src/sgml/protocol.sgml
***************
*** 1460,1475 **** The commands accepted in walsender mode are:
</varlistentry>
<varlistentry>
! <term>BASE_BACKUP <replaceable>options</><literal>;</><replaceable>label</></term>
<listitem>
<para>
Instructs the server to start streaming a base backup.
! The system will automatically be put in backup mode with the label
! specified in <replaceable>label</> before the backup is started, and
! taken out of it when the backup is complete. The following options
! are accepted:
<variablelist>
<varlistentry>
<term><literal>PROGRESS</></term>
<listitem>
<para>
--- 1460,1486 ----
</varlistentry>
<varlistentry>
! <term>BASE_BACKUP [<literal>LABEL</literal> <replaceable>'label'</replaceable>] [<literal>PROGRESS</literal>]</term>
<listitem>
<para>
Instructs the server to start streaming a base backup.
! The system will automatically be put in backup mode before the backup
! is started, and taken out of it when the backup is complete. The
! following options are accepted:
<variablelist>
<varlistentry>
+ <term><literal>LABEL</literal> <replaceable>'label'</replaceable></term>
+ <listitem>
+ <para>
+ Sets the label of the backup. If none is specified, a backup label
+ of <literal>base backup</literal> will be used. The quoting rules
+ for the label are the same as a standard SQL string with
+ <xref linkend="guc-standard-conforming-strings"> turned on.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><literal>PROGRESS</></term>
<listitem>
<para>
*** a/src/backend/replication/Makefile
--- b/src/backend/replication/Makefile
***************
*** 12,17 **** subdir = src/backend/replication
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
! OBJS = walsender.o walreceiverfuncs.o walreceiver.o basebackup.o
include $(top_srcdir)/src/backend/common.mk
--- 12,40 ----
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
! OBJS = walsender.o walreceiverfuncs.o walreceiver.o basebackup.o \
! repl_gram.o
include $(top_srcdir)/src/backend/common.mk
+
+ # repl_scanner is compiled as part of repl_gram
+ repl_gram.o: repl_scanner.c
+
+ # See notes in src/backend/parser/Makefile about the following two rules
+
+ repl_gram.c: repl_gram.y
+ ifdef BISON
+ $(BISON) -d $(BISONFLAGS) -o $@ $<
+ else
+ @$(missing) bison $< $@
+ endif
+
+ repl_scanner.c: repl_scanner.l
+ ifdef FLEX
+ $(FLEX) $(FLEXFLAGS) -o'$@' $<
+ else
+ @$(missing) flex $< $@
+ endif
+
+ # repl_gram.c and repl_scanner.c are in the distribution tarball, so
+ # they are not cleaned here.
*** a/src/backend/replication/basebackup.c
--- b/src/backend/replication/basebackup.c
***************
*** 64,75 **** base_backup_cleanup(int code, Datum arg)
* pg_stop_backup() for the user.
*/
void
! SendBaseBackup(const char *options)
{
DIR *dir;
struct dirent *de;
- char *backup_label = strchr(options, ';');
- bool progress = false;
List *tablespaces = NIL;
tablespaceinfo *ti;
MemoryContext backup_context;
--- 64,73 ----
* pg_stop_backup() for the user.
*/
void
! SendBaseBackup(const char *backup_label, bool progress)
{
DIR *dir;
struct dirent *de;
List *tablespaces = NIL;
tablespaceinfo *ti;
MemoryContext backup_context;
***************
*** 83,100 **** SendBaseBackup(const char *options)
old_context = MemoryContextSwitchTo(backup_context);
if (backup_label == NULL)
! ereport(FATAL,
! (errcode(ERRCODE_PROTOCOL_VIOLATION),
! errmsg("invalid base backup options: %s", options)));
! backup_label++; /* Walk past the semicolon */
!
! /* Currently the only option string supported is PROGRESS */
! if (strncmp(options, "PROGRESS", 8) == 0)
! progress = true;
! else if (options[0] != ';')
! ereport(FATAL,
! (errcode(ERRCODE_PROTOCOL_VIOLATION),
! errmsg("invalid base backup options: %s", options)));
/* Make sure we can open the directory with tablespaces in it */
dir = AllocateDir("pg_tblspc");
--- 81,87 ----
old_context = MemoryContextSwitchTo(backup_context);
if (backup_label == NULL)
! backup_label = "base backup";
/* Make sure we can open the directory with tablespaces in it */
dir = AllocateDir("pg_tblspc");
*** /dev/null
--- b/src/backend/replication/repl_gram.y
***************
*** 0 ****
--- 1,143 ----
+ %{
+ /*-------------------------------------------------------------------------
+ *
+ * repl_gram.y - Parser for the replication commands
+ *
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/replication/repl_gram.y
+ *
+ *-------------------------------------------------------------------------
+ */
+
+ #include "postgres.h"
+
+ #include "replication/replnodes.h"
+ #include "replication/walsender.h"
+
+ /* Result of the parsing is returned here */
+ Node *replication_parse_result;
+
+ /* Location tracking support --- simpler than bison's default */
+ #define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do { \
+ if (N) \
+ (Current) = (Rhs)[1]; \
+ else \
+ (Current) = (Rhs)[0]; \
+ } while (0)
+
+ /*
+ * Bison doesn't allocate anything that needs to live across parser calls,
+ * so we can easily have it use palloc instead of malloc. This prevents
+ * memory leaks if we error out during parsing. Note this only works with
+ * bison >= 2.0. However, in bison 1.875 the default is to use alloca()
+ * if possible, so there's not really much problem anyhow, at least if
+ * you're building with gcc.
+ */
+ #define YYMALLOC palloc
+ #define YYFREE pfree
+
+ #define parser_yyerror(msg) replication_yyerror(msg, yyscanner)
+ #define parser_errposition(pos) replication_scanner_errposition(pos)
+
+ %}
+
+ %expect 0
+ %name-prefix="replication_yy"
+
+ %union {
+ char *str;
+ bool boolval;
+
+ XLogRecPtr recptr;
+ Node *node;
+ }
+
+ /* Non-keyword tokens */
+ %token <str> SCONST
+ %token <recptr> RECPTR
+
+ /* Keyword tokens. */
+ %token K_BASE_BACKUP
+ %token K_IDENTIFY_SYSTEM
+ %token K_LABEL
+ %token K_PROGRESS
+ %token K_START_REPLICATION
+
+ %type <node> command
+ %type <node> base_backup start_replication identify_system
+ %type <boolval> opt_progress
+ %type <str> opt_label
+
+ %%
+
+ firstcmd: command opt_semicolon
+ {
+ replication_parse_result = $1;
+ }
+ ;
+
+ opt_semicolon: ';'
+ | /* EMPTY */
+ ;
+
+ command:
+ identify_system
+ | base_backup
+ | start_replication
+ ;
+
+ /*
+ * IDENTIFY_SYSTEM
+ */
+ identify_system:
+ K_IDENTIFY_SYSTEM
+ {
+ $$ = (Node *) makeNode(IdentifySystemCmd);
+ }
+ ;
+
+ /*
+ * BASE_BACKUP [LABEL <label>] [PROGRESS]
+ */
+ base_backup:
+ K_BASE_BACKUP opt_label opt_progress
+ {
+ BaseBackupCmd *cmd = (BaseBackupCmd *) makeNode(BaseBackupCmd);
+
+ cmd->label = $2;
+ cmd->progress = $3;
+
+ $$ = (Node *) cmd;
+ }
+ ;
+
+ opt_label: K_LABEL SCONST { $$ = $2; }
+ | /* EMPTY */ { $$ = NULL; }
+ ;
+
+ opt_progress: K_PROGRESS { $$ = true; }
+ | /* EMPTY */ { $$ = false; }
+ ;
+
+ /*
+ * START_REPLICATION %X/%X
+ */
+ start_replication:
+ K_START_REPLICATION RECPTR
+ {
+ StartReplicationCmd *cmd;
+
+ cmd = makeNode(StartReplicationCmd);
+ cmd->startpoint = $2;
+
+ $$ = (Node *) cmd;
+ }
+ ;
+ %%
+
+ #include "repl_scanner.c"
*** /dev/null
--- b/src/backend/replication/repl_scanner.l
***************
*** 0 ****
--- 1,165 ----
+ %{
+ /*-------------------------------------------------------------------------
+ *
+ * repl_scanner.l
+ * a lexical scanner for the replication commands
+ *
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/replication/repl_scanner.l
+ *
+ *-------------------------------------------------------------------------
+ */
+ #include "postgres.h"
+
+ /* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
+ #undef fprintf
+ #define fprintf(file, fmt, msg) ereport(ERROR, (errmsg_internal("%s", msg)))
+
+ /* Handle to the buffer that the lexer uses internally */
+ static YY_BUFFER_STATE scanbufhandle;
+
+ static StringInfoData litbuf;
+
+ static void startlit(void);
+ static char *litbufdup(void);
+ static void addlit(char *ytext, int yleng);
+ static void addlitchar(unsigned char ychar);
+
+ %}
+
+ %option 8bit
+ %option never-interactive
+ %option nodefault
+ %option noinput
+ %option nounput
+ %option noyywrap
+ %option warn
+ %option prefix="replication_yy"
+
+ %x xq
+
+ /* Extended quote
+ * xqdouble implements embedded quote, ''''
+ */
+ xqstart {quote}
+ xqdouble {quote}{quote}
+ xqinside [^']+
+
+ hexdigit [0-9A-Za-z]+
+
+ quote '
+ quotestop {quote}
+
+ %%
+
+ BASE_BACKUP { return K_BASE_BACKUP; }
+ IDENTIFY_SYSTEM { return K_IDENTIFY_SYSTEM; }
+ LABEL { return K_LABEL; }
+ PROGRESS { return K_PROGRESS; }
+ START_REPLICATION { return K_START_REPLICATION; }
+ "," { return ','; }
+ ";" { return ';'; }
+
+ [\n] ;
+ [\t] ;
+ " " ;
+
+ {hexdigit}+\/{hexdigit}+ {
+ yylval.str = pstrdup(yytext);
+ if (sscanf(yytext, "%X/%X", &yylval.recptr.xlogid, &yylval.recptr.xrecoff) != 2)
+ yyerror("invalid streaming start location");
+ return RECPTR;
+ }
+
+ {xqstart} {
+ BEGIN(xq);
+ startlit();
+ }
+ <xq>{quotestop} {
+ yyless(1);
+ BEGIN(INITIAL);
+ yylval.str = litbufdup();
+ return SCONST;
+ }
+ <xq>{xqdouble} {
+ addlitchar('\'');
+ }
+ <xq>{xqinside} {
+ addlit(yytext, yyleng);
+ }
+
+ <xq><<EOF>> { yyerror("unterminated quoted string"); }
+
+
+ <<EOF>> {
+ yyterminate();
+ }
+
+ . {
+ elog(ERROR, "syntax error: unexpected character \"%s\"", yytext);
+ }
+ %%
+
+
+ static void
+ startlit(void)
+ {
+ initStringInfo(&litbuf);
+ }
+
+ static char *
+ litbufdup(void)
+ {
+ return litbuf.data;
+ }
+
+ static void
+ addlit(char *ytext, int yleng)
+ {
+ appendBinaryStringInfo(&litbuf, ytext, yleng);
+ }
+
+ static void
+ addlitchar(unsigned char ychar)
+ {
+ appendStringInfoChar(&litbuf, ychar);
+ }
+
+ void
+ yyerror(const char *message)
+ {
+ elog(ERROR, "%s", message);
+ }
+
+
+ void
+ replication_scanner_init(const char *str)
+ {
+ Size slen = strlen(str);
+ char *scanbuf;
+
+ /*
+ * Might be left over after ereport()
+ */
+ if (YY_CURRENT_BUFFER)
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+
+ /*
+ * Make a scan buffer with special termination needed by flex.
+ */
+ scanbuf = (char *) palloc(slen + 2);
+ memcpy(scanbuf, str, slen);
+ scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
+ scanbufhandle = yy_scan_buffer(scanbuf, slen + 2);
+ }
+
+ void
+ replication_scanner_finish()
+ {
+ yy_delete_buffer(scanbufhandle);
+ scanbufhandle = NULL;
+ }
*** a/src/backend/replication/walsender.c
--- b/src/backend/replication/walsender.c
***************
*** 45,50 ****
--- 45,51 ----
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "replication/basebackup.h"
+ #include "replication/replnodes.h"
#include "replication/walprotocol.h"
#include "replication/walsender.h"
#include "storage/fd.h"
***************
*** 99,104 **** static void WalSndXLogSendHandler(SIGNAL_ARGS);
--- 100,106 ----
static void WalSndLastCycleHandler(SIGNAL_ARGS);
/* Prototypes for private functions */
+ static bool HandleReplicationCommand(const char *cmd_string);
static int WalSndLoop(void);
static void InitWalSnd(void);
static void WalSndHandshake(void);
***************
*** 106,111 **** static void WalSndKill(int code, Datum arg);
--- 108,115 ----
static void XLogRead(char *buf, XLogRecPtr recptr, Size nbytes);
static bool XLogSend(char *msgbuf, bool *caughtup);
static void CheckClosedConnection(void);
+ static void IdentifySystem(void);
+ static void StartReplication(StartReplicationCmd * cmd);
/* Main entry point for walsender process */
***************
*** 215,332 **** WalSndHandshake(void)
case 'Q': /* Query message */
{
const char *query_string;
- XLogRecPtr recptr;
query_string = pq_getmsgstring(&input_message);
pq_getmsgend(&input_message);
! if (strcmp(query_string, "IDENTIFY_SYSTEM") == 0)
! {
! StringInfoData buf;
! char sysid[32];
! char tli[11];
!
! /*
! * Reply with a result set with one row, two columns.
! * First col is system ID, and second is timeline ID
! */
!
! snprintf(sysid, sizeof(sysid), UINT64_FORMAT,
! GetSystemIdentifier());
! snprintf(tli, sizeof(tli), "%u", ThisTimeLineID);
!
! /* Send a RowDescription message */
! pq_beginmessage(&buf, 'T');
! pq_sendint(&buf, 2, 2); /* 2 fields */
!
! /* first field */
! pq_sendstring(&buf, "systemid"); /* col name */
! pq_sendint(&buf, 0, 4); /* table oid */
! pq_sendint(&buf, 0, 2); /* attnum */
! pq_sendint(&buf, TEXTOID, 4); /* type oid */
! pq_sendint(&buf, -1, 2); /* typlen */
! pq_sendint(&buf, 0, 4); /* typmod */
! pq_sendint(&buf, 0, 2); /* format code */
!
! /* second field */
! pq_sendstring(&buf, "timeline"); /* col name */
! pq_sendint(&buf, 0, 4); /* table oid */
! pq_sendint(&buf, 0, 2); /* attnum */
! pq_sendint(&buf, INT4OID, 4); /* type oid */
! pq_sendint(&buf, 4, 2); /* typlen */
! pq_sendint(&buf, 0, 4); /* typmod */
! pq_sendint(&buf, 0, 2); /* format code */
! pq_endmessage(&buf);
!
! /* Send a DataRow message */
! pq_beginmessage(&buf, 'D');
! pq_sendint(&buf, 2, 2); /* # of columns */
! pq_sendint(&buf, strlen(sysid), 4); /* col1 len */
! pq_sendbytes(&buf, (char *) &sysid, strlen(sysid));
! pq_sendint(&buf, strlen(tli), 4); /* col2 len */
! pq_sendbytes(&buf, (char *) tli, strlen(tli));
! pq_endmessage(&buf);
!
! /* Send CommandComplete and ReadyForQuery messages */
! EndCommand("SELECT", DestRemote);
! ReadyForQuery(DestRemote);
! /* ReadyForQuery did pq_flush for us */
! }
! else if (sscanf(query_string, "START_REPLICATION %X/%X",
! &recptr.xlogid, &recptr.xrecoff) == 2)
! {
! StringInfoData buf;
!
! /*
! * Check that we're logging enough information in the
! * WAL for log-shipping.
! *
! * NOTE: This only checks the current value of
! * wal_level. Even if the current setting is not
! * 'minimal', there can be old WAL in the pg_xlog
! * directory that was created with 'minimal'. So this
! * is not bulletproof, the purpose is just to give a
! * user-friendly error message that hints how to
! * configure the system correctly.
! */
! if (wal_level == WAL_LEVEL_MINIMAL)
! ereport(FATAL,
! (errcode(ERRCODE_CANNOT_CONNECT_NOW),
! errmsg("standby connections not allowed because wal_level=minimal")));
!
! /* Send a CopyBothResponse message, and start streaming */
! pq_beginmessage(&buf, 'W');
! pq_sendbyte(&buf, 0);
! pq_sendint(&buf, 0, 2);
! pq_endmessage(&buf);
! pq_flush();
!
! /*
! * Initialize position to the received one, then the
! * xlog records begin to be shipped from that position
! */
! sentPtr = recptr;
!
! /* break out of the loop */
replication_started = true;
- }
- else if (strncmp(query_string, "BASE_BACKUP ", 12) == 0)
- {
- /* Command is BASE_BACKUP <options>;<label> */
- SendBaseBackup(query_string + strlen("BASE_BACKUP "));
- /* Send CommandComplete and ReadyForQuery messages */
- EndCommand("SELECT", DestRemote);
- ReadyForQuery(DestRemote);
- /* ReadyForQuery did pq_flush for us */
- }
- else
- {
- ereport(FATAL,
- (errcode(ERRCODE_PROTOCOL_VIOLATION),
- errmsg("invalid standby query string: %s", query_string)));
- }
- break;
}
case 'X':
/* standby is closing the connection */
--- 219,232 ----
case 'Q': /* Query message */
{
const char *query_string;
query_string = pq_getmsgstring(&input_message);
pq_getmsgend(&input_message);
! if (HandleReplicationCommand(query_string))
replication_started = true;
}
+ break;
case 'X':
/* standby is closing the connection */
***************
*** 348,353 **** WalSndHandshake(void)
--- 248,414 ----
}
/*
+ * IDENTIFY_SYSTEM
+ */
+ static void
+ IdentifySystem(void)
+ {
+ StringInfoData buf;
+ char sysid[32];
+ char tli[11];
+
+ /*
+ * Reply with a result set with one row, two columns. First col is system
+ * ID, and second is timeline ID
+ */
+
+ snprintf(sysid, sizeof(sysid), UINT64_FORMAT,
+ GetSystemIdentifier());
+ snprintf(tli, sizeof(tli), "%u", ThisTimeLineID);
+
+ /* Send a RowDescription message */
+ pq_beginmessage(&buf, 'T');
+ pq_sendint(&buf, 2, 2); /* 2 fields */
+
+ /* first field */
+ pq_sendstring(&buf, "systemid"); /* col name */
+ pq_sendint(&buf, 0, 4); /* table oid */
+ pq_sendint(&buf, 0, 2); /* attnum */
+ pq_sendint(&buf, TEXTOID, 4); /* type oid */
+ pq_sendint(&buf, -1, 2); /* typlen */
+ pq_sendint(&buf, 0, 4); /* typmod */
+ pq_sendint(&buf, 0, 2); /* format code */
+
+ /* second field */
+ pq_sendstring(&buf, "timeline"); /* col name */
+ pq_sendint(&buf, 0, 4); /* table oid */
+ pq_sendint(&buf, 0, 2); /* attnum */
+ pq_sendint(&buf, INT4OID, 4); /* type oid */
+ pq_sendint(&buf, 4, 2); /* typlen */
+ pq_sendint(&buf, 0, 4); /* typmod */
+ pq_sendint(&buf, 0, 2); /* format code */
+ pq_endmessage(&buf);
+
+ /* Send a DataRow message */
+ pq_beginmessage(&buf, 'D');
+ pq_sendint(&buf, 2, 2); /* # of columns */
+ pq_sendint(&buf, strlen(sysid), 4); /* col1 len */
+ pq_sendbytes(&buf, (char *) &sysid, strlen(sysid));
+ pq_sendint(&buf, strlen(tli), 4); /* col2 len */
+ pq_sendbytes(&buf, (char *) tli, strlen(tli));
+ pq_endmessage(&buf);
+
+ /* Send CommandComplete and ReadyForQuery messages */
+ EndCommand("SELECT", DestRemote);
+ ReadyForQuery(DestRemote);
+ /* ReadyForQuery did pq_flush for us */
+ }
+
+ /*
+ * START_REPLICATION
+ */
+ static void
+ StartReplication(StartReplicationCmd * cmd)
+ {
+ StringInfoData buf;
+
+ /*
+ * Check that we're logging enough information in the WAL for
+ * log-shipping.
+ *
+ * NOTE: This only checks the current value of wal_level. Even if the
+ * current setting is not 'minimal', there can be old WAL in the pg_xlog
+ * directory that was created with 'minimal'. So this is not bulletproof,
+ * the purpose is just to give a user-friendly error message that hints
+ * how to configure the system correctly.
+ */
+ if (wal_level == WAL_LEVEL_MINIMAL)
+ ereport(FATAL,
+ (errcode(ERRCODE_CANNOT_CONNECT_NOW),
+ errmsg("standby connections not allowed because wal_level=minimal")));
+
+ /* Send a CopyBothResponse message, and start streaming */
+ pq_beginmessage(&buf, 'W');
+ pq_sendbyte(&buf, 0);
+ pq_sendint(&buf, 0, 2);
+ pq_endmessage(&buf);
+ pq_flush();
+
+ /*
+ * Initialize position to the received one, then the xlog records begin to
+ * be shipped from that position
+ */
+ sentPtr = cmd->startpoint;
+ }
+
+ /*
+ * Execute an incoming replication command.
+ */
+ static bool
+ HandleReplicationCommand(const char *cmd_string)
+ {
+ bool replication_started = false;
+ int parse_rc;
+ Node *cmd_node;
+ MemoryContext cmd_context;
+ MemoryContext old_context;
+
+ elog(DEBUG1, "received replication command: %s", cmd_string);
+
+ cmd_context = AllocSetContextCreate(CurrentMemoryContext,
+ "Replication command context",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+ old_context = MemoryContextSwitchTo(cmd_context);
+
+ replication_scanner_init(cmd_string);
+ parse_rc = replication_yyparse();
+ if (parse_rc != 0)
+ elog(ERROR, "replication command parser returned %d", parse_rc);
+
+ cmd_node = replication_parse_result;
+
+ switch (cmd_node->type)
+ {
+ case T_IdentifySystemCmd:
+ IdentifySystem();
+ break;
+
+ case T_StartReplicationCmd:
+ StartReplication((StartReplicationCmd *) cmd_node);
+
+ /* break out of the loop */
+ replication_started = true;
+ break;
+
+ case T_BaseBackupCmd:
+ {
+ BaseBackupCmd *cmd = (BaseBackupCmd *) cmd_node;
+
+ SendBaseBackup(cmd->label, cmd->progress);
+
+ /* Send CommandComplete and ReadyForQuery messages */
+ EndCommand("SELECT", DestRemote);
+ ReadyForQuery(DestRemote);
+ /* ReadyForQuery did pq_flush for us */
+ break;
+ }
+
+ default:
+ ereport(FATAL,
+ (errcode(ERRCODE_PROTOCOL_VIOLATION),
+ errmsg("invalid standby query string: %s", cmd_string)));
+ }
+
+ /* done */
+ MemoryContextSwitchTo(old_context);
+ MemoryContextDelete(cmd_context);
+
+ return replication_started;
+ }
+
+ /*
* Check if the remote end has closed the connection.
*/
static void
*** a/src/include/replication/basebackup.h
--- b/src/include/replication/basebackup.h
***************
*** 12,17 ****
#ifndef _BASEBACKUP_H
#define _BASEBACKUP_H
! extern void SendBaseBackup(const char *options);
#endif /* _BASEBACKUP_H */
--- 12,17 ----
#ifndef _BASEBACKUP_H
#define _BASEBACKUP_H
! extern void SendBaseBackup(const char *backup_label, bool progress);
#endif /* _BASEBACKUP_H */
*** /dev/null
--- b/src/include/replication/replnodes.h
***************
*** 0 ****
--- 1,63 ----
+ /*-------------------------------------------------------------------------
+ *
+ * replnodes.h
+ * definitions for replication grammar parse nodes
+ *
+ *
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/replication/replnodes.h
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef REPLNODES_H
+ #define REPLNODES_H
+
+ #include "access/xlogdefs.h"
+ #include "nodes/primnodes.h"
+ #include "nodes/value.h"
+
+ /*
+ * NodeTags for replication parser
+ */
+ typedef enum ReplNodeTag
+ {
+ T_IdentifySystemCmd = 10,
+ T_BaseBackupCmd,
+ T_StartReplicationCmd
+ } ReplNodeTag;
+
+ /* ----------------------
+ * IDENTIFY_SYSTEM command
+ * ----------------------
+ */
+ typedef struct IdentifySystemCmd
+ {
+ NodeTag type;
+ } IdentifySystemCmd;
+
+
+ /* ----------------------
+ * BASE_BACKUP command
+ * ----------------------
+ */
+ typedef struct BaseBackupCmd
+ {
+ NodeTag type;
+ char *label;
+ bool progress;
+ } BaseBackupCmd;
+
+
+ /* ----------------------
+ * START_REPLICATION command
+ * ----------------------
+ */
+ typedef struct StartReplicationCmd
+ {
+ NodeTag type;
+ XLogRecPtr startpoint;
+ } StartReplicationCmd;
+
+ #endif /* REPLNODES_H */
*** a/src/include/replication/walsender.h
--- b/src/include/replication/walsender.h
***************
*** 13,18 ****
--- 13,19 ----
#define _WALSENDER_H
#include "access/xlog.h"
+ #include "nodes/nodes.h"
#include "storage/latch.h"
#include "storage/spin.h"
***************
*** 56,59 **** extern void WalSndWakeup(void);
--- 57,72 ----
extern Datum pg_stat_get_wal_senders(PG_FUNCTION_ARGS);
+ /*
+ * Internal functions for parsing the replication grammar, in repl_gram.y and
+ * repl_scanner.l
+ */
+ extern int replication_yyparse(void);
+ extern int replication_yylex(void);
+ extern void replication_yyerror(const char *str);
+ extern void replication_scanner_init(const char *query_string);
+ extern void replication_scanner_finish(void);
+
+ extern Node *replication_parse_result;
+
#endif /* _WALSENDER_H */
*** a/src/tools/msvc/Mkvcbuild.pm
--- b/src/tools/msvc/Mkvcbuild.pm
***************
*** 70,75 **** sub mkvcbuild
--- 70,76 ----
$postgres->AddFiles('src\backend\parser','scan.l','gram.y');
$postgres->AddFiles('src\backend\bootstrap','bootscanner.l','bootparse.y');
$postgres->AddFiles('src\backend\utils\misc','guc-file.l');
+ $postgres->AddFiles('src\backend\replication', 'repl_scanner.l', 'repl_gram.y');
$postgres->AddDefine('BUILDING_DLL');
$postgres->AddLibrary('wsock32.lib');
$postgres->AddLibrary('ws2_32.lib');
*** a/src/tools/msvc/pgbison.bat
--- b/src/tools/msvc/pgbison.bat
***************
*** 17,22 **** goto nobison
--- 17,23 ----
if "%1" == "src\backend\parser\gram.y" call :generate %1 src\backend\parser\gram.c src\backend\parser\gram.h
if "%1" == "src\backend\bootstrap\bootparse.y" call :generate %1 src\backend\bootstrap\bootparse.c
+ if "%1" == "src\backend\replication\repl_gram.y" call :generate %1 src\backend\replication\repl_gram.c
if "%1" == "src\pl\plpgsql\src\gram.y" call :generate %1 src\pl\plpgsql\src\pl_gram.c src\pl\plpgsql\src\pl_gram.h
if "%1" == "src\interfaces\ecpg\preproc\preproc.y" call :generate %1 src\interfaces\ecpg\preproc\preproc.c src\interfaces\ecpg\preproc\preproc.h
if "%1" == "contrib\cube\cubeparse.y" call :generate %1 contrib\cube\cubeparse.c
*** a/src/tools/msvc/pgflex.bat
--- b/src/tools/msvc/pgflex.bat
***************
*** 13,18 **** if errorlevel 1 goto noflex
--- 13,19 ----
if "%1" == "src\backend\parser\scan.l" call :generate %1 src\backend\parser\scan.c -CF
if "%1" == "src\backend\bootstrap\bootscanner.l" call :generate %1 src\backend\bootstrap\bootscanner.c
if "%1" == "src\backend\utils\misc\guc-file.l" call :generate %1 src\backend\utils\misc\guc-file.c
+ if "%1" == "src\backend\replication\repl_scanner.l" call :generate %1 src\backend\replication\repl_scanner.c
if "%1" == "src\interfaces\ecpg\preproc\pgc.l" call :generate %1 src\interfaces\ecpg\preproc\pgc.c
if "%1" == "src\bin\psql\psqlscan.l" call :generate %1 src\bin\psql\psqlscan.c
if "%1" == "contrib\cube\cubescan.l" call :generate %1 contrib\cube\cubescan.c