Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit fcd810c

Browse files
committed
Use a lexer and grammar for parsing walsender commands
Makes it easier to parse mainly the BASE_BACKUP command with it's options, and avoids having to manually deal with quoted identifiers in the label (previously broken), and makes it easier to add new commands and options in the future. In passing, refactor the case statement in the walsender to put each command in it's own function.
1 parent 688423d commit fcd810c

File tree

12 files changed

+603
-128
lines changed

12 files changed

+603
-128
lines changed

doc/src/sgml/protocol.sgml

+16-5
Original file line numberDiff line numberDiff line change
@@ -1460,15 +1460,26 @@ The commands accepted in walsender mode are:
14601460
</varlistentry>
14611461

14621462
<varlistentry>
1463-
<term>BASE_BACKUP <replaceable>options</><literal>;</><replaceable>label</></term>
1463+
<term>BASE_BACKUP [<literal>LABEL</literal> <replaceable>'label'</replaceable>] [<literal>PROGRESS</literal>]</term>
14641464
<listitem>
14651465
<para>
14661466
Instructs the server to start streaming a base backup.
1467-
The system will automatically be put in backup mode with the label
1468-
specified in <replaceable>label</> before the backup is started, and
1469-
taken out of it when the backup is complete. The following options
1470-
are accepted:
1467+
The system will automatically be put in backup mode before the backup
1468+
is started, and taken out of it when the backup is complete. The
1469+
following options are accepted:
14711470
<variablelist>
1471+
<varlistentry>
1472+
<term><literal>LABEL</literal> <replaceable>'label'</replaceable></term>
1473+
<listitem>
1474+
<para>
1475+
Sets the label of the backup. If none is specified, a backup label
1476+
of <literal>base backup</literal> will be used. The quoting rules
1477+
for the label are the same as a standard SQL string with
1478+
<xref linkend="guc-standard-conforming-strings"> turned on.
1479+
</para>
1480+
</listitem>
1481+
</varlistentry>
1482+
14721483
<varlistentry>
14731484
<term><literal>PROGRESS</></term>
14741485
<listitem>

src/backend/replication/Makefile

+24-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,29 @@ subdir = src/backend/replication
1212
top_builddir = ../../..
1313
include $(top_builddir)/src/Makefile.global
1414

15-
OBJS = walsender.o walreceiverfuncs.o walreceiver.o basebackup.o
15+
OBJS = walsender.o walreceiverfuncs.o walreceiver.o basebackup.o \
16+
repl_gram.o
1617

1718
include $(top_srcdir)/src/backend/common.mk
19+
20+
# repl_scanner is compiled as part of repl_gram
21+
repl_gram.o: repl_scanner.c
22+
23+
# See notes in src/backend/parser/Makefile about the following two rules
24+
25+
repl_gram.c: repl_gram.y
26+
ifdef BISON
27+
$(BISON) -d $(BISONFLAGS) -o $@ $<
28+
else
29+
@$(missing) bison $< $@
30+
endif
31+
32+
repl_scanner.c: repl_scanner.l
33+
ifdef FLEX
34+
$(FLEX) $(FLEXFLAGS) -o'$@' $<
35+
else
36+
@$(missing) flex $< $@
37+
endif
38+
39+
# repl_gram.c and repl_scanner.c are in the distribution tarball, so
40+
# they are not cleaned here.

src/backend/replication/basebackup.c

