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