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