Age Owner TLA Line data Source code
1 : %top{
2 : /*-------------------------------------------------------------------------
3 : *
4 : * repl_scanner.l
5 : * a lexical scanner for the replication commands
6 : *
7 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
8 : * Portions Copyright (c) 1994, Regents of the University of California
9 : *
10 : *
11 : * IDENTIFICATION
12 : * src/backend/replication/repl_scanner.l
13 : *
14 : *-------------------------------------------------------------------------
15 : */
16 : #include "postgres.h"
17 :
18 : #include "nodes/parsenodes.h"
19 : #include "utils/builtins.h"
20 : #include "parser/scansup.h"
21 :
22 : /*
23 : * NB: include repl_gram.h only AFTER including walsender_private.h, because
24 : * walsender_private includes headers that define XLogRecPtr.
25 : */
26 : #include "replication/walsender_private.h"
27 : #include "repl_gram.h"
28 : }
29 :
30 : %{
31 : /* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
32 : #undef fprintf
33 : #define fprintf(file, fmt, msg) fprintf_to_ereport(fmt, msg)
34 :
35 : static void
3738 tgl 36 UIC 0 : fprintf_to_ereport(const char *fmt, const char *msg)
37 : {
38 0 : ereport(ERROR, (errmsg_internal("%s", msg)));
39 : }
40 :
41 : /* Handle to the buffer that the lexer uses internally */
42 : static YY_BUFFER_STATE scanbufhandle;
43 :
44 : /* Pushed-back token (we only handle one) */
45 : static int repl_pushed_back_token;
440 tgl 46 EUB :
47 : /* Work area for collecting literals */
4468 magnus 48 : static StringInfoData litbuf;
49 :
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);
54 :
55 : /* LCOV_EXCL_START */
56 :
57 : %}
58 :
59 : %option 8bit
60 : %option never-interactive
61 : %option nodefault
62 : %option noinput
63 : %option nounput
64 : %option noyywrap
65 : %option warn
66 : %option prefix="replication_yy"
67 :
68 : /*
69 : * Exclusive states:
70 : * <xd> delimited identifiers (double-quoted identifiers)
71 : * <xq> standard single-quoted strings
72 : */
73 : %x xd
74 : %x xq
75 :
76 : space [ \t\n\r\f]
77 :
78 : quote '
79 : quotestop {quote}
80 :
81 : /* Extended quote
82 : * xqdouble implements embedded quote, ''''
83 : */
84 : xqstart {quote}
85 : xqdouble {quote}{quote}
86 : xqinside [^']+
87 :
88 : /* Double quote
89 : * Allows embedded spaces and other special characters into identifiers.
90 : */
91 : dquote \"
92 : xdstart {dquote}
93 : xdstop {dquote}
94 : xddouble {dquote}{dquote}
95 : xdinside [^"]+
96 :
97 : digit [0-9]
98 : hexdigit [0-9A-Fa-f]
99 :
100 : ident_start [A-Za-z\200-\377_]
101 : ident_cont [A-Za-z\200-\377_0-9\$]
102 :
103 : identifier {ident_start}{ident_cont}*
104 :
105 : %%
106 :
107 : %{
108 : /* This code is inserted at the start of replication_yylex() */
109 :
110 : /* If we have a pushed-back token, return that. */
111 : if (repl_pushed_back_token)
440 tgl 112 GIC 19239 : {
113 : int result = repl_pushed_back_token;
114 2162 :
115 : repl_pushed_back_token = 0;
116 2162 : return result;
117 2162 : }
118 : %}
119 :
120 : BASE_BACKUP { return K_BASE_BACKUP; }
4468 magnus 121 143 : IDENTIFY_SYSTEM { return K_IDENTIFY_SYSTEM; }
531 michael 122 CBC 522 : READ_REPLICATION_SLOT { return K_READ_REPLICATION_SLOT; }
2266 rhaas 123 GIC 522 : SHOW { return K_SHOW; }
3769 heikki.linnakangas 124 CBC 6 : TIMELINE { return K_TIMELINE; }
4468 magnus 125 GIC 449 : START_REPLICATION { return K_START_REPLICATION; }
3355 rhaas 126 CBC 194 : CREATE_REPLICATION_SLOT { return K_CREATE_REPLICATION_SLOT; }
127 493 : DROP_REPLICATION_SLOT { return K_DROP_REPLICATION_SLOT; }
3769 heikki.linnakangas 128 GIC 344 : TIMELINE_HISTORY { return K_TIMELINE_HISTORY; }
3355 rhaas 129 192 : PHYSICAL { return K_PHYSICAL; }
2772 andres 130 13 : RESERVE_WAL { return K_RESERVE_WAL; }
3317 rhaas 131 CBC 97 : LOGICAL { return K_LOGICAL; }
3355 132 96 : SLOT { return K_SLOT; }
2313 peter_e 133 545 : TEMPORARY { return K_TEMPORARY; }
648 akapila 134 420 : TWO_PHASE { return K_TWO_PHASE; }
2217 peter_e 135 92 : EXPORT_SNAPSHOT { return K_EXPORT_SNAPSHOT; }
136 2 : NOEXPORT_SNAPSHOT { return K_NOEXPORT_SNAPSHOT; }
2208 peter_e 137 LBC 0 : USE_SNAPSHOT { return K_USE_SNAPSHOT; }
2046 alvherre 138 0 : WAIT { return K_WAIT; }
3355 rhaas 139 0 :
440 tgl 140 CBC 324 : {space}+ { /* do nothing */ }
4468 magnus 141 8269 :
3769 heikki.linnakangas 142 8269 : {digit}+ {
217 john.naylor 143 GNC 344 : replication_yylval.uintval = strtoul(yytext, NULL, 10);
3525 peter_e 144 CBC 344 : return UCONST;
3769 heikki.linnakangas 145 344 : }
3769 heikki.linnakangas 146 ECB :
4468 magnus 147 EUB : {hexdigit}+\/{hexdigit}+ {
3941 heikki.linnakangas 148 GBC 493 : uint32 hi,
3941 heikki.linnakangas 149 EUB : lo;
3941 heikki.linnakangas 150 ECB : if (sscanf(yytext, "%X/%X", &hi, &lo) != 2)
217 john.naylor 151 GNC 493 : replication_yyerror("invalid streaming start location");
217 john.naylor 152 UNC 0 : replication_yylval.recptr = ((uint64) hi) << 32 | lo;
4468 magnus 153 CBC 493 : return RECPTR;
154 493 : }
4468 magnus 155 ECB :
156 : {xqstart} {
4468 magnus 157 GIC 1774 : BEGIN(xq);
4468 magnus 158 CBC 1774 : startlit();
4468 magnus 159 GIC 1774 : }
160 :
4468 magnus 161 CBC 1774 : <xq>{quotestop} {
4468 magnus 162 GBC 1774 : yyless(1);
4468 magnus 163 CBC 1774 : BEGIN(INITIAL);
217 john.naylor 164 GNC 1774 : replication_yylval.str = litbufdup();
4468 magnus 165 GIC 1774 : return SCONST;
166 1774 : }
3355 rhaas 167 ECB :
168 : <xq>{xqdouble} {
4468 magnus 169 LBC 0 : addlitchar('\'');
4468 magnus 170 UIC 0 : }
3355 rhaas 171 ECB :
4468 magnus 172 LBC 0 : <xq>{xqinside} {
4468 magnus 173 CBC 1773 : addlit(yytext, yyleng);
174 1773 : }
4468 magnus 175 ECB :
3355 rhaas 176 CBC 1773 : {xdstart} {
3355 rhaas 177 GIC 819 : BEGIN(xd);
178 819 : startlit();
3355 rhaas 179 GBC 819 : }
3355 rhaas 180 EUB :
3355 rhaas 181 GIC 819 : <xd>{xdstop} {
331 peter 182 GBC 819 : int len;
331 peter 183 ECB :
3355 rhaas 184 : yyless(1);
3355 rhaas 185 GIC 819 : BEGIN(INITIAL);
217 john.naylor 186 GNC 819 : replication_yylval.str = litbufdup();
187 819 : len = strlen(replication_yylval.str);
188 819 : truncate_identifier(replication_yylval.str, len, true);
3355 rhaas 189 CBC 819 : return IDENT;
3355 rhaas 190 GIC 819 : }
3355 rhaas 191 ECB :
192 : <xd>{xdinside} {
3355 rhaas 193 GIC 819 : addlit(yytext, yyleng);
194 819 : }
3355 rhaas 195 ECB :
3355 rhaas 196 CBC 819 : {identifier} {
331 peter 197 4562 : int len = strlen(yytext);
3355 rhaas 198 4562 :
199 : replication_yylval.str = downcase_truncate_identifier(yytext, len, true);
200 4562 : return IDENT;
3355 rhaas 201 GIC 4562 : }
202 :
440 tgl 203 ECB : . {
440 tgl 204 CBC 2991 : /* Any char not recognized above is returned as itself */
205 : return yytext[0];
206 2991 : }
440 tgl 207 ECB :
208 : <xq,xd><<EOF>> { replication_yyerror("unterminated quoted string"); }
4468 magnus 209 UIC 0 :
4468 magnus 210 ECB :
4468 magnus 211 CBC 2162 : <<EOF>> {
212 : yyterminate();
4468 magnus 213 GIC 2162 : }
4468 magnus 214 ECB :
215 : %%
4468 magnus 216 LBC 0 :
217 : /* LCOV_EXCL_STOP */
218 :
4468 magnus 219 EUB : static void
220 : startlit(void)
4468 magnus 221 CBC 2593 : {
222 : initStringInfo(&litbuf);
223 2593 : }
4468 magnus 224 GIC 2593 :
225 : static char *
4468 magnus 226 EUB : litbufdup(void)
4468 magnus 227 GIC 2593 : {
228 : return litbuf.data;
229 2593 : }
230 :
4468 magnus 231 ECB : static void
232 : addlit(char *ytext, int yleng)
4468 magnus 233 CBC 2592 : {
4468 magnus 234 ECB : appendBinaryStringInfo(&litbuf, ytext, yleng);
4468 magnus 235 GIC 2592 : }
236 2592 :
4468 magnus 237 ECB : static void
238 : addlitchar(unsigned char ychar)
4468 magnus 239 LBC 0 : {
240 : appendStringInfoChar(&litbuf, ychar);
4468 magnus 241 UIC 0 : }
242 0 :
2936 tgl 243 ECB : void
244 : replication_yyerror(const char *message)
4468 magnus 245 LBC 0 : {
4177 peter_e 246 ECB : ereport(ERROR,
4468 magnus 247 UIC 0 : (errcode(ERRCODE_SYNTAX_ERROR),
248 : errmsg_internal("%s", message)));
4468 magnus 249 EUB : }
250 :
251 :
252 : void
253 : replication_scanner_init(const char *str)
4468 magnus 254 GIC 3914 : {
4468 magnus 255 EUB : Size slen = strlen(str);
4468 magnus 256 GIC 3914 : char *scanbuf;
4468 magnus 257 EUB :
258 : /*
259 : * Might be left over after ereport()
260 : */
261 : if (YY_CURRENT_BUFFER)
4468 magnus 262 GIC 3914 : yy_delete_buffer(YY_CURRENT_BUFFER);
4468 magnus 263 UIC 0 :
4468 magnus 264 ECB : /*
265 : * Make a scan buffer with special termination needed by flex.
266 : */
267 : scanbuf = (char *) palloc(slen + 2);
4468 magnus 268 GIC 3914 : memcpy(scanbuf, str, slen);
269 3914 : scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
270 3914 : scanbufhandle = yy_scan_buffer(scanbuf, slen + 2);
440 tgl 271 3914 :
440 tgl 272 ECB : /* Make sure we start in proper state */
440 tgl 273 EUB : BEGIN(INITIAL);
440 tgl 274 GIC 3914 : repl_pushed_back_token = 0;
4468 magnus 275 3914 : }
276 3914 :
277 : void
2794 andres 278 ECB : replication_scanner_finish(void)
4468 magnus 279 CBC 3914 : {
4468 magnus 280 ECB : yy_delete_buffer(scanbufhandle);
4468 magnus 281 CBC 3914 : scanbufhandle = NULL;
4468 magnus 282 GIC 3914 : }
440 tgl 283 3914 :
440 tgl 284 ECB : /*
285 : * Check to see if the first token of a command is a WalSender keyword.
286 : *
287 : * To keep repl_scanner.l minimal, we don't ask it to know every construct
288 : * that the core lexer knows. Therefore, we daren't lex more than the
289 : * first token of a general SQL command. That will usually look like an
290 : * IDENT token here, although some other cases are possible.
291 : */
292 : bool
293 : replication_scanner_is_replication_command(void)
440 tgl 294 GIC 3914 : {
295 : int first_token = replication_yylex();
296 3914 :
297 : switch (first_token)
298 3914 : {
299 : case K_IDENTIFY_SYSTEM:
300 2162 : case K_BASE_BACKUP:
301 : case K_START_REPLICATION:
302 : case K_CREATE_REPLICATION_SLOT:
303 : case K_DROP_REPLICATION_SLOT:
440 tgl 304 ECB : case K_READ_REPLICATION_SLOT:
305 : case K_TIMELINE_HISTORY:
306 : case K_SHOW:
307 : /* Yes; push back the first token so we can parse later. */
308 : repl_pushed_back_token = first_token;
440 tgl 309 GIC 2162 : return true;
440 tgl 310 CBC 2162 : default:
440 tgl 311 GIC 1752 : /* Nope; we don't bother to push back the token. */
312 : return false;
313 1752 : }
314 : }
|