Age Owner Branch data TLA 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 : : {
225 peter@eisentraut.org 104 :CBC 2804 : *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 : : {
5349 magnus@hagander.net 134 : 673 : $$ = (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 : : {
1412 michael@paquier.xyz 144 : 6 : ReadReplicationSlotCmd *n = makeNode(ReadReplicationSlotCmd);
145 : 6 : n->slotname = $2;
146 : 6 : $$ = (Node *) n;
147 : : }
148 : : ;
149 : :
150 : : /*
151 : : * SHOW setting
152 : : */
153 : : show:
154 : : K_SHOW var_name
155 : : {
3147 rhaas@postgresql.org 156 : 540 : VariableShowStmt *n = makeNode(VariableShowStmt);
157 : 540 : n->name = $2;
158 : 540 : $$ = (Node *) n;
159 : : }
160 : :
161 : 546 : var_name: IDENT { $$ = $1; }
162 : : | var_name '.' IDENT
3147 rhaas@postgresql.org 163 :UBC 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 : : {
1432 rhaas@postgresql.org 172 :CBC 186 : BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
173 : 186 : cmd->options = $3;
174 : 186 : $$ = (Node *) cmd;
175 : : }
176 : : | K_BASE_BACKUP
177 : : {
3179 peter_e@gmx.net 178 : 1 : BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
5349 magnus@hagander.net 179 : 1 : $$ = (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;
4236 rhaas@postgresql.org 188 : 134 : cmd = makeNode(CreateReplicationSlotCmd);
189 : 134 : cmd->kind = REPLICATION_KIND_PHYSICAL;
190 : 134 : cmd->slotname = $2;
3194 peter_e@gmx.net 191 : 134 : cmd->temporary = $3;
3098 192 : 134 : cmd->options = $5;
4236 rhaas@postgresql.org 193 : 134 : $$ = (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;
4198 199 : 309 : cmd = makeNode(CreateReplicationSlotCmd);
200 : 309 : cmd->kind = REPLICATION_KIND_LOGICAL;
201 : 309 : cmd->slotname = $2;
3194 peter_e@gmx.net 202 : 309 : cmd->temporary = $3;
203 : 309 : cmd->plugin = $5;
3098 204 : 309 : cmd->options = $6;
4198 rhaas@postgresql.org 205 : 309 : $$ = (Node *) cmd;
206 : : }
207 : : ;
208 : :
209 : : create_slot_options:
1432 210 : 441 : '(' generic_option_list ')' { $$ = $2; }
211 : 2 : | create_slot_legacy_opt_list { $$ = $1; }
212 : : ;
213 : :
214 : : create_slot_legacy_opt_list:
215 : : create_slot_legacy_opt_list create_slot_legacy_opt
3098 peter_e@gmx.net 216 : 1 : { $$ = lappend($1, $2); }
217 : : | /* EMPTY */
218 : 2 : { $$ = NIL; }
219 : : ;
220 : :
221 : : create_slot_legacy_opt:
222 : : K_EXPORT_SNAPSHOT
223 : : {
1432 rhaas@postgresql.org 224 :UBC 0 : $$ = makeDefElem("snapshot",
1212 peter@eisentraut.org 225 : 0 : (Node *) makeString("export"), -1);
226 : : }
227 : : | K_NOEXPORT_SNAPSHOT
228 : : {
1432 rhaas@postgresql.org 229 : 0 : $$ = makeDefElem("snapshot",
1212 peter@eisentraut.org 230 : 0 : (Node *) makeString("nothing"), -1);
231 : : }
232 : : | K_USE_SNAPSHOT
233 : : {
1432 rhaas@postgresql.org 234 : 0 : $$ = makeDefElem("snapshot",
1212 peter@eisentraut.org 235 : 0 : (Node *) makeString("use"), -1);
236 : : }
237 : : | K_RESERVE_WAL
238 : : {
3098 peter_e@gmx.net 239 :CBC 1 : $$ = makeDefElem("reserve_wal",
1212 peter@eisentraut.org 240 : 1 : (Node *) makeBoolean(true), -1);
241 : : }
242 : : | K_TWO_PHASE
243 : : {
1529 akapila@postgresql.o 244 :UBC 0 : $$ = makeDefElem("two_phase",
1212 peter@eisentraut.org 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;
4236 rhaas@postgresql.org 254 :CBC 5 : cmd = makeNode(DropReplicationSlotCmd);
255 : 5 : cmd->slotname = $2;
2927 alvherre@alvh.no-ip. 256 : 5 : cmd->wait = false;
257 : 5 : $$ = (Node *) cmd;
258 : : }
259 : : | K_DROP_REPLICATION_SLOT IDENT K_WAIT
260 : : {
261 : : DropReplicationSlotCmd *cmd;
262 : 266 : cmd = makeNode(DropReplicationSlotCmd);
263 : 266 : cmd->slotname = $2;
264 : 266 : cmd->wait = true;
4236 rhaas@postgresql.org 265 : 266 : $$ = (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;
586 akapila@postgresql.o 274 : 6 : cmd = makeNode(AlterReplicationSlotCmd);
275 : 6 : cmd->slotname = $2;
276 : 6 : cmd->options = $4;
277 : 6 : $$ = (Node *) cmd;
278 : : }
279 : : ;
280 : :
281 : : /*
282 : : * START_REPLICATION [SLOT slot] [PHYSICAL] %X/%08X [TIMELINE %u]
283 : : */
284 : : start_replication:
285 : : K_START_REPLICATION opt_slot opt_physical RECPTR opt_timeline
286 : : {
287 : : StartReplicationCmd *cmd;
288 : :
5349 magnus@hagander.net 289 : 254 : cmd = makeNode(StartReplicationCmd);
4236 rhaas@postgresql.org 290 : 254 : cmd->kind = REPLICATION_KIND_PHYSICAL;
291 : 254 : cmd->slotname = $2;
292 : 254 : cmd->startpoint = $4;
293 : 254 : cmd->timeline = $5;
4650 heikki.linnakangas@i 294 : 254 : $$ = (Node *) cmd;
295 : : }
296 : : ;
297 : :
298 : : /* START_REPLICATION SLOT slot LOGICAL %X/%08X options */
299 : : start_logical_replication:
300 : : K_START_REPLICATION K_SLOT IDENT K_LOGICAL RECPTR plugin_options
301 : : {
302 : : StartReplicationCmd *cmd;
4198 rhaas@postgresql.org 303 : 399 : cmd = makeNode(StartReplicationCmd);
3812 heikki.linnakangas@i 304 : 399 : cmd->kind = REPLICATION_KIND_LOGICAL;
4198 rhaas@postgresql.org 305 : 399 : cmd->slotname = $3;
306 : 399 : cmd->startpoint = $5;
307 : 399 : cmd->options = $6;
308 : 399 : $$ = (Node *) cmd;
309 : : }
310 : : ;
311 : : /*
312 : : * TIMELINE_HISTORY %u
313 : : */
314 : : timeline_history:
315 : : K_TIMELINE_HISTORY UCONST
316 : : {
317 : : TimeLineHistoryCmd *cmd;
318 : :
4650 heikki.linnakangas@i 319 [ - + ]: 13 : if ($2 <= 0)
4650 heikki.linnakangas@i 320 [ # # ]:UBC 0 : ereport(ERROR,
321 : : (errcode(ERRCODE_SYNTAX_ERROR),
322 : : errmsg("invalid timeline %u", $2)));
323 : :
4650 heikki.linnakangas@i 324 :CBC 13 : cmd = makeNode(TimeLineHistoryCmd);
325 : 13 : cmd->timeline = $2;
326 : :
5349 magnus@hagander.net 327 : 13 : $$ = (Node *) cmd;
328 : : }
329 : : ;
330 : :
331 : : /* UPLOAD_MANIFEST doesn't currently accept any arguments */
332 : : upload_manifest:
333 : : K_UPLOAD_MANIFEST
334 : : {
626 rhaas@postgresql.org 335 : 12 : UploadManifestCmd *cmd = makeNode(UploadManifestCmd);
336 : :
337 : 12 : $$ = (Node *) cmd;
338 : : }
339 : :
340 : : opt_physical:
341 : : K_PHYSICAL
342 : : | /* EMPTY */
343 : : ;
344 : :
345 : : opt_temporary:
3194 peter_e@gmx.net 346 : 129 : K_TEMPORARY { $$ = true; }
347 : 314 : | /* EMPTY */ { $$ = false; }
348 : : ;
349 : :
350 : : opt_slot:
351 : : K_SLOT IDENT
4234 tgl@sss.pgh.pa.us 352 : 172 : { $$ = $2; }
353 : : | /* EMPTY */
354 : 82 : { $$ = NULL; }
355 : : ;
356 : :
357 : : opt_timeline:
358 : : K_TIMELINE UCONST
359 : : {
4198 rhaas@postgresql.org 360 [ - + ]: 253 : if ($2 <= 0)
4198 rhaas@postgresql.org 361 [ # # ]:UBC 0 : ereport(ERROR,
362 : : (errcode(ERRCODE_SYNTAX_ERROR),
363 : : errmsg("invalid timeline %u", $2)));
4198 rhaas@postgresql.org 364 :CBC 253 : $$ = $2;
365 : : }
366 : 1 : | /* EMPTY */ { $$ = 0; }
367 : : ;
368 : :
369 : :
370 : : plugin_options:
371 : 394 : '(' plugin_opt_list ')' { $$ = $2; }
372 : 5 : | /* EMPTY */ { $$ = NIL; }
373 : : ;
374 : :
375 : : plugin_opt_list:
376 : : plugin_opt_elem
377 : : {
378 : 394 : $$ = list_make1($1);
379 : : }
380 : : | plugin_opt_list ',' plugin_opt_elem
381 : : {
382 : 1187 : $$ = lappend($1, $3);
383 : : }
384 : : ;
385 : :
386 : : plugin_opt_elem:
387 : : IDENT plugin_opt_arg
388 : : {
3287 peter_e@gmx.net 389 : 1581 : $$ = makeDefElem($1, $2, -1);
390 : : }
391 : : ;
392 : :
393 : : plugin_opt_arg:
4198 rhaas@postgresql.org 394 : 1581 : SCONST { $$ = (Node *) makeString($1); }
4198 rhaas@postgresql.org 395 :UBC 0 : | /* EMPTY */ { $$ = NULL; }
396 : : ;
397 : :
398 : : generic_option_list:
399 : : generic_option_list ',' generic_option
1432 rhaas@postgresql.org 400 :CBC 1061 : { $$ = lappend($1, $3); }
401 : : | generic_option
402 : 633 : { $$ = list_make1($1); }
403 : : ;
404 : :
405 : : generic_option:
406 : : ident_or_keyword
407 : : {
408 : 403 : $$ = makeDefElem($1, NULL, -1);
409 : : }
410 : : | ident_or_keyword IDENT
411 : : {
412 : 6 : $$ = makeDefElem($1, (Node *) makeString($2), -1);
413 : : }
414 : : | ident_or_keyword SCONST
415 : : {
416 : 1107 : $$ = makeDefElem($1, (Node *) makeString($2), -1);
417 : : }
418 : : | ident_or_keyword UCONST
419 : : {
420 : 178 : $$ = makeDefElem($1, (Node *) makeInteger($2), -1);
421 : : }
422 : : ;
423 : :
424 : : ident_or_keyword:
425 : 1384 : IDENT { $$ = $1; }
1432 rhaas@postgresql.org 426 :UBC 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"; }
586 akapila@postgresql.o 432 : 0 : | K_ALTER_REPLICATION_SLOT { $$ = "alter_replication_slot"; }
1432 rhaas@postgresql.org 433 : 0 : | K_TIMELINE_HISTORY { $$ = "timeline_history"; }
1432 rhaas@postgresql.org 434 :CBC 175 : | K_WAIT { $$ = "wait"; }
1432 rhaas@postgresql.org 435 :UBC 0 : | K_TIMELINE { $$ = "timeline"; }
436 : 0 : | K_PHYSICAL { $$ = "physical"; }
437 : 0 : | K_LOGICAL { $$ = "logical"; }
438 : 0 : | K_SLOT { $$ = "slot"; }
1432 rhaas@postgresql.org 439 :CBC 132 : | K_RESERVE_WAL { $$ = "reserve_wal"; }
1432 rhaas@postgresql.org 440 :UBC 0 : | K_TEMPORARY { $$ = "temporary"; }
1432 rhaas@postgresql.org 441 :CBC 3 : | K_TWO_PHASE { $$ = "two_phase"; }
1432 rhaas@postgresql.org 442 :UBC 0 : | K_EXPORT_SNAPSHOT { $$ = "export_snapshot"; }
443 : 0 : | K_NOEXPORT_SNAPSHOT { $$ = "noexport_snapshot"; }
444 : 0 : | K_USE_SNAPSHOT { $$ = "use_snapshot"; }
626 445 : 0 : | K_UPLOAD_MANIFEST { $$ = "upload_manifest"; }
446 : : ;
447 : :
448 : : %%
|