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 "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
5044 tgl@sss.pgh.pa.us 37 :UBC 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)
1746 tgl@sss.pgh.pa.us 119 [ + + ]:CBC 32300 : {
120 : : int result = yyextra->repl_pushed_back_token;
121 : 3559 :
122 : : yyextra->repl_pushed_back_token = 0;
123 : 3559 : return result;
124 : 3559 : }
125 : : %}
126 : :
127 : : BASE_BACKUP { return K_BASE_BACKUP; }
5774 magnus@hagander.net 128 : 221 : IDENTIFY_SYSTEM { return K_IDENTIFY_SYSTEM; }
1837 michael@paquier.xyz 129 : 896 : READ_REPLICATION_SLOT { return K_READ_REPLICATION_SLOT; }
3572 rhaas@postgresql.org 130 : 896 : SHOW { return K_SHOW; }
5075 heikki.linnakangas@i 131 : 6 : TIMELINE { return K_TIMELINE; }
5774 magnus@hagander.net 132 : 699 : START_REPLICATION { return K_START_REPLICATION; }
4661 rhaas@postgresql.org 133 : 339 : CREATE_REPLICATION_SLOT { return K_CREATE_REPLICATION_SLOT; }
134 : 834 : DROP_REPLICATION_SLOT { return K_DROP_REPLICATION_SLOT; }
1011 akapila@postgresql.o 135 : 550 : ALTER_REPLICATION_SLOT { return K_ALTER_REPLICATION_SLOT; }
5075 heikki.linnakangas@i 136 : 310 : TIMELINE_HISTORY { return K_TIMELINE_HISTORY; }
4661 rhaas@postgresql.org 137 : 7 : PHYSICAL { return K_PHYSICAL; }
4078 andres@anarazel.de 138 : 18 : RESERVE_WAL { return K_RESERVE_WAL; }
4623 rhaas@postgresql.org 139 : 172 : LOGICAL { return K_LOGICAL; }
4661 140 : 171 : SLOT { return K_SLOT; }
3619 peter_e@gmx.net 141 : 870 : TEMPORARY { return K_TEMPORARY; }
1954 akapila@postgresql.o 142 : 715 : TWO_PHASE { return K_TWO_PHASE; }
3523 peter_e@gmx.net 143 : 167 : EXPORT_SNAPSHOT { return K_EXPORT_SNAPSHOT; }
144 : 3 : NOEXPORT_SNAPSHOT { return K_NOEXPORT_SNAPSHOT; }
3514 peter_e@gmx.net 145 :UBC 0 : USE_SNAPSHOT { return K_USE_SNAPSHOT; }
3352 alvherre@alvh.no-ip. 146 : 0 : WAIT { return K_WAIT; }
1051 rhaas@postgresql.org 147 :CBC 1 : UPLOAD_MANIFEST { return K_UPLOAD_MANIFEST; }
4661 148 : 510 :
1746 tgl@sss.pgh.pa.us 149 : 18 : {space}+ { /* do nothing */ }
5774 magnus@hagander.net 150 : 14159 :
5075 heikki.linnakangas@i 151 : 14159 : {digit}+ {
703 peter@eisentraut.org 152 : 567 : yylval->uintval = strtoul(yytext, NULL, 10);
4831 peter_e@gmx.net 153 : 567 : return UCONST;
5075 heikki.linnakangas@i 154 : 567 : }
155 : :
156 : : {hexdigit}+\/{hexdigit}+ {
14 fujii@postgresql.org 157 :GNC 834 : if (!pg_parse_lsn(yytext, &yylval->recptr))
650 peter@eisentraut.org 158 [ + + ]:CBC 834 : replication_yyerror(NULL, yyscanner, "invalid streaming start location");
5774 magnus@hagander.net 159 : 2 : return RECPTR;
160 : 832 : }
161 : :
162 : : {xqstart} {
163 : 3196 : BEGIN(xq);
703 peter@eisentraut.org 164 : 3196 : startlit(yyscanner);
5774 magnus@hagander.net 165 : 3196 : }
166 : :
167 : 3196 : <xq>{quotestop} {
168 : 3196 : yyless(1);
169 : 3196 : BEGIN(INITIAL);
703 peter@eisentraut.org 170 : 3196 : yylval->str = litbufdup(yyscanner);
5774 magnus@hagander.net 171 : 3196 : return SCONST;
172 : 3196 : }
173 : :
174 : : <xq>{xqdouble} {
703 peter@eisentraut.org 175 :UBC 0 : addlitchar('\'', yyscanner);
5774 magnus@hagander.net 176 : 0 : }
177 : :
178 : 0 : <xq>{xqinside} {
703 peter@eisentraut.org 179 :CBC 3195 : addlit(yytext, yyleng, yyscanner);
5774 magnus@hagander.net 180 : 3195 : }
181 : :
4661 rhaas@postgresql.org 182 : 3195 : {xdstart} {
183 : 1645 : BEGIN(xd);
703 peter@eisentraut.org 184 : 1645 : startlit(yyscanner);
4661 rhaas@postgresql.org 185 : 1645 : }
186 : :
187 : 1645 : <xd>{xdstop} {
1637 peter@eisentraut.org 188 : 1645 : int len;
189 : :
190 : : yyless(1);
4661 rhaas@postgresql.org 191 : 1645 : BEGIN(INITIAL);
703 peter@eisentraut.org 192 : 1645 : yylval->str = litbufdup(yyscanner);
193 : 1645 : len = strlen(yylval->str);
194 : 1645 : truncate_identifier(yylval->str, len, true);
4661 rhaas@postgresql.org 195 : 1645 : return IDENT;
196 : 1645 : }
197 : :
198 : : <xd>{xddouble} {
143 tgl@sss.pgh.pa.us 199 :UBC 0 : addlitchar('"', yyscanner);
200 : 0 : }
201 : :
4661 rhaas@postgresql.org 202 : 0 : <xd>{xdinside} {
703 peter@eisentraut.org 203 :CBC 1645 : addlit(yytext, yyleng, yyscanner);
4661 rhaas@postgresql.org 204 : 1645 : }
205 : :
206 : 1645 : {identifier} {
1637 peter@eisentraut.org 207 : 7264 : int len = strlen(yytext);
4661 rhaas@postgresql.org 208 : 7264 :
209 : : yylval->str = downcase_truncate_identifier(yytext, len, true);
210 : 7264 : return IDENT;
211 : 7264 : }
212 : :
213 : : . {
1746 tgl@sss.pgh.pa.us 214 : 5171 : /* Any char not recognized above is returned as itself */
215 : : return yytext[0];
216 : 5171 : }
217 : :
218 : : <xq,xd><<EOF>> { replication_yyerror(NULL, yyscanner, "unterminated quoted string"); }
5774 magnus@hagander.net 219 :UBC 0 :
220 : :
5774 magnus@hagander.net 221 :CBC 3557 : <<EOF>> {
222 : : yyterminate();
223 : 3557 : }
224 : :
225 : : %%
5774 magnus@hagander.net 226 :UBC 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)
5774 magnus@hagander.net 235 :CBC 4841 : {
236 : : initStringInfo(&yyextra->litbuf);
237 : 4841 : }
238 : 4841 :
239 : : static char *
240 : : litbufdup(yyscan_t yyscanner)
241 : 4841 : {
242 : : return yyextra->litbuf.data;
243 : 4841 : }
244 : :
245 : : static void
246 : : addlit(char *ytext, int yleng, yyscan_t yyscanner)
247 : 4840 : {
248 : : appendBinaryStringInfo(&yyextra->litbuf, ytext, yleng);
249 : 4840 : }
250 : 4840 :
251 : : static void
252 : : addlitchar(unsigned char ychar, yyscan_t yyscanner)
5774 magnus@hagander.net 253 :UBC 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)
5774 magnus@hagander.net 263 :GBC 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)
5774 magnus@hagander.net 271 :CBC 6284 : {
272 : : yyscan_t yyscanner;
273 : : struct replication_yy_extra_type *yyext = palloc0_object(struct replication_yy_extra_type);
703 peter@eisentraut.org 274 : 6284 :
275 : : if (yylex_init(yyscannerp) != 0)
276 [ - + ]: 6284 : elog(ERROR, "yylex_init() failed: %m");
703 peter@eisentraut.org 277 [ # # ]:UBC 0 :
278 : : yyscanner = *yyscannerp;
703 peter@eisentraut.org 279 :CBC 6284 :
280 : : yyset_extra(yyext, yyscanner);
281 : 6284 :
282 : : yy_scan_string(str, yyscanner);
5774 magnus@hagander.net 283 : 6284 : }
284 : 6284 :
285 : : void
286 : : replication_scanner_finish(yyscan_t yyscanner)
287 : 6282 : {
288 : : pfree(yyextra);
703 peter@eisentraut.org 289 : 6282 : yylex_destroy(yyscanner);
5774 magnus@hagander.net 290 : 6282 : }
1746 tgl@sss.pgh.pa.us 291 : 6282 :
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 : 6284 : {
303 : : YYSTYPE dummy;
304 : : int first_token = replication_yylex(&dummy, yyscanner);
305 : 6284 :
306 : : switch (first_token)
307 [ + + ]: 6284 : {
308 : : case K_IDENTIFY_SYSTEM:
309 : 3559 : 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 : 3559 : return true;
321 : 3559 : default:
322 : 2725 : /* Nope; we don't bother to push back the token. */
323 : : return false;
324 : 2725 : }
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)
703 peter@eisentraut.org 334 : 25136 : {
335 : : return palloc(size);
336 : 25136 : }
337 : :
338 : : void *
339 : : yyrealloc(void *ptr, yy_size_t size, yyscan_t yyscanner)
703 peter@eisentraut.org 340 :UBC 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)
703 peter@eisentraut.org 349 :CBC 31410 : {
350 : : if (ptr)
680 351 [ + + ]: 31410 : pfree(ptr);
703 352 : 25128 : }
0 s.n.thetic 353 : 31410 : /* END: function "replication_yyfree" */
|