+2-15
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,10 @@ perform_base_backup(const char *backup_label, List *tablespaces)
9898
* pg_stop_backup() for the user.
9999
*/
100100
void
101-
SendBaseBackup(const char *options)
101+
SendBaseBackup(const char *backup_label, bool progress)
102102
{
103103
DIR *dir;
104104
struct dirent *de;
105-
char *backup_label = strchr(options, ';');
106-
bool progress = false;
107105
List *tablespaces = NIL;
108106
tablespaceinfo *ti;
109107
MemoryContext backup_context;
@@ -119,18 +117,7 @@ SendBaseBackup(const char *options)
119117
WalSndSetState(WALSNDSTATE_BACKUP);
120118

121119
if (backup_label == NULL)
122-
ereport(FATAL,
123-
(errcode(ERRCODE_PROTOCOL_VIOLATION),
124-
errmsg("invalid base backup options: %s", options)));
125-
backup_label++; /* Walk past the semicolon */
126-
127-
/* Currently the only option string supported is PROGRESS */
128-
if (strncmp(options, "PROGRESS", 8) == 0)
129-
progress = true;
130-
else if (options[0] != ';')
131-
ereport(FATAL,
132-
(errcode(ERRCODE_PROTOCOL_VIOLATION),
133-
errmsg("invalid base backup options: %s", options)));
120+
backup_label = "base backup";
134121

135122
if (update_process_title)
136123
{

src/backend/replication/repl_gram.y

+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
%{
2+
/*-------------------------------------------------------------------------
3+
*
4+
* repl_gram.y - Parser for the replication commands
5+
*
6+
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7+
* Portions Copyright (c) 1994, Regents of the University of California
8+
*
9+
*
10+
* IDENTIFICATION
11+
* src/backend/replication/repl_gram.y
12+
*
13+
*-------------------------------------------------------------------------
14+
*/
15+
16+
#include "postgres.h"
17+
18+
#include "replication/replnodes.h"
19+
#include "replication/walsender.h"
20+
21+
/* Result of the parsing is returned here */
22+
Node *replication_parse_result;
23+
24+
/* Location tracking support --- simpler than bison's default */
25+
#define YYLLOC_DEFAULT(Current, Rhs, N) \
26+
do { \
27+
if (N) \
28+
(Current) = (Rhs)[1]; \
29+
else \
30+
(Current) = (Rhs)[0]; \
31+
} while (0)
32+
33+
/*
34+
* Bison doesn't allocate anything that needs to live across parser calls,
35+
* so we can easily have it use palloc instead of malloc. This prevents
36+
* memory leaks if we error out during parsing. Note this only works with
37+
* bison >= 2.0. However, in bison 1.875 the default is to use alloca()
38+
* if possible, so there's not really much problem anyhow, at least if
39+
* you're building with gcc.
40+
*/
41+
#define YYMALLOC palloc
42+
#define YYFREE pfree
43+
44+
#define parser_yyerror(msg) replication_yyerror(msg, yyscanner)
45+
#define parser_errposition(pos) replication_scanner_errposition(pos)
46+
47+
%}
48+
49+
%expect 0
50+
%name-prefix="replication_yy"
51+
52+
%union {
53+
char *str;
54+
bool boolval;
55+
56+
XLogRecPtr recptr;
57+
Node *node;
58+
}
59+
60+
/* Non-keyword tokens */
61+
%token <str> SCONST
62+
%token <recptr> RECPTR
63+
64+
/* Keyword tokens. */
65+
%token K_BASE_BACKUP
66+
%token K_IDENTIFY_SYSTEM
67+
%token K_LABEL
68+
%token K_PROGRESS
69+
%token K_START_REPLICATION
70+
71+
%type <node> command
72+
%type <node> base_backup start_replication identify_system
73+
%type <boolval> opt_progress
74+
%type <str> opt_label
75+
76+
%%
77+
78+
firstcmd: command opt_semicolon
79+
{
80+
replication_parse_result = $1;
81+
}
82+
;
83+
84+
opt_semicolon: ';'
85+
| /* EMPTY */
86+
;
87+
88+
command:
89+
identify_system
90+
| base_backup
91+
| start_replication
92+
;
93+
94+
/*
95+
* IDENTIFY_SYSTEM
96+
*/
97+
identify_system:
98+
K_IDENTIFY_SYSTEM
99+
{
100+
$$ = (Node *) makeNode(IdentifySystemCmd);
101+
}
102+
;
103+
104+
/*
105+
* BASE_BACKUP [LABEL <label>] [PROGRESS]
106+
*/
107+
base_backup:
108+
K_BASE_BACKUP opt_label opt_progress
109+
{
110+
BaseBackupCmd *cmd = (BaseBackupCmd *) makeNode(BaseBackupCmd);
111+
112+
cmd->label = $2;
113+
cmd->progress = $3;
114+
115+
$$ = (Node *) cmd;
116+
}
117+
;
118+
119+
opt_label: K_LABEL SCONST { $$ = $2; }
120+
| /* EMPTY */ { $$ = NULL; }
121+
;
122+
123+
opt_progress: K_PROGRESS { $$ = true; }
124+
| /* EMPTY */ { $$ = false; }
125+
;
126+
127+
/*
128+
* START_REPLICATION %X/%X
129+
*/
130+
start_replication:
131+
K_START_REPLICATION RECPTR
132+
{
133+
StartReplicationCmd *cmd;
134+
135+
cmd = makeNode(StartReplicationCmd);
136+
cmd->startpoint = $2;
137+
138+
$$ = (Node *) cmd;
139+
}
140+
;
141+
%%
142+
143+
#include "repl_scanner.c"

0 commit comments

Comments
 (0)