Age Owner Branch data 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-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
4916 tgl@sss.pgh.pa.us 36 :UBC 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)
1618 tgl@sss.pgh.pa.us 118 [ + + ]:CBC 29818 : {
119 : : int result = yyextra->repl_pushed_back_token;
120 : 3256 :
121 : : yyextra->repl_pushed_back_token = 0;
122 : 3256 : return result;
123 : 3256 : }
124 : : %}
125 : :
126 : : BASE_BACKUP { return K_BASE_BACKUP; }
5646 magnus@hagander.net 127 : 200 : IDENTIFY_SYSTEM { return K_IDENTIFY_SYSTEM; }
1709 michael@paquier.xyz 128 : 808 : READ_REPLICATION_SLOT { return K_READ_REPLICATION_SLOT; }
3444 rhaas@postgresql.org 129 : 808 : SHOW { return K_SHOW; }
4947 heikki.linnakangas@i 130 : 6 : TIMELINE { return K_TIMELINE; }
5646 magnus@hagander.net 131 : 633 : START_REPLICATION { return K_START_REPLICATION; }
4533 rhaas@postgresql.org 132 : 306 : CREATE_REPLICATION_SLOT { return K_CREATE_REPLICATION_SLOT; }
133 : 762 : DROP_REPLICATION_SLOT { return K_DROP_REPLICATION_SLOT; }
883 akapila@postgresql.o 134 : 516 : ALTER_REPLICATION_SLOT { return K_ALTER_REPLICATION_SLOT; }
4947 heikki.linnakangas@i 135 : 295 : TIMELINE_HISTORY { return K_TIMELINE_HISTORY; }
4533 rhaas@postgresql.org 136 : 7 : PHYSICAL { return K_PHYSICAL; }
3950 andres@anarazel.de 137 : 16 : RESERVE_WAL { return K_RESERVE_WAL; }
4495 rhaas@postgresql.org 138 : 154 : LOGICAL { return K_LOGICAL; }
4533 139 : 153 : SLOT { return K_SLOT; }
3491 peter_e@gmx.net 140 : 817 : TEMPORARY { return K_TEMPORARY; }
1826 akapila@postgresql.o 141 : 659 : TWO_PHASE { return K_TWO_PHASE; }
3395 peter_e@gmx.net 142 : 148 : EXPORT_SNAPSHOT { return K_EXPORT_SNAPSHOT; }
143 : 3 : NOEXPORT_SNAPSHOT { return K_NOEXPORT_SNAPSHOT; }
3386 peter_e@gmx.net 144 :UBC 0 : USE_SNAPSHOT { return K_USE_SNAPSHOT; }
3224 alvherre@alvh.no-ip. 145 : 0 : WAIT { return K_WAIT; }
923 rhaas@postgresql.org 146 : 0 : UPLOAD_MANIFEST { return K_UPLOAD_MANIFEST; }
4533 rhaas@postgresql.org 147 :CBC 477 :
1618 tgl@sss.pgh.pa.us 148 : 13 : {space}+ { /* do nothing */ }
5646 magnus@hagander.net 149 : 13084 :
4947 heikki.linnakangas@i 150 : 13084 : {digit}+ {
575 peter@eisentraut.org 151 : 513 : yylval->uintval = strtoul(yytext, NULL, 10);
4703 peter_e@gmx.net 152 : 513 : return UCONST;
4947 heikki.linnakangas@i 153 : 513 : }
154 : :
155 : : {hexdigit}+\/{hexdigit}+ {
5119 156 : 762 : uint32 hi,
157 : : lo;
158 : : if (sscanf(yytext, "%X/%08X", &hi, &lo) != 2)
522 peter@eisentraut.org 159 [ - + ]: 762 : replication_yyerror(NULL, yyscanner, "invalid streaming start location");
575 peter@eisentraut.org 160 :UBC 0 : yylval->recptr = ((uint64) hi) << 32 | lo;
5646 magnus@hagander.net 161 :CBC 762 : return RECPTR;
162 : 762 : }
163 : :
164 : : {xqstart} {
165 : 2966 : BEGIN(xq);
575 peter@eisentraut.org 166 : 2966 : startlit(yyscanner);
5646 magnus@hagander.net 167 : 2966 : }
168 : :
169 : 2966 : <xq>{quotestop} {
170 : 2966 : yyless(1);
171 : 2966 : BEGIN(INITIAL);
575 peter@eisentraut.org 172 : 2966 : yylval->str = litbufdup(yyscanner);
5646 magnus@hagander.net 173 : 2966 : return SCONST;
174 : 2966 : }
175 : :
176 : : <xq>{xqdouble} {
575 peter@eisentraut.org 177 :UBC 0 : addlitchar('\'', yyscanner);
5646 magnus@hagander.net 178 : 0 : }
179 : :
180 : 0 : <xq>{xqinside} {
575 peter@eisentraut.org 181 :CBC 2965 : addlit(yytext, yyleng, yyscanner);
5646 magnus@hagander.net 182 : 2965 : }
183 : :
4533 rhaas@postgresql.org 184 : 2965 : {xdstart} {
185 : 1538 : BEGIN(xd);
575 peter@eisentraut.org 186 : 1538 : startlit(yyscanner);
4533 rhaas@postgresql.org 187 : 1538 : }
188 : :
189 : 1538 : <xd>{xdstop} {
1509 peter@eisentraut.org 190 : 1538 : int len;
191 : :
192 : : yyless(1);
4533 rhaas@postgresql.org 193 : 1538 : BEGIN(INITIAL);
575 peter@eisentraut.org 194 : 1538 : yylval->str = litbufdup(yyscanner);
195 : 1538 : len = strlen(yylval->str);
196 : 1538 : truncate_identifier(yylval->str, len, true);
4533 rhaas@postgresql.org 197 : 1538 : return IDENT;
198 : 1538 : }
199 : :
200 : : <xd>{xddouble} {
15 tgl@sss.pgh.pa.us 201 :UBC 0 : addlitchar('"', yyscanner);
202 : 0 : }
203 : :
4533 rhaas@postgresql.org 204 : 0 : <xd>{xdinside} {
575 peter@eisentraut.org 205 :CBC 1538 : addlit(yytext, yyleng, yyscanner);
4533 rhaas@postgresql.org 206 : 1538 : }
207 : :
208 : 1538 : {identifier} {
1509 peter@eisentraut.org 209 : 6771 : int len = strlen(yytext);
4533 rhaas@postgresql.org 210 : 6771 :
211 : : yylval->str = downcase_truncate_identifier(yytext, len, true);
212 : 6771 : return IDENT;
213 : 6771 : }
214 : :
215 : : . {
1618 tgl@sss.pgh.pa.us 216 : 4783 : /* Any char not recognized above is returned as itself */
217 : : return yytext[0];
218 : 4783 : }
219 : :
220 : : <xq,xd><<EOF>> { replication_yyerror(NULL, yyscanner, "unterminated quoted string"); }
5646 magnus@hagander.net 221 :UBC 0 :
222 : :
5646 magnus@hagander.net 223 :CBC 3256 : <<EOF>> {
224 : : yyterminate();
225 : 3256 : }
226 : :
227 : : %%
5646 magnus@hagander.net 228 :UBC 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)
5646 magnus@hagander.net 237 :CBC 4504 : {
238 : : initStringInfo(&yyextra->litbuf);
239 : 4504 : }
240 : 4504 :
241 : : static char *
242 : : litbufdup(yyscan_t yyscanner)
243 : 4504 : {
244 : : return yyextra->litbuf.data;
245 : 4504 : }
246 : :
247 : : static void
248 : : addlit(char *ytext, int yleng, yyscan_t yyscanner)
249 : 4503 : {
250 : : appendBinaryStringInfo(&yyextra->litbuf, ytext, yleng);
251 : 4503 : }
252 : 4503 :
253 : : static void
254 : : addlitchar(unsigned char ychar, yyscan_t yyscanner)
5646 magnus@hagander.net 255 :UBC 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)
5646 magnus@hagander.net 273 :CBC 5829 : {
274 : : yyscan_t yyscanner;
275 : : struct replication_yy_extra_type *yyext = palloc0_object(struct replication_yy_extra_type);
575 peter@eisentraut.org 276 : 5829 :
277 : : if (yylex_init(yyscannerp) != 0)
278 [ - + ]: 5829 : elog(ERROR, "yylex_init() failed: %m");
575 peter@eisentraut.org 279 [ # # ]:UBC 0 :
280 : : yyscanner = *yyscannerp;
575 peter@eisentraut.org 281 :CBC 5829 :
282 : : yyset_extra(yyext, yyscanner);
283 : 5829 :
284 : : yy_scan_string(str, yyscanner);
5646 magnus@hagander.net 285 : 5829 : }
286 : 5829 :
287 : : void
288 : : replication_scanner_finish(yyscan_t yyscanner)
289 : 5829 : {
290 : : pfree(yyextra);
575 peter@eisentraut.org 291 : 5829 : yylex_destroy(yyscanner);
5646 magnus@hagander.net 292 : 5829 : }
1618 tgl@sss.pgh.pa.us 293 : 5829 :
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 : 5829 : {
305 : : YYSTYPE dummy;
306 : : int first_token = replication_yylex(&dummy, yyscanner);
307 : 5829 :
308 : : switch (first_token)
309 [ + + ]: 5829 : {
310 : : case K_IDENTIFY_SYSTEM:
311 : 3256 : 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 : 3256 : return true;
323 : 3256 : default:
324 : 2573 : /* Nope; we don't bother to push back the token. */
325 : : return false;
326 : 2573 : }
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)
575 peter@eisentraut.org 336 : 23316 : {
337 : : return palloc(size);
338 : 23316 : }
339 : :
340 : : void *
341 : : yyrealloc(void *ptr, yy_size_t size, yyscan_t yyscanner)
575 peter@eisentraut.org 342 :UBC 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)
575 peter@eisentraut.org 351 :CBC 29145 : {
352 : : if (ptr)
552 353 [ + + ]: 29145 : pfree(ptr);
575 354 : 23316 : }
0 s.n.thetic 355 : 29145 : /* END: function "replication_yyfree" */
|