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