Line data Source code
1 : %{
2 : /*-------------------------------------------------------------------------
3 : *
4 : * repl_gram.y - Parser for the replication commands
5 : *
6 : * Portions Copyright (c) 1996-2025, 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/parsenodes.h"
21 : #include "nodes/replnodes.h"
22 : #include "replication/walsender.h"
23 : #include "replication/walsender_private.h"
24 :
25 : #include "repl_gram.h"
26 :
27 :
28 : /* Result of the parsing is returned here */
29 : Node *replication_parse_result;
30 :
31 :
32 : /*
33 : * Bison doesn't allocate anything that needs to live across parser calls,
34 : * so we can easily have it use palloc instead of malloc. This prevents
35 : * memory leaks if we error out during parsing.
36 : */
37 : #define YYMALLOC palloc
38 : #define YYFREE pfree
39 :
40 : %}
41 :
42 : %parse-param {yyscan_t yyscanner}
43 : %lex-param {yyscan_t yyscanner}
44 : %pure-parser
45 : %expect 0
46 : %name-prefix="replication_yy"
47 :
48 : %union
49 : {
50 : char *str;
51 : bool boolval;
52 : uint32 uintval;
53 : XLogRecPtr recptr;
54 : Node *node;
55 : List *list;
56 : DefElem *defelt;
57 : }
58 :
59 : /* Non-keyword tokens */
60 : %token <str> SCONST IDENT
61 : %token <uintval> UCONST
62 : %token <recptr> RECPTR
63 :
64 : /* Keyword tokens. */
65 : %token K_BASE_BACKUP
66 : %token K_IDENTIFY_SYSTEM
67 : %token K_READ_REPLICATION_SLOT
68 : %token K_SHOW
69 : %token K_START_REPLICATION
70 : %token K_CREATE_REPLICATION_SLOT
71 : %token K_DROP_REPLICATION_SLOT
72 : %token K_ALTER_REPLICATION_SLOT
73 : %token K_TIMELINE_HISTORY
74 : %token K_WAIT
75 : %token K_TIMELINE
76 : %token K_PHYSICAL
77 : %token K_LOGICAL
78 : %token K_SLOT
79 : %token K_RESERVE_WAL
80 : %token K_TEMPORARY
81 : %token K_TWO_PHASE
82 : %token K_EXPORT_SNAPSHOT
83 : %token K_NOEXPORT_SNAPSHOT
84 : %token K_USE_SNAPSHOT
85 : %token K_UPLOAD_MANIFEST
86 :
87 : %type <node> command
88 : %type <node> base_backup start_replication start_logical_replication
89 : create_replication_slot drop_replication_slot
90 : alter_replication_slot identify_system read_replication_slot
91 : timeline_history show upload_manifest
92 : %type <list> generic_option_list
93 : %type <defelt> generic_option
94 : %type <uintval> opt_timeline
95 : %type <list> plugin_options plugin_opt_list
96 : %type <defelt> plugin_opt_elem
97 : %type <node> plugin_opt_arg
98 : %type <str> opt_slot var_name ident_or_keyword
99 : %type <boolval> opt_temporary
100 : %type <list> create_slot_options create_slot_legacy_opt_list
101 : %type <defelt> create_slot_legacy_opt
102 :
103 : %%
104 :
105 : firstcmd: command opt_semicolon
106 : {
107 5472 : replication_parse_result = $1;
108 :
109 : (void) yynerrs; /* suppress compiler warning */
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 : | alter_replication_slot
125 : | read_replication_slot
126 : | timeline_history
127 : | show
128 : | upload_manifest
129 : ;
130 :
131 : /*
132 : * IDENTIFY_SYSTEM
133 : */
134 : identify_system:
135 : K_IDENTIFY_SYSTEM
136 : {
137 1314 : $$ = (Node *) makeNode(IdentifySystemCmd);
138 : }
139 : ;
140 :
141 : /*
142 : * READ_REPLICATION_SLOT %s
143 : */
144 : read_replication_slot:
145 : K_READ_REPLICATION_SLOT var_name
146 : {
147 12 : ReadReplicationSlotCmd *n = makeNode(ReadReplicationSlotCmd);
148 12 : n->slotname = $2;
149 12 : $$ = (Node *) n;
150 : }
151 : ;
152 :
153 : /*
154 : * SHOW setting
155 : */
156 : show:
157 : K_SHOW var_name
158 : {
159 1108 : VariableShowStmt *n = makeNode(VariableShowStmt);
160 1108 : n->name = $2;
161 1108 : $$ = (Node *) n;
162 : }
163 :
164 1120 : var_name: IDENT { $$ = $1; }
165 : | var_name '.' IDENT
166 0 : { $$ = psprintf("%s.%s", $1, $3); }
167 : ;
168 :
169 : /*
170 : * BASE_BACKUP [ ( option [ 'value' ] [, ...] ) ]
171 : */
172 : base_backup:
173 : K_BASE_BACKUP '(' generic_option_list ')'
174 : {
175 350 : BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
176 350 : cmd->options = $3;
177 350 : $$ = (Node *) cmd;
178 : }
179 : | K_BASE_BACKUP
180 : {
181 2 : BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
182 2 : $$ = (Node *) cmd;
183 : }
184 : ;
185 :
186 : create_replication_slot:
187 : /* CREATE_REPLICATION_SLOT slot [TEMPORARY] PHYSICAL [options] */
188 : K_CREATE_REPLICATION_SLOT IDENT opt_temporary K_PHYSICAL create_slot_options
189 : {
190 : CreateReplicationSlotCmd *cmd;
191 268 : cmd = makeNode(CreateReplicationSlotCmd);
192 268 : cmd->kind = REPLICATION_KIND_PHYSICAL;
193 268 : cmd->slotname = $2;
194 268 : cmd->temporary = $3;
195 268 : cmd->options = $5;
196 268 : $$ = (Node *) cmd;
197 : }
198 : /* CREATE_REPLICATION_SLOT slot [TEMPORARY] LOGICAL plugin [options] */
199 : | K_CREATE_REPLICATION_SLOT IDENT opt_temporary K_LOGICAL IDENT create_slot_options
200 : {
201 : CreateReplicationSlotCmd *cmd;
202 622 : cmd = makeNode(CreateReplicationSlotCmd);
203 622 : cmd->kind = REPLICATION_KIND_LOGICAL;
204 622 : cmd->slotname = $2;
205 622 : cmd->temporary = $3;
206 622 : cmd->plugin = $5;
207 622 : cmd->options = $6;
208 622 : $$ = (Node *) cmd;
209 : }
210 : ;
211 :
212 : create_slot_options:
213 886 : '(' generic_option_list ')' { $$ = $2; }
214 4 : | create_slot_legacy_opt_list { $$ = $1; }
215 : ;
216 :
217 : create_slot_legacy_opt_list:
218 : create_slot_legacy_opt_list create_slot_legacy_opt
219 2 : { $$ = lappend($1, $2); }
220 : | /* EMPTY */
221 4 : { $$ = NIL; }
222 : ;
223 :
224 : create_slot_legacy_opt:
225 : K_EXPORT_SNAPSHOT
226 : {
227 0 : $$ = makeDefElem("snapshot",
228 0 : (Node *) makeString("export"), -1);
229 : }
230 : | K_NOEXPORT_SNAPSHOT
231 : {
232 0 : $$ = makeDefElem("snapshot",
233 0 : (Node *) makeString("nothing"), -1);
234 : }
235 : | K_USE_SNAPSHOT
236 : {
237 0 : $$ = makeDefElem("snapshot",
238 0 : (Node *) makeString("use"), -1);
239 : }
240 : | K_RESERVE_WAL
241 : {
242 2 : $$ = makeDefElem("reserve_wal",
243 2 : (Node *) makeBoolean(true), -1);
244 : }
245 : | K_TWO_PHASE
246 : {
247 0 : $$ = makeDefElem("two_phase",
248 0 : (Node *) makeBoolean(true), -1);
249 : }
250 : ;
251 :
252 : /* DROP_REPLICATION_SLOT slot */
253 : drop_replication_slot:
254 : K_DROP_REPLICATION_SLOT IDENT
255 : {
256 : DropReplicationSlotCmd *cmd;
257 6 : cmd = makeNode(DropReplicationSlotCmd);
258 6 : cmd->slotname = $2;
259 6 : cmd->wait = false;
260 6 : $$ = (Node *) cmd;
261 : }
262 : | K_DROP_REPLICATION_SLOT IDENT K_WAIT
263 : {
264 : DropReplicationSlotCmd *cmd;
265 490 : cmd = makeNode(DropReplicationSlotCmd);
266 490 : cmd->slotname = $2;
267 490 : cmd->wait = true;
268 490 : $$ = (Node *) cmd;
269 : }
270 : ;
271 :
272 : /* ALTER_REPLICATION_SLOT slot (options) */
273 : alter_replication_slot:
274 : K_ALTER_REPLICATION_SLOT IDENT '(' generic_option_list ')'
275 : {
276 : AlterReplicationSlotCmd *cmd;
277 12 : cmd = makeNode(AlterReplicationSlotCmd);
278 12 : cmd->slotname = $2;
279 12 : cmd->options = $4;
280 12 : $$ = (Node *) cmd;
281 : }
282 : ;
283 :
284 : /*
285 : * START_REPLICATION [SLOT slot] [PHYSICAL] %X/%X [TIMELINE %u]
286 : */
287 : start_replication:
288 : K_START_REPLICATION opt_slot opt_physical RECPTR opt_timeline
289 : {
290 : StartReplicationCmd *cmd;
291 :
292 510 : cmd = makeNode(StartReplicationCmd);
293 510 : cmd->kind = REPLICATION_KIND_PHYSICAL;
294 510 : cmd->slotname = $2;
295 510 : cmd->startpoint = $4;
296 510 : cmd->timeline = $5;
297 510 : $$ = (Node *) cmd;
298 : }
299 : ;
300 :
301 : /* START_REPLICATION SLOT slot LOGICAL %X/%X options */
302 : start_logical_replication:
303 : K_START_REPLICATION K_SLOT IDENT K_LOGICAL RECPTR plugin_options
304 : {
305 : StartReplicationCmd *cmd;
306 728 : cmd = makeNode(StartReplicationCmd);
307 728 : cmd->kind = REPLICATION_KIND_LOGICAL;
308 728 : cmd->slotname = $3;
309 728 : cmd->startpoint = $5;
310 728 : cmd->options = $6;
311 728 : $$ = (Node *) cmd;
312 : }
313 : ;
314 : /*
315 : * TIMELINE_HISTORY %u
316 : */
317 : timeline_history:
318 : K_TIMELINE_HISTORY UCONST
319 : {
320 : TimeLineHistoryCmd *cmd;
321 :
322 28 : if ($2 <= 0)
323 0 : ereport(ERROR,
324 : (errcode(ERRCODE_SYNTAX_ERROR),
325 : errmsg("invalid timeline %u", $2)));
326 :
327 28 : cmd = makeNode(TimeLineHistoryCmd);
328 28 : cmd->timeline = $2;
329 :
330 28 : $$ = (Node *) cmd;
331 : }
332 : ;
333 :
334 : /* UPLOAD_MANIFEST doesn't currently accept any arguments */
335 : upload_manifest:
336 : K_UPLOAD_MANIFEST
337 : {
338 22 : UploadManifestCmd *cmd = makeNode(UploadManifestCmd);
339 :
340 22 : $$ = (Node *) cmd;
341 : }
342 :
343 : opt_physical:
344 : K_PHYSICAL
345 : | /* EMPTY */
346 : ;
347 :
348 : opt_temporary:
349 258 : K_TEMPORARY { $$ = true; }
350 632 : | /* EMPTY */ { $$ = false; }
351 : ;
352 :
353 : opt_slot:
354 : K_SLOT IDENT
355 356 : { $$ = $2; }
356 : | /* EMPTY */
357 154 : { $$ = NULL; }
358 : ;
359 :
360 : opt_timeline:
361 : K_TIMELINE UCONST
362 : {
363 508 : if ($2 <= 0)
364 0 : ereport(ERROR,
365 : (errcode(ERRCODE_SYNTAX_ERROR),
366 : errmsg("invalid timeline %u", $2)));
367 508 : $$ = $2;
368 : }
369 2 : | /* EMPTY */ { $$ = 0; }
370 : ;
371 :
372 :
373 : plugin_options:
374 718 : '(' plugin_opt_list ')' { $$ = $2; }
375 10 : | /* EMPTY */ { $$ = NIL; }
376 : ;
377 :
378 : plugin_opt_list:
379 : plugin_opt_elem
380 : {
381 718 : $$ = list_make1($1);
382 : }
383 : | plugin_opt_list ',' plugin_opt_elem
384 : {
385 2106 : $$ = lappend($1, $3);
386 : }
387 : ;
388 :
389 : plugin_opt_elem:
390 : IDENT plugin_opt_arg
391 : {
392 2824 : $$ = makeDefElem($1, $2, -1);
393 : }
394 : ;
395 :
396 : plugin_opt_arg:
397 2824 : SCONST { $$ = (Node *) makeString($1); }
398 0 : | /* EMPTY */ { $$ = NULL; }
399 : ;
400 :
401 : generic_option_list:
402 : generic_option_list ',' generic_option
403 1964 : { $$ = lappend($1, $3); }
404 : | generic_option
405 1248 : { $$ = list_make1($1); }
406 : ;
407 :
408 : generic_option:
409 : ident_or_keyword
410 : {
411 752 : $$ = makeDefElem($1, NULL, -1);
412 : }
413 : | ident_or_keyword IDENT
414 : {
415 8 : $$ = makeDefElem($1, (Node *) makeString($2), -1);
416 : }
417 : | ident_or_keyword SCONST
418 : {
419 2114 : $$ = makeDefElem($1, (Node *) makeString($2), -1);
420 : }
421 : | ident_or_keyword UCONST
422 : {
423 338 : $$ = makeDefElem($1, (Node *) makeInteger($2), -1);
424 : }
425 : ;
426 :
427 : ident_or_keyword:
428 2608 : IDENT { $$ = $1; }
429 0 : | K_BASE_BACKUP { $$ = "base_backup"; }
430 0 : | K_IDENTIFY_SYSTEM { $$ = "identify_system"; }
431 0 : | K_SHOW { $$ = "show"; }
432 0 : | K_START_REPLICATION { $$ = "start_replication"; }
433 0 : | K_CREATE_REPLICATION_SLOT { $$ = "create_replication_slot"; }
434 0 : | K_DROP_REPLICATION_SLOT { $$ = "drop_replication_slot"; }
435 0 : | K_ALTER_REPLICATION_SLOT { $$ = "alter_replication_slot"; }
436 0 : | K_TIMELINE_HISTORY { $$ = "timeline_history"; }
437 334 : | K_WAIT { $$ = "wait"; }
438 0 : | K_TIMELINE { $$ = "timeline"; }
439 0 : | K_PHYSICAL { $$ = "physical"; }
440 0 : | K_LOGICAL { $$ = "logical"; }
441 0 : | K_SLOT { $$ = "slot"; }
442 264 : | K_RESERVE_WAL { $$ = "reserve_wal"; }
443 0 : | K_TEMPORARY { $$ = "temporary"; }
444 6 : | K_TWO_PHASE { $$ = "two_phase"; }
445 0 : | K_EXPORT_SNAPSHOT { $$ = "export_snapshot"; }
446 0 : | K_NOEXPORT_SNAPSHOT { $$ = "noexport_snapshot"; }
447 0 : | K_USE_SNAPSHOT { $$ = "use_snapshot"; }
448 0 : | K_UPLOAD_MANIFEST { $$ = "upload_manifest"; }
449 : ;
450 :
451 : %%
|