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