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-2024, 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 : /* 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;
46 :
47 : /* Work area for collecting literals */
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\v]
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)
112 : {
113 : int result = repl_pushed_back_token;
114 :
115 : repl_pushed_back_token = 0;
116 : return result;
117 : }
118 : %}
119 :
120 : BASE_BACKUP { return K_BASE_BACKUP; }
121 : IDENTIFY_SYSTEM { return K_IDENTIFY_SYSTEM; }
122 : READ_REPLICATION_SLOT { return K_READ_REPLICATION_SLOT; }
123 : SHOW { return K_SHOW; }
124 : TIMELINE { return K_TIMELINE; }
125 : START_REPLICATION { return K_START_REPLICATION; }
126 : CREATE_REPLICATION_SLOT { return K_CREATE_REPLICATION_SLOT; }
127 : DROP_REPLICATION_SLOT { return K_DROP_REPLICATION_SLOT; }
128 : ALTER_REPLICATION_SLOT { return K_ALTER_REPLICATION_SLOT; }
129 : TIMELINE_HISTORY { return K_TIMELINE_HISTORY; }
130 : PHYSICAL { return K_PHYSICAL; }
131 : RESERVE_WAL { return K_RESERVE_WAL; }
132 : LOGICAL { return K_LOGICAL; }
133 : SLOT { return K_SLOT; }
134 : TEMPORARY { return K_TEMPORARY; }
135 : TWO_PHASE { return K_TWO_PHASE; }
136 : EXPORT_SNAPSHOT { return K_EXPORT_SNAPSHOT; }
137 : NOEXPORT_SNAPSHOT { return K_NOEXPORT_SNAPSHOT; }
138 : USE_SNAPSHOT { return K_USE_SNAPSHOT; }
139 : WAIT { return K_WAIT; }
140 : UPLOAD_MANIFEST { return K_UPLOAD_MANIFEST; }
141 :
142 : {space}+ { /* do nothing */ }
143 :
144 : {digit}+ {
145 : replication_yylval.uintval = strtoul(yytext, NULL, 10);
146 : return UCONST;
147 : }
148 :
149 : {hexdigit}+\/{hexdigit}+ {
150 : uint32 hi,
151 : lo;
152 : if (sscanf(yytext, "%X/%X", &hi, &lo) != 2)
153 : replication_yyerror("invalid streaming start location");
154 : replication_yylval.recptr = ((uint64) hi) << 32 | lo;
155 : return RECPTR;
156 : }
157 :
158 : {xqstart} {
159 : BEGIN(xq);
160 : startlit();
161 : }
162 :
163 : <xq>{quotestop} {
164 : yyless(1);
165 : BEGIN(INITIAL);
166 : replication_yylval.str = litbufdup();
167 : return SCONST;
168 : }
169 :
170 : <xq>{xqdouble} {
171 : addlitchar('\'');
172 : }
173 :
174 : <xq>{xqinside} {
175 : addlit(yytext, yyleng);
176 : }
177 :
178 : {xdstart} {
179 : BEGIN(xd);
180 : startlit();
181 : }
182 :
183 : <xd>{xdstop} {
184 : int len;
185 :
186 : yyless(1);
187 : BEGIN(INITIAL);
188 : replication_yylval.str = litbufdup();
189 : len = strlen(replication_yylval.str);
190 : truncate_identifier(replication_yylval.str, len, true);
191 : return IDENT;
192 : }
193 :
194 : <xd>{xdinside} {
195 : addlit(yytext, yyleng);
196 : }
197 :
198 : {identifier} {
199 : int len = strlen(yytext);
200 :
201 : replication_yylval.str = downcase_truncate_identifier(yytext, len, true);
202 : return IDENT;
203 : }
204 :
205 : . {
206 : /* Any char not recognized above is returned as itself */
207 : return yytext[0];
208 : }
209 :
210 : <xq,xd><<EOF>> { replication_yyerror("unterminated quoted string"); }
211 :
212 :
213 : <<EOF>> {
214 : yyterminate();
215 : }
216 :
217 : %%
218 :
219 : /* LCOV_EXCL_STOP */
220 :
221 : static void
222 : startlit(void)
223 6750 : {
224 : initStringInfo(&litbuf);
225 6750 : }
226 6750 :
227 : static char *
228 : litbufdup(void)
229 6750 : {
230 : return litbuf.data;
231 6750 : }
232 :
233 : static void
234 : addlit(char *ytext, int yleng)
235 6748 : {
236 : appendBinaryStringInfo(&litbuf, ytext, yleng);
237 6748 : }
238 6748 :
239 : static void
240 : addlitchar(unsigned char ychar)
241 0 : {
242 : appendStringInfoChar(&litbuf, ychar);
243 0 : }
244 0 :
245 : void
246 : replication_yyerror(const char *message)
247 0 : {
248 : ereport(ERROR,
249 0 : (errcode(ERRCODE_SYNTAX_ERROR),
250 : errmsg_internal("%s", message)));
251 : }
252 :
253 :
254 : void
255 : replication_scanner_init(const char *str)
256 9354 : {
257 : Size slen = strlen(str);
258 9354 : char *scanbuf;
259 :
260 : /*
261 : * Might be left over after ereport()
262 : */
263 : if (YY_CURRENT_BUFFER)
264 9354 : yy_delete_buffer(YY_CURRENT_BUFFER);
265 0 :
266 : /*
267 : * Make a scan buffer with special termination needed by flex.
268 : */
269 : scanbuf = (char *) palloc(slen + 2);
270 9354 : memcpy(scanbuf, str, slen);
271 9354 : scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
272 9354 : scanbufhandle = yy_scan_buffer(scanbuf, slen + 2);
273 9354 :
274 : /* Make sure we start in proper state */
275 : BEGIN(INITIAL);
276 9354 : repl_pushed_back_token = 0;
277 9354 : }
278 9354 :
279 : void
280 : replication_scanner_finish(void)
281 9354 : {
282 : yy_delete_buffer(scanbufhandle);
283 9354 : scanbufhandle = NULL;
284 9354 : }
285 9354 :
286 : /*
287 : * Check to see if the first token of a command is a WalSender keyword.
288 : *
289 : * To keep repl_scanner.l minimal, we don't ask it to know every construct
290 : * that the core lexer knows. Therefore, we daren't lex more than the
291 : * first token of a general SQL command. That will usually look like an
292 : * IDENT token here, although some other cases are possible.
293 : */
294 : bool
295 : replication_scanner_is_replication_command(void)
296 9354 : {
297 : int first_token = replication_yylex();
298 9354 :
299 : switch (first_token)
300 9354 : {
301 : case K_IDENTIFY_SYSTEM:
302 5324 : case K_BASE_BACKUP:
303 : case K_START_REPLICATION:
304 : case K_CREATE_REPLICATION_SLOT:
305 : case K_DROP_REPLICATION_SLOT:
306 : case K_ALTER_REPLICATION_SLOT:
307 : case K_READ_REPLICATION_SLOT:
308 : case K_TIMELINE_HISTORY:
309 : case K_UPLOAD_MANIFEST:
310 : case K_SHOW:
311 : /* Yes; push back the first token so we can parse later. */
312 : repl_pushed_back_token = first_token;
313 5324 : return true;
314 5324 : default:
315 4030 : /* Nope; we don't bother to push back the token. */
316 : return false;
317 4030 : }
318 : }
|