doc: Fix section of functions age(xid) and mxid_age(xid)
[pgsql.git] / src / backend / replication / repl_scanner.l
blobe7def800655f3c5b1a2637f4e9303764dfa9b417
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"
18 #include "nodes/parsenodes.h"
19 #include "utils/builtins.h"
20 #include "parser/scansup.h"
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"
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)
35 static void
36 fprintf_to_ereport(const char *fmt, const char *msg)
38         ereport(ERROR, (errmsg_internal("%s", msg)));
41 /* Handle to the buffer that the lexer uses internally */
42 static YY_BUFFER_STATE scanbufhandle;
44 /* Pushed-back token (we only handle one) */
45 static int      repl_pushed_back_token;
47 /* Work area for collecting literals */
48 static StringInfoData litbuf;
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);
55 /* LCOV_EXCL_START */
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"
69  * Exclusive states:
70  *  <xd> delimited identifiers (double-quoted identifiers)
71  *  <xq> standard single-quoted strings
72  */
73 %x xd
74 %x xq
76 space                   [ \t\n\r\f\v]
78 quote                   '
79 quotestop               {quote}
81 /* Extended quote
82  * xqdouble implements embedded quote, ''''
83  */
84 xqstart                 {quote}
85 xqdouble                {quote}{quote}
86 xqinside                [^']+
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                [^"]+
97 digit                   [0-9]
98 hexdigit                [0-9A-Fa-f]
100 ident_start             [A-Za-z\200-\377_]
101 ident_cont              [A-Za-z\200-\377_0-9\$]
103 identifier              {ident_start}{ident_cont}*
108         /* This code is inserted at the start of replication_yylex() */
110         /* If we have a pushed-back token, return that. */
111         if (repl_pushed_back_token)
112         {
113                 int                     result = repl_pushed_back_token;
115                 repl_pushed_back_token = 0;
116                 return result;
117         }
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; }
142 {space}+                { /* do nothing */ }
144 {digit}+                {
145                                         replication_yylval.uintval = strtoul(yytext, NULL, 10);
146                                         return UCONST;
147                                 }
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                                 }
158 {xqstart}               {
159                                         BEGIN(xq);
160                                         startlit();
161                                 }
163 <xq>{quotestop} {
164                                         yyless(1);
165                                         BEGIN(INITIAL);
166                                         replication_yylval.str = litbufdup();
167                                         return SCONST;
168                                 }
170 <xq>{xqdouble}  {
171                                         addlitchar('\'');
172                                 }
174 <xq>{xqinside}  {
175                                         addlit(yytext, yyleng);
176                                 }
178 {xdstart}               {
179                                         BEGIN(xd);
180                                         startlit();
181                                 }
183 <xd>{xdstop}    {
184                                         int                     len;
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                                 }
194 <xd>{xdinside}  {
195                                         addlit(yytext, yyleng);
196                                 }
198 {identifier}    {
199                                         int                     len = strlen(yytext);
201                                         replication_yylval.str = downcase_truncate_identifier(yytext, len, true);
202                                         return IDENT;
203                                 }
205 .                               {
206                                         /* Any char not recognized above is returned as itself */
207                                         return yytext[0];
208                                 }
210 <xq,xd><<EOF>>  { replication_yyerror("unterminated quoted string"); }
213 <<EOF>>                 {
214                                         yyterminate();
215                                 }
219 /* LCOV_EXCL_STOP */
221 static void
222 startlit(void)
224         initStringInfo(&litbuf);
227 static char *
228 litbufdup(void)
230         return litbuf.data;
233 static void
234 addlit(char *ytext, int yleng)
236         appendBinaryStringInfo(&litbuf, ytext, yleng);
239 static void
240 addlitchar(unsigned char ychar)
242         appendStringInfoChar(&litbuf, ychar);
245 void
246 replication_yyerror(const char *message)
248         ereport(ERROR,
249                         (errcode(ERRCODE_SYNTAX_ERROR),
250                          errmsg_internal("%s", message)));
254 void
255 replication_scanner_init(const char *str)
257         Size            slen = strlen(str);
258         char       *scanbuf;
260         /*
261          * Might be left over after ereport()
262          */
263         if (YY_CURRENT_BUFFER)
264                 yy_delete_buffer(YY_CURRENT_BUFFER);
266         /*
267          * Make a scan buffer with special termination needed by flex.
268          */
269         scanbuf = (char *) palloc(slen + 2);
270         memcpy(scanbuf, str, slen);
271         scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
272         scanbufhandle = yy_scan_buffer(scanbuf, slen + 2);
274         /* Make sure we start in proper state */
275         BEGIN(INITIAL);
276         repl_pushed_back_token = 0;
279 void
280 replication_scanner_finish(void)
282         yy_delete_buffer(scanbufhandle);
283         scanbufhandle = NULL;
287  * Check to see if the first token of a command is a WalSender keyword.
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)
297         int                     first_token = replication_yylex();
299         switch (first_token)
300         {
301                 case K_IDENTIFY_SYSTEM:
302                 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                         return true;
314                 default:
315                         /* Nope; we don't bother to push back the token. */
316                         return false;
317         }