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-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
4109 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 : : /* 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)
4839 magnus@hagander.net 223 :CBC 3085 : {
224 : : initStringInfo(&litbuf);
225 : 3085 : }
226 : 3085 :
227 : : static char *
228 : : litbufdup(void)
229 : 3085 : {
230 : : return litbuf.data;
231 : 3085 : }
232 : :
233 : : static void
234 : : addlit(char *ytext, int yleng)
235 : 3084 : {
236 : : appendBinaryStringInfo(&litbuf, ytext, yleng);
237 : 3084 : }
238 : 3084 :
239 : : static void
240 : : addlitchar(unsigned char ychar)
4839 magnus@hagander.net 241 :UBC 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)
4839 magnus@hagander.net 256 :CBC 4643 : {
257 : : Size slen = strlen(str);
258 : 4643 : char *scanbuf;
259 : :
260 : : /*
261 : : * Might be left over after ereport()
262 : : */
263 : : if (YY_CURRENT_BUFFER)
264 [ + + - + ]: 4643 : yy_delete_buffer(YY_CURRENT_BUFFER);
4839 magnus@hagander.net 265 [ # # ]:UBC 0 :
266 : : /*
267 : : * Make a scan buffer with special termination needed by flex.
268 : : */
269 : : scanbuf = (char *) palloc(slen + 2);
4839 magnus@hagander.net 270 :CBC 4643 : memcpy(scanbuf, str, slen);
271 : 4643 : scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
272 : 4643 : scanbufhandle = yy_scan_buffer(scanbuf, slen + 2);
811 tgl@sss.pgh.pa.us 273 : 4643 :
274 : : /* Make sure we start in proper state */
275 : : BEGIN(INITIAL);
276 : 4643 : repl_pushed_back_token = 0;
4839 magnus@hagander.net 277 : 4643 : }
278 : 4643 :
279 : : void
280 : : replication_scanner_finish(void)
281 : 4643 : {
282 : : yy_delete_buffer(scanbufhandle);
283 : 4643 : scanbufhandle = NULL;
284 : 4643 : }
811 tgl@sss.pgh.pa.us 285 : 4643 :
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 : 4643 : {
297 : : int first_token = replication_yylex();
298 : 4643 :
299 : : switch (first_token)
300 [ + + ]: 4643 : {
301 : : case K_IDENTIFY_SYSTEM:
302 : 2657 : 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 : 2657 : return true;
314 : 2657 : default:
315 : 1986 : /* Nope; we don't bother to push back the token. */
316 : : return false;
317 : 1986 : }
318 : : }
|