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