Branch data 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-2026, 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
36 : 0 : fprintf_to_ereport(const char *fmt, const char *msg)
37 : : {
38 [ # # ]: 0 : ereport(ERROR, (errmsg_internal("%s", msg)));
39 : : }
40 : :
41 : : struct replication_yy_extra_type
42 : : {
43 : : /* Pushed-back token (we only handle one) */
44 : : int repl_pushed_back_token;
45 : :
46 : : /* Work area for collecting literals */
47 : : StringInfoData litbuf;
48 : : };
49 : :
50 : : static void startlit(yyscan_t yyscanner);
51 : : static char *litbufdup(yyscan_t yyscanner);
52 : : static void addlit(char *ytext, int yleng, yyscan_t yyscanner);
53 : : static void addlitchar(unsigned char ychar, yyscan_t yyscanner);
54 : :
55 : : /* LCOV_EXCL_START */
56 : :
57 : : %}
58 : :
59 : : %option reentrant
60 : : %option bison-bridge
61 : : %option 8bit
62 : : %option never-interactive
63 : : %option nodefault
64 : : %option noinput
65 : : %option nounput
66 : : %option noyywrap
67 : : %option noyyalloc
68 : : %option noyyrealloc
69 : : %option noyyfree
70 : : %option warn
71 : : %option prefix="replication_yy"
72 : : %option extra-type="struct replication_yy_extra_type *"
73 : :
74 : : /*
75 : : * Exclusive states:
76 : : * <xd> delimited identifiers (double-quoted identifiers)
77 : : * <xq> standard single-quoted strings
78 : : */
79 : : %x xd
80 : : %x xq
81 : :
82 : : space [ \t\n\r\f\v]
83 : :
84 : : quote '
85 : : quotestop {quote}
86 : :
87 : : /* Extended quote
88 : : * xqdouble implements embedded quote, ''''
89 : : */
90 : : xqstart {quote}
91 : : xqdouble {quote}{quote}
92 : : xqinside [^']+
93 : :
94 : : /* Double quote
95 : : * Allows embedded spaces and other special characters into identifiers.
96 : : */
97 : : dquote \"
98 : : xdstart {dquote}
99 : : xdstop {dquote}
100 : : xddouble {dquote}{dquote}
101 : : xdinside [^"]+
102 : :
103 : : digit [0-9]
104 : : hexdigit [0-9A-Fa-f]
105 : :
106 : : ident_start [A-Za-z\200-\377_]
107 : : ident_cont [A-Za-z\200-\377_0-9\$]
108 : :
109 : : identifier {ident_start}{ident_cont}*
110 : :
111 : : %%
112 : :
113 : : %{
114 : : /* This code is inserted at the start of replication_yylex() */
115 : :
116 : : /* If we have a pushed-back token, return that. */
117 : : if (yyextra->repl_pushed_back_token)
118 [ + + ]: 29686 : {
119 : : int result = yyextra->repl_pushed_back_token;
120 : 3231 :
121 : : yyextra->repl_pushed_back_token = 0;
122 : 3231 : return result;
123 : 3231 : }
124 : : %}
125 : :
126 : : BASE_BACKUP { return K_BASE_BACKUP; }
127 : 197 : IDENTIFY_SYSTEM { return K_IDENTIFY_SYSTEM; }
128 : 800 : READ_REPLICATION_SLOT { return K_READ_REPLICATION_SLOT; }
129 : 800 : SHOW { return K_SHOW; }
130 : 6 : TIMELINE { return K_TIMELINE; }
131 : 626 : START_REPLICATION { return K_START_REPLICATION; }
132 : 301 : CREATE_REPLICATION_SLOT { return K_CREATE_REPLICATION_SLOT; }
133 : 757 : DROP_REPLICATION_SLOT { return K_DROP_REPLICATION_SLOT; }
134 : 517 : ALTER_REPLICATION_SLOT { return K_ALTER_REPLICATION_SLOT; }
135 : 293 : TIMELINE_HISTORY { return K_TIMELINE_HISTORY; }
136 : 7 : PHYSICAL { return K_PHYSICAL; }
137 : 16 : RESERVE_WAL { return K_RESERVE_WAL; }
138 : 153 : LOGICAL { return K_LOGICAL; }
139 : 152 : SLOT { return K_SLOT; }
140 : 819 : TEMPORARY { return K_TEMPORARY; }
141 : 658 : TWO_PHASE { return K_TWO_PHASE; }
142 : 147 : EXPORT_SNAPSHOT { return K_EXPORT_SNAPSHOT; }
143 : 3 : NOEXPORT_SNAPSHOT { return K_NOEXPORT_SNAPSHOT; }
144 : 0 : USE_SNAPSHOT { return K_USE_SNAPSHOT; }
145 : 0 : WAIT { return K_WAIT; }
146 : 0 : UPLOAD_MANIFEST { return K_UPLOAD_MANIFEST; }
147 : 475 :
148 : 12 : {space}+ { /* do nothing */ }
149 : 13036 :
150 : 13036 : {digit}+ {
151 : 506 : yylval->uintval = strtoul(yytext, NULL, 10);
152 : 506 : return UCONST;
153 : 506 : }
154 : :
155 : : {hexdigit}+\/{hexdigit}+ {
156 : 757 : uint32 hi,
157 : : lo;
158 : : if (sscanf(yytext, "%X/%08X", &hi, &lo) != 2)
159 [ - + ]: 757 : replication_yyerror(NULL, yyscanner, "invalid streaming start location");
160 : 0 : yylval->recptr = ((uint64) hi) << 32 | lo;
161 : 757 : return RECPTR;
162 : 757 : }
163 : :
164 : : {xqstart} {
165 : 2960 : BEGIN(xq);
166 : 2960 : startlit(yyscanner);
167 : 2960 : }
168 : :
169 : 2960 : <xq>{quotestop} {
170 : 2960 : yyless(1);
171 : 2960 : BEGIN(INITIAL);
172 : 2960 : yylval->str = litbufdup(yyscanner);
173 : 2960 : return SCONST;
174 : 2960 : }
175 : :
176 : : <xq>{xqdouble} {
177 : 0 : addlitchar('\'', yyscanner);
178 : 0 : }
179 : :
180 : 0 : <xq>{xqinside} {
181 : 2959 : addlit(yytext, yyleng, yyscanner);
182 : 2959 : }
183 : :
184 : 2959 : {xdstart} {
185 : 1534 : BEGIN(xd);
186 : 1534 : startlit(yyscanner);
187 : 1534 : }
188 : :
189 : 1534 : <xd>{xdstop} {
190 : 1534 : int len;
191 : :
192 : : yyless(1);
193 : 1534 : BEGIN(INITIAL);
194 : 1534 : yylval->str = litbufdup(yyscanner);
195 : 1534 : len = strlen(yylval->str);
196 : 1534 : truncate_identifier(yylval->str, len, true);
197 : 1534 : return IDENT;
198 : 1534 : }
199 : :
200 : : <xd>{xddouble} {
201 : 0 : addlitchar('"', yyscanner);
202 : 0 : }
203 : :
204 : 0 : <xd>{xdinside} {
205 : 1534 : addlit(yytext, yyleng, yyscanner);
206 : 1534 : }
207 : :
208 : 1534 : {identifier} {
209 : 6761 : int len = strlen(yytext);
210 : 6761 :
211 : : yylval->str = downcase_truncate_identifier(yytext, len, true);
212 : 6761 : return IDENT;
213 : 6761 : }
214 : :
215 : : . {
216 : 4767 : /* Any char not recognized above is returned as itself */
217 : : return yytext[0];
218 : 4767 : }
219 : :
220 : : <xq,xd><<EOF>> { replication_yyerror(NULL, yyscanner, "unterminated quoted string"); }
221 : 0 :
222 : :
223 : 3231 : <<EOF>> {
224 : : yyterminate();
225 : 3231 : }
226 : :
227 : : %%
228 : 0 :
229 : : /* LCOV_EXCL_STOP */
230 : :
231 : : /* see scan.l */
232 : : #undef yyextra
233 : : #define yyextra (((struct yyguts_t *) yyscanner)->yyextra_r)
234 : :
235 : : static void
236 : : startlit(yyscan_t yyscanner)
237 : 4494 : {
238 : : initStringInfo(&yyextra->litbuf);
239 : 4494 : }
240 : 4494 :
241 : : static char *
242 : : litbufdup(yyscan_t yyscanner)
243 : 4494 : {
244 : : return yyextra->litbuf.data;
245 : 4494 : }
246 : :
247 : : static void
248 : : addlit(char *ytext, int yleng, yyscan_t yyscanner)
249 : 4493 : {
250 : : appendBinaryStringInfo(&yyextra->litbuf, ytext, yleng);
251 : 4493 : }
252 : 4493 :
253 : : static void
254 : : addlitchar(unsigned char ychar, yyscan_t yyscanner)
255 : 0 : {
256 : : appendStringInfoChar(&yyextra->litbuf, ychar);
257 : 0 : }
258 : 0 :
259 : : /*
260 : : * (The first argument is enforced by Bison to match the first argument of
261 : : * yyparse(), but it is not used here.)
262 : : */
263 : : void
264 : : replication_yyerror(Node **replication_parse_result_p, yyscan_t yyscanner, const char *message)
265 : 0 : {
266 : : ereport(ERROR,
267 [ # # ]: 0 : (errcode(ERRCODE_SYNTAX_ERROR),
268 : : errmsg_internal("%s", message)));
269 : : }
270 : :
271 : : void
272 : : replication_scanner_init(const char *str, yyscan_t *yyscannerp)
273 : 5808 : {
274 : : yyscan_t yyscanner;
275 : : struct replication_yy_extra_type *yyext = palloc0_object(struct replication_yy_extra_type);
276 : 5808 :
277 : : if (yylex_init(yyscannerp) != 0)
278 [ - + ]: 5808 : elog(ERROR, "yylex_init() failed: %m");
279 [ # # ]: 0 :
280 : : yyscanner = *yyscannerp;
281 : 5808 :
282 : : yyset_extra(yyext, yyscanner);
283 : 5808 :
284 : : yy_scan_string(str, yyscanner);
285 : 5808 : }
286 : 5808 :
287 : : void
288 : : replication_scanner_finish(yyscan_t yyscanner)
289 : 5808 : {
290 : : pfree(yyextra);
291 : 5808 : yylex_destroy(yyscanner);
292 : 5808 : }
293 : 5808 :
294 : : /*
295 : : * Check to see if the first token of a command is a WalSender keyword.
296 : : *
297 : : * To keep repl_scanner.l minimal, we don't ask it to know every construct
298 : : * that the core lexer knows. Therefore, we daren't lex more than the
299 : : * first token of a general SQL command. That will usually look like an
300 : : * IDENT token here, although some other cases are possible.
301 : : */
302 : : bool
303 : : replication_scanner_is_replication_command(yyscan_t yyscanner)
304 : 5808 : {
305 : : YYSTYPE dummy;
306 : : int first_token = replication_yylex(&dummy, yyscanner);
307 : 5808 :
308 : : switch (first_token)
309 [ + + ]: 5808 : {
310 : : case K_IDENTIFY_SYSTEM:
311 : 3231 : case K_BASE_BACKUP:
312 : : case K_START_REPLICATION:
313 : : case K_CREATE_REPLICATION_SLOT:
314 : : case K_DROP_REPLICATION_SLOT:
315 : : case K_ALTER_REPLICATION_SLOT:
316 : : case K_READ_REPLICATION_SLOT:
317 : : case K_TIMELINE_HISTORY:
318 : : case K_UPLOAD_MANIFEST:
319 : : case K_SHOW:
320 : : /* Yes; push back the first token so we can parse later. */
321 : : yyextra->repl_pushed_back_token = first_token;
322 : 3231 : return true;
323 : 3231 : default:
324 : 2577 : /* Nope; we don't bother to push back the token. */
325 : : return false;
326 : 2577 : }
327 : : }
328 : :
329 : : /*
330 : : * Interface functions to make flex use palloc() instead of malloc().
331 : : * It'd be better to make these static, but flex insists otherwise.
332 : : */
333 : :
334 : : void *
335 : : yyalloc(yy_size_t size, yyscan_t yyscanner)
336 : 23232 : {
337 : : return palloc(size);
338 : 23232 : }
339 : :
340 : : void *
341 : : yyrealloc(void *ptr, yy_size_t size, yyscan_t yyscanner)
342 : 0 : {
343 : : if (ptr)
344 [ # # ]: 0 : return repalloc(ptr, size);
345 : 0 : else
346 : : return palloc(size);
347 : 0 : }
348 : :
349 : : void
350 : : yyfree(void *ptr, yyscan_t yyscanner)
351 : 29040 : {
352 : : if (ptr)
353 [ + + ]: 29040 : pfree(ptr);
354 : 23232 : }
355 : 29040 : /* END: function "replication_yyfree" */
|