PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pgpa_scanner.l
Go to the documentation of this file.
1%top{
2/*
3 * Scanner for plan advice
4 *
5 * Copyright (c) 2000-2026, PostgreSQL Global Development Group
6 *
7 * contrib/pg_plan_advice/pgpa_scanner.l
8 */
9#include "postgres.h"
10
11#include "common/string.h"
12#include "nodes/miscnodes.h"
13#include "parser/scansup.h"
14
15#include "pgpa_ast.h"
16#include "pgpa_parser.h"
17
18/*
19 * Extra data that we pass around when during scanning.
20 *
21 * 'litbuf' is used to implement the <xd> exclusive state, which handles
22 * double-quoted identifiers.
23 */
28
StringInfoData litbuf
29}
30
31%{
32/* LCOV_EXCL_START */
33
34#define YY_DECL \
35 extern int pgpa_yylex(union YYSTYPE *yylval_param, List **result, \
36 char **parse_error_msg_p, yyscan_t yyscanner)
37
38/* No reason to constrain amount of data slurped */
39#define YY_READ_BUF_SIZE 16777216
40
41/* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
42#undef fprintf
43#define fprintf(file, fmt, msg) fprintf_to_ereport(fmt, msg)
44
45static void
46fprintf_to_ereport(const char *fmt, const char *msg)
47{
48 ereport(ERROR, (errmsg_internal("%s", msg)));
49}
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
static void fprintf_to_ereport(const char *fmt, const char *msg)
static int fb(int x)
50%}
51
52%option reentrant
53%option bison-bridge
54%option 8bit
55%option never-interactive
56%option nodefault
57%option noinput
58%option nounput
59%option noyywrap
60%option noyyalloc
61%option noyyrealloc
62%option noyyfree
63%option warn
64%option prefix="pgpa_yy"
65%option extra-type="pgpa_yy_extra_type *"
66
67/*
68 * What follows is a severely stripped-down version of the core scanner. We
69 * only care about recognizing identifiers with or without identifier quoting
70 * (i.e. double-quoting), decimal integers, and a small handful of other
71 * things. Keep these rules in sync with src/backend/parser/scan.l. As in that
72 * file, we use an exclusive state called 'xc' for C-style comments, and an
73 * exclusive state called 'xd' for double-quoted identifiers.
74 */
75%x xc
76%x xd
77
78ident_start [A-Za-z\200-\377_]
79ident_cont [A-Za-z\200-\377_0-9\$]
80
81identifier {ident_start}{ident_cont}*
82
83decdigit [0-9]
84decinteger {decdigit}(_?{decdigit})*
85
86space [ \t\n\r\f\v]
87whitespace {space}+
88
89dquote \"
90xdstart {dquote}
91xdstop {dquote}
92xddouble {dquote}{dquote}
93xdinside [^"]+
94
95xcstart \/\*
96xcstop \*+\/
97xcinside [^*/]+
98
99%%
100
101{whitespace} { /* ignore */ }
102
103{identifier} {
104 char *str;
105 bool fail;
107
108 /*
109 * Unlike the core scanner, we don't truncate identifiers
110 * here. There is no obvious reason to do so.
111 */
112 str = downcase_identifier(yytext, yyleng, false, false);
113 yylval->str = str;
114
115 /*
116 * If it's not a tag, just return TOK_IDENT; else, return
117 * a token type based on how further parsing should
118 * proceed.
119 */
121 if (fail)
122 return TOK_IDENT;
123 else if (tag == PGPA_TAG_JOIN_ORDER)
124 return TOK_TAG_JOIN_ORDER;
125 else if (tag == PGPA_TAG_INDEX_SCAN ||
127 return TOK_TAG_INDEX;
128 else if (tag == PGPA_TAG_SEQ_SCAN ||
129 tag == PGPA_TAG_TID_SCAN ||
131 tag == PGPA_TAG_NO_GATHER)
132 return TOK_TAG_SIMPLE;
133 else
134 return TOK_TAG_GENERIC;
135 }
const char * str
pgpa_advice_tag_type pgpa_parse_advice_tag(const char *tag, bool *fail)
Definition pgpa_ast.c:85
pgpa_advice_tag_type
Definition pgpa_ast.h:81
@ PGPA_TAG_INDEX_SCAN
Definition pgpa_ast.h:88
@ PGPA_TAG_BITMAP_HEAP_SCAN
Definition pgpa_ast.h:82
@ PGPA_TAG_NO_GATHER
Definition pgpa_ast.h:95
@ PGPA_TAG_INDEX_ONLY_SCAN
Definition pgpa_ast.h:87
@ PGPA_TAG_SEQ_SCAN
Definition pgpa_ast.h:99
@ PGPA_TAG_JOIN_ORDER
Definition pgpa_ast.h:89
@ PGPA_TAG_TID_SCAN
Definition pgpa_ast.h:100
#define yyleng
Definition scan.l:1099
char * downcase_identifier(const char *ident, int len, bool warn, bool truncate)
Definition scansup.c:47
136
137{decinteger} {
138 char *endptr;
139
140 errno = 0;
141 yylval->integer = strtoint(yytext, &endptr, 10);
142 if (*endptr != '\0' || errno == ERANGE)
143 pgpa_yyerror(result, parse_error_msg_p, yyscanner,
144 "integer out of range");
145 return TOK_INTEGER;
146 }
void pgpa_yyerror(List **result, char **parse_error_msg_p, yyscan_t yyscanner, const char *message)
int strtoint(const char *pg_restrict str, char **pg_restrict endptr, int base)
Definition string.c:50
147
148{xcstart} {
149 BEGIN(xc);
150 }
151
152{xdstart} {
153 BEGIN(xd);
154 resetStringInfo(&yyextra->litbuf);
155 }
#define yyextra
Definition scan.l:1093
void resetStringInfo(StringInfo str)
Definition stringinfo.c:126
156
157. { return yytext[0]; }
158
159<xc>{xcstop} {
160 BEGIN(INITIAL);
161 }
162
163<xc>{xcinside} {
164 /* discard multiple characters without slash or asterisk */
165 }
166
167<xc>. {
168 /*
169 * Discard any single character. flex prefers longer
170 * matches, so this rule will never be picked when we could
171 * have matched xcstop.
172 *
173 * NB: At present, we don't bother to support nested
174 * C-style comments here, but this logic could be extended
175 * if that restriction poses a problem.
176 */
177 }
178
179<xc><<EOF>> {
180 BEGIN(INITIAL);
181 pgpa_yyerror(result, parse_error_msg_p, yyscanner,
182 "unterminated comment");
183 }
184
185<xd>{xdstop} {
186 BEGIN(INITIAL);
187 if (yyextra->litbuf.len == 0)
188 pgpa_yyerror(result, parse_error_msg_p, yyscanner,
189 "zero-length delimited identifier");
190 yylval->str = pstrdup(yyextra->litbuf.data);
191 return TOK_IDENT;
192 }
char * pstrdup(const char *in)
Definition mcxt.c:1781
193
194<xd>{xddouble} {
195 appendStringInfoChar(&yyextra->litbuf, '"');
196 }
void appendStringInfoChar(StringInfo str, char ch)
Definition stringinfo.c:242
197
198<xd>{xdinside} {
200 }
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition stringinfo.c:281
201
202<xd><<EOF>> {
203 BEGIN(INITIAL);
204 pgpa_yyerror(result, parse_error_msg_p, yyscanner,
205 "unterminated quoted identifier");
206 }
207
208%%
209
210/* LCOV_EXCL_STOP */
211
212/*
213 * Handler for errors while scanning or parsing advice.
214 *
215 * bison passes the error message to us via 'message', and the context is
216 * available via the 'yytext' macro. We assemble those values into a final
217 * error text and then arrange to pass it back to the caller of pgpa_yyparse()
218 * by storing it into *parse_error_msg_p.
219 */
220void
221pgpa_yyerror(List **result, char **parse_error_msg_p, yyscan_t yyscanner,
222 const char *message)
223{
224 struct yyguts_t *yyg = (struct yyguts_t *) yyscanner; /* needed for yytext
225 * macro */
226
227
228 /* report only the first error in a parse operation */
230 return;
231
232 if (yytext[0])
233 *parse_error_msg_p = psprintf("%s at or near \"%s\"", message, yytext);
234 else
235 *parse_error_msg_p = psprintf("%s at end of input", message);
236}
237
238/*
239 * Initialize the advice scanner.
240 *
241 * This should be called before parsing begins.
242 */
243void
245{
246 yyscan_t yyscanner;
248
249 if (yylex_init(yyscannerp) != 0)
250 elog(ERROR, "yylex_init() failed: %m");
251
252 yyscanner = *yyscannerp;
253
254 initStringInfo(&yyext->litbuf);
255 pgpa_yyset_extra(yyext, yyscanner);
256
257 yy_scan_string(str, yyscanner);
258}
259
260
261/*
262 * Shut down the advice scanner.
263 *
264 * This should be called after parsing is complete.
265 */
266void
268{
269 yylex_destroy(yyscanner);
270}
271
272/*
273 * Interface functions to make flex use palloc() instead of malloc().
274 * It'd be better to make these static, but flex insists otherwise.
275 */
276
277void *
278yyalloc(yy_size_t size, yyscan_t yyscanner)
279{
280 return palloc(size);
281}
282
283void *
284yyrealloc(void *ptr, yy_size_t size, yyscan_t yyscanner)
285{
286 if (ptr)
287 return repalloc(ptr, size);
288 else
289 return palloc(size);
290}
291
292void
293yyfree(void *ptr, yyscan_t yyscanner)
294{
295 if (ptr)
296 pfree(ptr);
297}
void * yyscan_t
Definition cubedata.h:65
#define elog(elevel,...)
Definition elog.h:226
#define palloc0_object(type)
Definition fe_memutils.h:75
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1632
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc(Size size)
Definition mcxt.c:1387
void * yyrealloc(void *ptr, yy_size_t size, yyscan_t yyscanner)
void pgpa_scanner_finish(yyscan_t yyscanner)
void pgpa_scanner_init(const char *str, yyscan_t *yyscannerp)
void yyfree(void *ptr, yyscan_t yyscanner)
void * yyalloc(yy_size_t size, yyscan_t yyscanner)
char * psprintf(const char *fmt,...)
Definition psprintf.c:43
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
Definition pg_list.h:54