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 "nodes/miscnodes.h"
12#include "parser/scansup.h"
13#include "utils/builtins.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:40
#define ereport(elevel,...)
Definition elog.h:152
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})*
85integer_junk {decinteger}{identifier}
86
87space [ \t\n\r\f\v]
88whitespace {space}+
89
90dquote \"
91xdstart {dquote}
92xdstop {dquote}
93xddouble {dquote}{dquote}
94xdinside [^"]+
95
96xcstart \/\*
97xcstop \*+\/
98xcinside [^*/]+
99
101
102{whitespace} { /* ignore */ }
103
104{identifier} {
105 char *str;
106 bool fail;
108
109 /*
110 * Unlike the core scanner, we don't truncate identifiers
111 * here. There is no obvious reason to do so.
112 */
113 str = downcase_identifier(yytext, yyleng, false, false);
114 yylval->str = str;
115
116 /*
117 * If it's not a tag, just return TOK_IDENT; else, return
118 * a token type based on how further parsing should
119 * proceed.
120 */
122 if (fail)
123 return TOK_IDENT;
124 else if (tag == PGPA_TAG_JOIN_ORDER)
125 return TOK_TAG_JOIN_ORDER;
126 else if (tag == PGPA_TAG_INDEX_SCAN ||
128 return TOK_TAG_INDEX;
129 else if (tag == PGPA_TAG_SEQ_SCAN ||
130 tag == PGPA_TAG_TID_SCAN ||
132 tag == PGPA_TAG_NO_GATHER ||
134 return TOK_TAG_SIMPLE;
135 else
136 return TOK_TAG_GENERIC;
137 }
const char * str
pgpa_advice_tag_type pgpa_parse_advice_tag(const char *tag, bool *fail)
Definition pgpa_ast.c:87
pgpa_advice_tag_type
Definition pgpa_ast.h:81
@ PGPA_TAG_INDEX_SCAN
Definition pgpa_ast.h:89
@ PGPA_TAG_BITMAP_HEAP_SCAN
Definition pgpa_ast.h:82
@ PGPA_TAG_NO_GATHER
Definition pgpa_ast.h:96
@ PGPA_TAG_INDEX_ONLY_SCAN
Definition pgpa_ast.h:88
@ PGPA_TAG_SEQ_SCAN
Definition pgpa_ast.h:100
@ PGPA_TAG_DO_NOT_SCAN
Definition pgpa_ast.h:83
@ PGPA_TAG_JOIN_ORDER
Definition pgpa_ast.h:90
@ PGPA_TAG_TID_SCAN
Definition pgpa_ast.h:101
#define yyleng
Definition scan.l:1108
char * downcase_identifier(const char *ident, int len, bool warn, bool truncate)
Definition scansup.c:47
138
139{decinteger} {
141
143 (Node *) &escontext);
144 if (escontext.error_occurred)
146 "integer out of range");
147 return TOK_INTEGER;
148 }
uint32 result
int32 pg_strtoint32_safe(const char *s, Node *escontext)
Definition numutils.c:388
void pgpa_yyerror(List **result, char **parse_error_msg_p, yyscan_t yyscanner, const char *message)
Definition nodes.h:133
149
150{integer_junk} {
151 BEGIN(INITIAL);
153 "trailing junk after numeric literal");
154 }
155
156{xcstart} {
157 BEGIN(xc);
158 }
159
160{xdstart} {
161 BEGIN(xd);
162 resetStringInfo(&yyextra->litbuf);
163 }
#define yyextra
Definition scan.l:1102
void resetStringInfo(StringInfo str)
Definition stringinfo.c:126
164
165. { return yytext[0]; }
166
167<xc>{xcstop} {
168 BEGIN(INITIAL);
169 }
170
171<xc>{xcinside} {
172 /* discard multiple characters without slash or asterisk */
173 }
174
175<xc>. {
176 /*
177 * Discard any single character. flex prefers longer
178 * matches, so this rule will never be picked when we could
179 * have matched xcstop.
180 *
181 * NB: At present, we don't bother to support nested
182 * C-style comments here, but this logic could be extended
183 * if that restriction poses a problem.
184 */
185 }
186
187<xc><<EOF>> {
188 BEGIN(INITIAL);
190 "unterminated comment");
191 }
192
193<xd>{xdstop} {
194 BEGIN(INITIAL);
195 if (yyextra->litbuf.len == 0)
197 "zero-length delimited identifier");
198 yylval->str = pstrdup(yyextra->litbuf.data);
199 return TOK_IDENT;
200 }
char * pstrdup(const char *in)
Definition mcxt.c:1910
201
202<xd>{xddouble} {
203 appendStringInfoChar(&yyextra->litbuf, '"');
204 }
void appendStringInfoChar(StringInfo str, char ch)
Definition stringinfo.c:242
205
206<xd>{xdinside} {
208 }
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition stringinfo.c:281
209
210<xd><<EOF>> {
211 BEGIN(INITIAL);
213 "unterminated quoted identifier");
214 }
215
216%%
217
218/* LCOV_EXCL_STOP */
219
220/*
221 * Handler for errors while scanning or parsing advice.
222 *
223 * bison passes the error message to us via 'message', and the context is
224 * available via the 'yytext' macro. We assemble those values into a final
225 * error text and then arrange to pass it back to the caller of pgpa_yyparse()
226 * by storing it into *parse_error_msg_p.
227 */
228void
230 const char *message)
231{
232 struct yyguts_t *yyg = (struct yyguts_t *) yyscanner; /* needed for yytext
233 * macro */
234
235
236 /* report only the first error in a parse operation */
238 return;
239
240 if (yytext[0])
241 *parse_error_msg_p = psprintf("%s at or near \"%s\"", message, yytext);
242 else
243 *parse_error_msg_p = psprintf("%s at end of input", message);
244}
245
246/*
247 * Initialize the advice scanner.
248 *
249 * This should be called before parsing begins.
250 */
251void
253{
254 yyscan_t yyscanner;
256
257 if (yylex_init(yyscannerp) != 0)
258 elog(ERROR, "yylex_init() failed: %m");
259
260 yyscanner = *yyscannerp;
261
262 initStringInfo(&yyext->litbuf);
263 pgpa_yyset_extra(yyext, yyscanner);
264
265 yy_scan_string(str, yyscanner);
266}
267
268
269/*
270 * Shut down the advice scanner.
271 *
272 * This should be called after parsing is complete.
273 */
274void
276{
277 yylex_destroy(yyscanner);
278}
279
280/*
281 * Interface functions to make flex use palloc() instead of malloc().
282 * It'd be better to make these static, but flex insists otherwise.
283 */
284
285void *
286yyalloc(yy_size_t size, yyscan_t yyscanner)
287{
288 return palloc(size);
289}
290
291void *
292yyrealloc(void *ptr, yy_size_t size, yyscan_t yyscanner)
293{
294 if (ptr)
295 return repalloc(ptr, size);
296 else
297 return palloc(size);
298}
299
300void
301yyfree(void *ptr, yyscan_t yyscanner)
302{
303 if (ptr)
304 pfree(ptr);
305}
void * yyscan_t
Definition cubedata.h:65
#define elog(elevel,...)
Definition elog.h:228
#define palloc0_object(type)
Definition fe_memutils.h:90
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1635
void pfree(void *pointer)
Definition mcxt.c:1619
void * palloc(Size size)
Definition mcxt.c:1390
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