1 %{
2 /*-------------------------------------------------------------------------
3  *
4  * repl_scanner.l
5  *	  a lexical scanner for the replication commands
6  *
7  * Portions Copyright (c) 1996-2016, 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 "utils/builtins.h"
19 #include "parser/scansup.h"
20 
21 /* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
22 #undef fprintf
23 #define fprintf(file, fmt, msg)  fprintf_to_ereport(fmt, msg)
24 
25 static void
fprintf_to_ereport(const char * fmt,const char * msg)26 fprintf_to_ereport(const char *fmt, const char *msg)
27 {
28 	ereport(ERROR, (errmsg_internal("%s", msg)));
29 }
30 
31 /* Handle to the buffer that the lexer uses internally */
32 static YY_BUFFER_STATE scanbufhandle;
33 
34 static StringInfoData litbuf;
35 
36 static void startlit(void);
37 static char *litbufdup(void);
38 static void addlit(char *ytext, int yleng);
39 static void addlitchar(unsigned char ychar);
40 
41 %}
42 
43 %option 8bit
44 %option never-interactive
45 %option nodefault
46 %option noinput
47 %option nounput
48 %option noyywrap
49 %option warn
50 %option prefix="replication_yy"
51 
52 %x xq xd
53 
54 /* Extended quote
55  * xqdouble implements embedded quote, ''''
56  */
57 xqstart			{quote}
58 xqdouble		{quote}{quote}
59 xqinside		[^']+
60 
61 /* Double quote
62  * Allows embedded spaces and other special characters into identifiers.
63  */
64 dquote			\"
65 xdstart			{dquote}
66 xdstop			{dquote}
67 xddouble		{dquote}{dquote}
68 xdinside		[^"]+
69 
70 digit			[0-9]+
71 hexdigit		[0-9A-Za-z]+
72 
73 quote			'
74 quotestop		{quote}
75 
76 ident_start		[A-Za-z\200-\377_]
77 ident_cont		[A-Za-z\200-\377_0-9\$]
78 
79 identifier		{ident_start}{ident_cont}*
80 
81 %%
82 
83 BASE_BACKUP			{ return K_BASE_BACKUP; }
84 FAST			{ return K_FAST; }
85 IDENTIFY_SYSTEM		{ return K_IDENTIFY_SYSTEM; }
86 LABEL			{ return K_LABEL; }
87 NOWAIT			{ return K_NOWAIT; }
88 PROGRESS			{ return K_PROGRESS; }
89 MAX_RATE		{ return K_MAX_RATE; }
90 WAL			{ return K_WAL; }
91 TABLESPACE_MAP			{ return K_TABLESPACE_MAP; }
92 TIMELINE			{ return K_TIMELINE; }
93 START_REPLICATION	{ return K_START_REPLICATION; }
94 CREATE_REPLICATION_SLOT		{ return K_CREATE_REPLICATION_SLOT; }
95 DROP_REPLICATION_SLOT		{ return K_DROP_REPLICATION_SLOT; }
96 TIMELINE_HISTORY	{ return K_TIMELINE_HISTORY; }
97 PHYSICAL			{ return K_PHYSICAL; }
98 RESERVE_WAL			{ return K_RESERVE_WAL; }
99 LOGICAL				{ return K_LOGICAL; }
100 SLOT				{ return K_SLOT; }
101 
102 ","				{ return ','; }
103 ";"				{ return ';'; }
104 "("				{ return '('; }
105 ")"				{ return ')'; }
106 
107 [\n]			;
108 [\t]			;
109 " "				;
110 
111 {digit}+		{
112 					yylval.uintval = strtoul(yytext, NULL, 10);
113 					return UCONST;
114 				}
115 
116 {hexdigit}+\/{hexdigit}+		{
117 					uint32	hi,
118 							lo;
119 					if (sscanf(yytext, "%X/%X", &hi, &lo) != 2)
120 						yyerror("invalid streaming start location");
121 					yylval.recptr = ((uint64) hi) << 32 | lo;
122 					return RECPTR;
123 				}
124 
125 {xqstart}		{
126 					BEGIN(xq);
127 					startlit();
128 				}
129 
130 <xq>{quotestop}	{
131 					yyless(1);
132 					BEGIN(INITIAL);
133 					yylval.str = litbufdup();
134 					return SCONST;
135 				}
136 
137 <xq>{xqdouble}	{
138 					addlitchar('\'');
139 				}
140 
141 <xq>{xqinside}  {
142 					addlit(yytext, yyleng);
143 				}
144 
145 {xdstart}		{
146 					BEGIN(xd);
147 					startlit();
148 				}
149 
150 <xd>{xdstop}	{
151 					int len;
152 					yyless(1);
153 					BEGIN(INITIAL);
154 					yylval.str = litbufdup();
155 					len = strlen(yylval.str);
156 					truncate_identifier(yylval.str, len, true);
157 					return IDENT;
158 				}
159 
160 <xd>{xdinside}  {
161 					addlit(yytext, yyleng);
162 				}
163 
164 {identifier}	{
165 					int len = strlen(yytext);
166 
167 					yylval.str = downcase_truncate_identifier(yytext, len, true);
168 					return IDENT;
169 				}
170 
171 <xq,xd><<EOF>>	{ yyerror("unterminated quoted string"); }
172 
173 
174 <<EOF>>			{
175 					yyterminate();
176 				}
177 
178 .				{
179 					ereport(ERROR,
180 							(errcode(ERRCODE_SYNTAX_ERROR),
181 							 errmsg("syntax error: unexpected character \"%s\"", yytext)));
182 				}
183 %%
184 
185 
186 static void
187 startlit(void)
188 {
189 	initStringInfo(&litbuf);
190 }
191 
192 static char *
litbufdup(void)193 litbufdup(void)
194 {
195 	return litbuf.data;
196 }
197 
198 static void
addlit(char * ytext,int yleng)199 addlit(char *ytext, int yleng)
200 {
201 	appendBinaryStringInfo(&litbuf, ytext, yleng);
202 }
203 
204 static void
addlitchar(unsigned char ychar)205 addlitchar(unsigned char ychar)
206 {
207 	appendStringInfoChar(&litbuf, ychar);
208 }
209 
210 void
yyerror(const char * message)211 yyerror(const char *message)
212 {
213 	ereport(ERROR,
214 			(errcode(ERRCODE_SYNTAX_ERROR),
215 			 errmsg_internal("%s", message)));
216 }
217 
218 
219 void
replication_scanner_init(const char * str)220 replication_scanner_init(const char *str)
221 {
222 	Size		slen = strlen(str);
223 	char	   *scanbuf;
224 
225 	/*
226 	 * Might be left over after ereport()
227 	 */
228 	if (YY_CURRENT_BUFFER)
229 		yy_delete_buffer(YY_CURRENT_BUFFER);
230 
231 	/*
232 	 * Make a scan buffer with special termination needed by flex.
233 	 */
234 	scanbuf = (char *) palloc(slen + 2);
235 	memcpy(scanbuf, str, slen);
236 	scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
237 	scanbufhandle = yy_scan_buffer(scanbuf, slen + 2);
238 }
239 
240 void
replication_scanner_finish(void)241 replication_scanner_finish(void)
242 {
243 	yy_delete_buffer(scanbufhandle);
244 	scanbufhandle = NULL;
245 }
246