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