1 %{
2 /*-------------------------------------------------------------------------
3  *
4  * repl_gram.y				- Parser for the replication commands
5  *
6  * Portions Copyright (c) 1996-2017, 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 "access/xlogdefs.h"
19 #include "nodes/makefuncs.h"
20 #include "nodes/replnodes.h"
21 #include "replication/walsender.h"
22 #include "replication/walsender_private.h"
23 
24 
25 /* Result of the parsing is returned here */
26 Node *replication_parse_result;
27 
28 static SQLCmd *make_sqlcmd(void);
29 
30 
31 /*
32  * Bison doesn't allocate anything that needs to live across parser calls,
33  * so we can easily have it use palloc instead of malloc.  This prevents
34  * memory leaks if we error out during parsing.  Note this only works with
35  * bison >= 2.0.  However, in bison 1.875 the default is to use alloca()
36  * if possible, so there's not really much problem anyhow, at least if
37  * you're building with gcc.
38  */
39 #define YYMALLOC palloc
40 #define YYFREE   pfree
41 
42 %}
43 
44 %expect 0
45 %name-prefix="replication_yy"
46 
47 %union {
48 		char					*str;
49 		bool					boolval;
50 		uint32					uintval;
51 
52 		XLogRecPtr				recptr;
53 		Node					*node;
54 		List					*list;
55 		DefElem					*defelt;
56 }
57 
58 /* Non-keyword tokens */
59 %token <str> SCONST IDENT
60 %token <uintval> UCONST
61 %token <recptr> RECPTR
62 %token T_WORD
63 
64 /* Keyword tokens. */
65 %token K_BASE_BACKUP
66 %token K_IDENTIFY_SYSTEM
67 %token K_SHOW
68 %token K_START_REPLICATION
69 %token K_CREATE_REPLICATION_SLOT
70 %token K_DROP_REPLICATION_SLOT
71 %token K_TIMELINE_HISTORY
72 %token K_LABEL
73 %token K_PROGRESS
74 %token K_FAST
75 %token K_WAIT
76 %token K_NOWAIT
77 %token K_MAX_RATE
78 %token K_WAL
79 %token K_TABLESPACE_MAP
80 %token K_TIMELINE
81 %token K_PHYSICAL
82 %token K_LOGICAL
83 %token K_SLOT
84 %token K_RESERVE_WAL
85 %token K_TEMPORARY
86 %token K_EXPORT_SNAPSHOT
87 %token K_NOEXPORT_SNAPSHOT
88 %token K_USE_SNAPSHOT
89 
90 %type <node>	command
91 %type <node>	base_backup start_replication start_logical_replication
92 				create_replication_slot drop_replication_slot identify_system
93 				timeline_history show sql_cmd
94 %type <list>	base_backup_opt_list
95 %type <defelt>	base_backup_opt
96 %type <uintval>	opt_timeline
97 %type <list>	plugin_options plugin_opt_list
98 %type <defelt>	plugin_opt_elem
99 %type <node>	plugin_opt_arg
100 %type <str>		opt_slot var_name
101 %type <boolval>	opt_temporary
102 %type <list>	create_slot_opt_list
103 %type <defelt>	create_slot_opt
104 
105 %%
106 
107 firstcmd: command opt_semicolon
108 				{
109 					replication_parse_result = $1;
110 				}
111 			;
112 
113 opt_semicolon:	';'
114 				| /* EMPTY */
115 				;
116 
117 command:
118 			identify_system
119 			| base_backup
120 			| start_replication
121 			| start_logical_replication
122 			| create_replication_slot
123 			| drop_replication_slot
124 			| timeline_history
125 			| show
126 			| sql_cmd
127 			;
128 
129 /*
130  * IDENTIFY_SYSTEM
131  */
132 identify_system:
133 			K_IDENTIFY_SYSTEM
134 				{
135 					$$ = (Node *) makeNode(IdentifySystemCmd);
136 				}
137 			;
138 
139 /*
140  * SHOW setting
141  */
142 show:
143 			K_SHOW var_name
144 				{
145 					VariableShowStmt *n = makeNode(VariableShowStmt);
146 					n->name = $2;
147 					$$ = (Node *) n;
148 				}
149 
150 var_name:	IDENT	{ $$ = $1; }
151 			| var_name '.' IDENT
152 				{ $$ = psprintf("%s.%s", $1, $3); }
153 		;
154 
155 /*
156  * BASE_BACKUP [LABEL '<label>'] [PROGRESS] [FAST] [WAL] [NOWAIT]
157  * [MAX_RATE %d] [TABLESPACE_MAP]
158  */
159 base_backup:
160 			K_BASE_BACKUP base_backup_opt_list
161 				{
162 					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
163 					cmd->options = $2;
164 					$$ = (Node *) cmd;
165 				}
166 			;
167 
168 base_backup_opt_list:
169 			base_backup_opt_list base_backup_opt
170 				{ $$ = lappend($1, $2); }
171 			| /* EMPTY */
172 				{ $$ = NIL; }
173 			;
174 
175 base_backup_opt:
176 			K_LABEL SCONST
177 				{
178 				  $$ = makeDefElem("label",
179 								   (Node *)makeString($2), -1);
180 				}
181 			| K_PROGRESS
182 				{
183 				  $$ = makeDefElem("progress",
184 								   (Node *)makeInteger(TRUE), -1);
185 				}
186 			| K_FAST
187 				{
188 				  $$ = makeDefElem("fast",
189 								   (Node *)makeInteger(TRUE), -1);
190 				}
191 			| K_WAL
192 				{
193 				  $$ = makeDefElem("wal",
194 								   (Node *)makeInteger(TRUE), -1);
195 				}
196 			| K_NOWAIT
197 				{
198 				  $$ = makeDefElem("nowait",
199 								   (Node *)makeInteger(TRUE), -1);
200 				}
201 			| K_MAX_RATE UCONST
202 				{
203 				  $$ = makeDefElem("max_rate",
204 								   (Node *)makeInteger($2), -1);
205 				}
206 			| K_TABLESPACE_MAP
207 				{
208 				  $$ = makeDefElem("tablespace_map",
209 								   (Node *)makeInteger(TRUE), -1);
210 				}
211 			;
212 
213 create_replication_slot:
214 			/* CREATE_REPLICATION_SLOT slot TEMPORARY PHYSICAL RESERVE_WAL */
215 			K_CREATE_REPLICATION_SLOT IDENT opt_temporary K_PHYSICAL create_slot_opt_list
216 				{
217 					CreateReplicationSlotCmd *cmd;
218 					cmd = makeNode(CreateReplicationSlotCmd);
219 					cmd->kind = REPLICATION_KIND_PHYSICAL;
220 					cmd->slotname = $2;
221 					cmd->temporary = $3;
222 					cmd->options = $5;
223 					$$ = (Node *) cmd;
224 				}
225 			/* CREATE_REPLICATION_SLOT slot TEMPORARY LOGICAL plugin */
226 			| K_CREATE_REPLICATION_SLOT IDENT opt_temporary K_LOGICAL IDENT create_slot_opt_list
227 				{
228 					CreateReplicationSlotCmd *cmd;
229 					cmd = makeNode(CreateReplicationSlotCmd);
230 					cmd->kind = REPLICATION_KIND_LOGICAL;
231 					cmd->slotname = $2;
232 					cmd->temporary = $3;
233 					cmd->plugin = $5;
234 					cmd->options = $6;
235 					$$ = (Node *) cmd;
236 				}
237 			;
238 
239 create_slot_opt_list:
240 			create_slot_opt_list create_slot_opt
241 				{ $$ = lappend($1, $2); }
242 			| /* EMPTY */
243 				{ $$ = NIL; }
244 			;
245 
246 create_slot_opt:
247 			K_EXPORT_SNAPSHOT
248 				{
249 				  $$ = makeDefElem("export_snapshot",
250 								   (Node *)makeInteger(TRUE), -1);
251 				}
252 			| K_NOEXPORT_SNAPSHOT
253 				{
254 				  $$ = makeDefElem("export_snapshot",
255 								   (Node *)makeInteger(FALSE), -1);
256 				}
257 			| K_USE_SNAPSHOT
258 				{
259 				  $$ = makeDefElem("use_snapshot",
260 								   (Node *)makeInteger(TRUE), -1);
261 				}
262 			| K_RESERVE_WAL
263 				{
264 				  $$ = makeDefElem("reserve_wal",
265 								   (Node *)makeInteger(TRUE), -1);
266 				}
267 			;
268 
269 /* DROP_REPLICATION_SLOT slot */
270 drop_replication_slot:
271 			K_DROP_REPLICATION_SLOT IDENT
272 				{
273 					DropReplicationSlotCmd *cmd;
274 					cmd = makeNode(DropReplicationSlotCmd);
275 					cmd->slotname = $2;
276 					cmd->wait = false;
277 					$$ = (Node *) cmd;
278 				}
279 			| K_DROP_REPLICATION_SLOT IDENT K_WAIT
280 				{
281 					DropReplicationSlotCmd *cmd;
282 					cmd = makeNode(DropReplicationSlotCmd);
283 					cmd->slotname = $2;
284 					cmd->wait = true;
285 					$$ = (Node *) cmd;
286 				}
287 			;
288 
289 /*
290  * START_REPLICATION [SLOT slot] [PHYSICAL] %X/%X [TIMELINE %d]
291  */
292 start_replication:
293 			K_START_REPLICATION opt_slot opt_physical RECPTR opt_timeline
294 				{
295 					StartReplicationCmd *cmd;
296 
297 					cmd = makeNode(StartReplicationCmd);
298 					cmd->kind = REPLICATION_KIND_PHYSICAL;
299 					cmd->slotname = $2;
300 					cmd->startpoint = $4;
301 					cmd->timeline = $5;
302 					$$ = (Node *) cmd;
303 				}
304 			;
305 
306 /* START_REPLICATION SLOT slot LOGICAL %X/%X options */
307 start_logical_replication:
308 			K_START_REPLICATION K_SLOT IDENT K_LOGICAL RECPTR plugin_options
309 				{
310 					StartReplicationCmd *cmd;
311 					cmd = makeNode(StartReplicationCmd);
312 					cmd->kind = REPLICATION_KIND_LOGICAL;
313 					cmd->slotname = $3;
314 					cmd->startpoint = $5;
315 					cmd->options = $6;
316 					$$ = (Node *) cmd;
317 				}
318 			;
319 /*
320  * TIMELINE_HISTORY %d
321  */
322 timeline_history:
323 			K_TIMELINE_HISTORY UCONST
324 				{
325 					TimeLineHistoryCmd *cmd;
326 
327 					if ($2 <= 0)
328 						ereport(ERROR,
329 								(errcode(ERRCODE_SYNTAX_ERROR),
330 								 (errmsg("invalid timeline %u", $2))));
331 
332 					cmd = makeNode(TimeLineHistoryCmd);
333 					cmd->timeline = $2;
334 
335 					$$ = (Node *) cmd;
336 				}
337 			;
338 
339 opt_physical:
340 			K_PHYSICAL
341 			| /* EMPTY */
342 			;
343 
344 opt_temporary:
345 			K_TEMPORARY						{ $$ = true; }
346 			| /* EMPTY */					{ $$ = false; }
347 			;
348 
349 opt_slot:
350 			K_SLOT IDENT
351 				{ $$ = $2; }
352 			| /* EMPTY */
353 				{ $$ = NULL; }
354 			;
355 
356 opt_timeline:
357 			K_TIMELINE UCONST
358 				{
359 					if ($2 <= 0)
360 						ereport(ERROR,
361 								(errcode(ERRCODE_SYNTAX_ERROR),
362 								 (errmsg("invalid timeline %u", $2))));
363 					$$ = $2;
364 				}
365 				| /* EMPTY */			{ $$ = 0; }
366 			;
367 
368 
369 plugin_options:
370 			'(' plugin_opt_list ')'			{ $$ = $2; }
371 			| /* EMPTY */					{ $$ = NIL; }
372 		;
373 
374 plugin_opt_list:
375 			plugin_opt_elem
376 				{
377 					$$ = list_make1($1);
378 				}
379 			| plugin_opt_list ',' plugin_opt_elem
380 				{
381 					$$ = lappend($1, $3);
382 				}
383 		;
384 
385 plugin_opt_elem:
386 			IDENT plugin_opt_arg
387 				{
388 					$$ = makeDefElem($1, $2, -1);
389 				}
390 		;
391 
392 plugin_opt_arg:
393 			SCONST							{ $$ = (Node *) makeString($1); }
394 			| /* EMPTY */					{ $$ = NULL; }
395 		;
396 
397 sql_cmd:
398 			IDENT							{ $$ = (Node *) make_sqlcmd(); }
399 		;
400 %%
401 
402 static SQLCmd *
403 make_sqlcmd(void)
404 {
405 	SQLCmd *cmd = makeNode(SQLCmd);
406 	int tok;
407 
408 	/* Just move lexer to the end of command. */
409 	for (;;)
410 	{
411 		tok = yylex();
412 		if (tok == ';' || tok == 0)
413 			break;
414 	}
415 	return cmd;
416 }
417 
418 #include "repl_scanner.c"
419