2 /*-------------------------------------------------------------------------
5 * a lexical scanner for the replication commands
7 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * src/backend/replication/repl_scanner.l
14 *-------------------------------------------------------------------------
18 #include "nodes/parsenodes.h"
19 #include "utils/builtins.h"
20 #include "parser/scansup.h"
23 * NB: include repl_gram.h only AFTER including walsender_private.h, because
24 * walsender_private includes headers that define XLogRecPtr.
26 #include "replication/walsender_private.h"
27 #include "repl_gram.h"
31 /* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
33 #define fprintf(file, fmt, msg) fprintf_to_ereport(fmt, msg)
36 fprintf_to_ereport(const char *fmt, const char *msg)
38 ereport(ERROR, (errmsg_internal("%s", msg)));
41 /* Handle to the buffer that the lexer uses internally */
42 static YY_BUFFER_STATE scanbufhandle;
44 /* Pushed-back token (we only handle one) */
45 static int repl_pushed_back_token;
47 /* Work area for collecting literals */
48 static StringInfoData litbuf;
50 static void startlit(void);
51 static char *litbufdup(void);
52 static void addlit(char *ytext, int yleng);
53 static void addlitchar(unsigned char ychar);
60 %option never-interactive
66 %option prefix="replication_yy"
70 * <xd> delimited identifiers (double-quoted identifiers)
71 * <xq> standard single-quoted strings
82 * xqdouble implements embedded quote, ''''
85 xqdouble {quote}{quote}
89 * Allows embedded spaces and other special characters into identifiers.
94 xddouble {dquote}{dquote}
100 ident_start [A-Za-z\200-\377_]
101 ident_cont [A-Za-z\200-\377_0-9\$]
103 identifier {ident_start}{ident_cont}*
108 /* This code is inserted at the start of replication_yylex() */
110 /* If we have a pushed-back token, return that. */
111 if (repl_pushed_back_token)
113 int result = repl_pushed_back_token;
115 repl_pushed_back_token = 0;
120 BASE_BACKUP { return K_BASE_BACKUP; }
121 IDENTIFY_SYSTEM { return K_IDENTIFY_SYSTEM; }
122 READ_REPLICATION_SLOT { return K_READ_REPLICATION_SLOT; }
123 SHOW { return K_SHOW; }
124 TIMELINE { return K_TIMELINE; }
125 START_REPLICATION { return K_START_REPLICATION; }
126 CREATE_REPLICATION_SLOT { return K_CREATE_REPLICATION_SLOT; }
127 DROP_REPLICATION_SLOT { return K_DROP_REPLICATION_SLOT; }
128 ALTER_REPLICATION_SLOT { return K_ALTER_REPLICATION_SLOT; }
129 TIMELINE_HISTORY { return K_TIMELINE_HISTORY; }
130 PHYSICAL { return K_PHYSICAL; }
131 RESERVE_WAL { return K_RESERVE_WAL; }
132 LOGICAL { return K_LOGICAL; }
133 SLOT { return K_SLOT; }
134 TEMPORARY { return K_TEMPORARY; }
135 TWO_PHASE { return K_TWO_PHASE; }
136 EXPORT_SNAPSHOT { return K_EXPORT_SNAPSHOT; }
137 NOEXPORT_SNAPSHOT { return K_NOEXPORT_SNAPSHOT; }
138 USE_SNAPSHOT { return K_USE_SNAPSHOT; }
139 WAIT { return K_WAIT; }
140 UPLOAD_MANIFEST { return K_UPLOAD_MANIFEST; }
142 {space}+ { /* do nothing */ }
145 replication_yylval.uintval = strtoul(yytext, NULL, 10);
149 {hexdigit}+\/{hexdigit}+ {
152 if (sscanf(yytext, "%X/%X", &hi, &lo) != 2)
153 replication_yyerror("invalid streaming start location");
154 replication_yylval.recptr = ((uint64) hi) << 32 | lo;
166 replication_yylval.str = litbufdup();
175 addlit(yytext, yyleng);
188 replication_yylval.str = litbufdup();
189 len = strlen(replication_yylval.str);
190 truncate_identifier(replication_yylval.str, len, true);
195 addlit(yytext, yyleng);
199 int len = strlen(yytext);
201 replication_yylval.str = downcase_truncate_identifier(yytext, len, true);
206 /* Any char not recognized above is returned as itself */
210 <xq,xd><<EOF>> { replication_yyerror("unterminated quoted string"); }
224 initStringInfo(&litbuf);
234 addlit(char *ytext, int yleng)
236 appendBinaryStringInfo(&litbuf, ytext, yleng);
240 addlitchar(unsigned char ychar)
242 appendStringInfoChar(&litbuf, ychar);
246 replication_yyerror(const char *message)
249 (errcode(ERRCODE_SYNTAX_ERROR),
250 errmsg_internal("%s", message)));
255 replication_scanner_init(const char *str)
257 Size slen = strlen(str);
261 * Might be left over after ereport()
263 if (YY_CURRENT_BUFFER)
264 yy_delete_buffer(YY_CURRENT_BUFFER);
267 * Make a scan buffer with special termination needed by flex.
269 scanbuf = (char *) palloc(slen + 2);
270 memcpy(scanbuf, str, slen);
271 scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
272 scanbufhandle = yy_scan_buffer(scanbuf, slen + 2);
274 /* Make sure we start in proper state */
276 repl_pushed_back_token = 0;
280 replication_scanner_finish(void)
282 yy_delete_buffer(scanbufhandle);
283 scanbufhandle = NULL;
287 * Check to see if the first token of a command is a WalSender keyword.
289 * To keep repl_scanner.l minimal, we don't ask it to know every construct
290 * that the core lexer knows. Therefore, we daren't lex more than the
291 * first token of a general SQL command. That will usually look like an
292 * IDENT token here, although some other cases are possible.
295 replication_scanner_is_replication_command(void)
297 int first_token = replication_yylex();
301 case K_IDENTIFY_SYSTEM:
303 case K_START_REPLICATION:
304 case K_CREATE_REPLICATION_SLOT:
305 case K_DROP_REPLICATION_SLOT:
306 case K_ALTER_REPLICATION_SLOT:
307 case K_READ_REPLICATION_SLOT:
308 case K_TIMELINE_HISTORY:
309 case K_UPLOAD_MANIFEST:
311 /* Yes; push back the first token so we can parse later. */
312 repl_pushed_back_token = first_token;
315 /* Nope; we don't bother to push back the token. */