1 %{
2 /*-------------------------------------------------------------------------
3  *
4  * repl_gram.y				- Parser for the replication commands
5  *
6  * Portions Copyright (c) 1996-2019, 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_NOVERIFY_CHECKSUMS
81 %token K_TIMELINE
82 %token K_PHYSICAL
83 %token K_LOGICAL
84 %token K_SLOT
85 %token K_RESERVE_WAL
86 %token K_TEMPORARY
87 %token K_EXPORT_SNAPSHOT
88 %token K_NOEXPORT_SNAPSHOT
89 %token K_USE_SNAPSHOT
90 
91 %type <node>	command
92 %type <node>	base_backup start_replication start_logical_replication
93 				create_replication_slot drop_replication_slot identify_system
94 				timeline_history show sql_cmd
95 %type <list>	base_backup_opt_list
96 %type <defelt>	base_backup_opt
97 %type <uintval>	opt_timeline
98 %type <list>	plugin_options plugin_opt_list
99 %type <defelt>	plugin_opt_elem
100 %type <node>	plugin_opt_arg
101 %type <str>		opt_slot var_name
102 %type <boolval>	opt_temporary
103 %type <list>	create_slot_opt_list
104 %type <defelt>	create_slot_opt
105 
106 %%
107 
108 firstcmd: command opt_semicolon
109 				{
110 					replication_parse_result = $1;
111 				}
112 			;
113 
114 opt_semicolon:	';'
115 				| /* EMPTY */
116 				;
117 
118 command:
119 			identify_system
120 			| base_backup
121 			| start_replication
122 			| start_logical_replication
123 			| create_replication_slot
124 			| drop_replication_slot
125 			| timeline_history
126 			| show
127 			| sql_cmd
128 			;
129 
130 /*
131  * IDENTIFY_SYSTEM
132  */
133 identify_system:
134 			K_IDENTIFY_SYSTEM
135 				{
136 					$$ = (Node *) makeNode(IdentifySystemCmd);
137 				}
138 			;
139 
140 /*
141  * SHOW setting
142  */
143 show:
144 			K_SHOW var_name
145 				{
146 					VariableShowStmt *n = makeNode(VariableShowStmt);
147 					n->name = $2;
148 					$$ = (Node *) n;
149 				}
150 
151 var_name:	IDENT	{ $$ = $1; }
152 			| var_name '.' IDENT
153 				{ $$ = psprintf("%s.%s", $1, $3); }
154 		;
155 
156 /*
157  * BASE_BACKUP [LABEL '<label>'] [PROGRESS] [FAST] [WAL] [NOWAIT]
158  * [MAX_RATE %d] [TABLESPACE_MAP] [NOVERIFY_CHECKSUMS]
159  */
160 base_backup:
161 			K_BASE_BACKUP base_backup_opt_list
162 				{
163 					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
164 					cmd->options = $2;
165 					$$ = (Node *) cmd;
166 				}
167 			;
168 
169 base_backup_opt_list:
170 			base_backup_opt_list base_backup_opt
171 				{ $$ = lappend($1, $2); }
172 			| /* EMPTY */
173 				{ $$ = NIL; }
174 			;
175 
176 base_backup_opt:
177 			K_LABEL SCONST
178 				{
179 				  $$ = makeDefElem("label",
180 								   (Node *)makeString($2), -1);
181 				}
182 			| K_PROGRESS
183 				{
184 				  $$ = makeDefElem("progress",
185 								   (Node *)makeInteger(true), -1);
186 				}
187 			| K_FAST
188 				{
189 				  $$ = makeDefElem("fast",
190 								   (Node *)makeInteger(true), -1);
191 				}
192 			| K_WAL
193 				{
194 				  $$ = makeDefElem("wal",
195 								   (Node *)makeInteger(true), -1);
196 				}
197 			| K_NOWAIT
198 				{
199 				  $$ = makeDefElem("nowait",
200 								   (Node *)makeInteger(true), -1);
201 				}
202 			| K_MAX_RATE UCONST
203 				{
204 				  $$ = makeDefElem("max_rate",
205 								   (Node *)makeInteger($2), -1);
206 				}
207 			| K_TABLESPACE_MAP
208 				{
209 				  $$ = makeDefElem("tablespace_map",
210 								   (Node *)makeInteger(true), -1);
211 				}
212 			| K_NOVERIFY_CHECKSUMS
213 				{
214 				  $$ = makeDefElem("noverify_checksums",
215 								   (Node *)makeInteger(true), -1);
216 				}
217 			;
218 
219 create_replication_slot:
220 			/* CREATE_REPLICATION_SLOT slot TEMPORARY PHYSICAL RESERVE_WAL */
221 			K_CREATE_REPLICATION_SLOT IDENT opt_temporary K_PHYSICAL create_slot_opt_list
222 				{
223 					CreateReplicationSlotCmd *cmd;
224 					cmd = makeNode(CreateReplicationSlotCmd);
225 					cmd->kind = REPLICATION_KIND_PHYSICAL;
226 					cmd->slotname = $2;
227 					cmd->temporary = $3;
228 					cmd->options = $5;
229 					$$ = (Node *) cmd;
230 				}
231 			/* CREATE_REPLICATION_SLOT slot TEMPORARY LOGICAL plugin */
232 			| K_CREATE_REPLICATION_SLOT IDENT opt_temporary K_LOGICAL IDENT create_slot_opt_list
233 				{
234 					CreateReplicationSlotCmd *cmd;
235 					cmd = makeNode(CreateReplicationSlotCmd);
236 					cmd->kind = REPLICATION_KIND_LOGICAL;
237 					cmd->slotname = $2;
238 					cmd->temporary = $3;
239 					cmd->plugin = $5;
240 					cmd->options = $6;
241 					$$ = (Node *) cmd;
242 				}
243 			;
244 
245 create_slot_opt_list:
246 			create_slot_opt_list create_slot_opt
247 				{ $$ = lappend($1, $2); }
248 			| /* EMPTY */
249 				{ $$ = NIL; }
250 			;
251 
252 create_slot_opt:
253 			K_EXPORT_SNAPSHOT
254 				{
255 				  $$ = makeDefElem("export_snapshot",
256 								   (Node *)makeInteger(true), -1);
257 				}
258 			| K_NOEXPORT_SNAPSHOT
259 				{
260 				  $$ = makeDefElem("export_snapshot",
261 								   (Node *)makeInteger(false), -1);
262 				}
263 			| K_USE_SNAPSHOT
264 				{
265 				  $$ = makeDefElem("use_snapshot",
266 								   (Node *)makeInteger(true), -1);
267 				}
268 			| K_RESERVE_WAL
269 				{
270 				  $$ = makeDefElem("reserve_wal",
271 								   (Node *)makeInteger(true), -1);
272 				}
273 			;
274 
275 /* DROP_REPLICATION_SLOT slot */
276 drop_replication_slot:
277 			K_DROP_REPLICATION_SLOT IDENT
278 				{
279 					DropReplicationSlotCmd *cmd;
280 					cmd = makeNode(DropReplicationSlotCmd);
281 					cmd->slotname = $2;
282 					cmd->wait = false;
283 					$$ = (Node *) cmd;
284 				}
285 			| K_DROP_REPLICATION_SLOT IDENT K_WAIT
286 				{
287 					DropReplicationSlotCmd *cmd;
288 					cmd = makeNode(DropReplicationSlotCmd);
289 					cmd->slotname = $2;
290 					cmd->wait = true;
291 					$$ = (Node *) cmd;
292 				}
293 			;
294 
295 /*
296  * START_REPLICATION [SLOT slot] [PHYSICAL] %X/%X [TIMELINE %d]
297  */
298 start_replication:
299 			K_START_REPLICATION opt_slot opt_physical RECPTR opt_timeline
300 				{
301 					StartReplicationCmd *cmd;
302 
303 					cmd = makeNode(StartReplicationCmd);
304 					cmd->kind = REPLICATION_KIND_PHYSICAL;
305 					cmd->slotname = $2;
306 					cmd->startpoint = $4;
307 					cmd->timeline = $5;
308 					$$ = (Node *) cmd;
309 				}
310 			;
311 
312 /* START_REPLICATION SLOT slot LOGICAL %X/%X options */
313 start_logical_replication:
314 			K_START_REPLICATION K_SLOT IDENT K_LOGICAL RECPTR plugin_options
315 				{
316 					StartReplicationCmd *cmd;
317 					cmd = makeNode(StartReplicationCmd);
318 					cmd->kind = REPLICATION_KIND_LOGICAL;
319 					cmd->slotname = $3;
320 					cmd->startpoint = $5;
321 					cmd->options = $6;
322 					$$ = (Node *) cmd;
323 				}
324 			;
325 /*
326  * TIMELINE_HISTORY %d
327  */
328 timeline_history:
329 			K_TIMELINE_HISTORY UCONST
330 				{
331 					TimeLineHistoryCmd *cmd;
332 
333 					if ($2 <= 0)
334 						ereport(ERROR,
335 								(errcode(ERRCODE_SYNTAX_ERROR),
336 								 (errmsg("invalid timeline %u", $2))));
337 
338 					cmd = makeNode(TimeLineHistoryCmd);
339 					cmd->timeline = $2;
340 
341 					$$ = (Node *) cmd;
342 				}
343 			;
344 
345 opt_physical:
346 			K_PHYSICAL
347 			| /* EMPTY */
348 			;
349 
350 opt_temporary:
351 			K_TEMPORARY						{ $$ = true; }
352 			| /* EMPTY */					{ $$ = false; }
353 			;
354 
355 opt_slot:
356 			K_SLOT IDENT
357 				{ $$ = $2; }
358 			| /* EMPTY */
359 				{ $$ = NULL; }
360 			;
361 
362 opt_timeline:
363 			K_TIMELINE UCONST
364 				{
365 					if ($2 <= 0)
366 						ereport(ERROR,
367 								(errcode(ERRCODE_SYNTAX_ERROR),
368 								 (errmsg("invalid timeline %u", $2))));
369 					$$ = $2;
370 				}
371 				| /* EMPTY */			{ $$ = 0; }
372 			;
373 
374 
375 plugin_options:
376 			'(' plugin_opt_list ')'			{ $$ = $2; }
377 			| /* EMPTY */					{ $$ = NIL; }
378 		;
379 
380 plugin_opt_list:
381 			plugin_opt_elem
382 				{
383 					$$ = list_make1($1);
384 				}
385 			| plugin_opt_list ',' plugin_opt_elem
386 				{
387 					$$ = lappend($1, $3);
388 				}
389 		;
390 
391 plugin_opt_elem:
392 			IDENT plugin_opt_arg
393 				{
394 					$$ = makeDefElem($1, $2, -1);
395 				}
396 		;
397 
398 plugin_opt_arg:
399 			SCONST							{ $$ = (Node *) makeString($1); }
400 			| /* EMPTY */					{ $$ = NULL; }
401 		;
402 
403 sql_cmd:
404 			IDENT							{ $$ = (Node *) make_sqlcmd(); }
405 		;
406 %%
407 
408 static SQLCmd *
409 make_sqlcmd(void)
410 {
411 	SQLCmd *cmd = makeNode(SQLCmd);
412 	int tok;
413 
414 	/* Just move lexer to the end of command. */
415 	for (;;)
416 	{
417 		tok = yylex();
418 		if (tok == ';' || tok == 0)
419 			break;
420 	}
421 	return cmd;
422 }
423 
424 #include "repl_scanner.c"
425