Branch data Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * parser.c
4 : : * Main entry point/driver for PostgreSQL grammar
5 : : *
6 : : * Note that the grammar is not allowed to perform any table access
7 : : * (since we need to be able to do basic parsing even while inside an
8 : : * aborted transaction). Therefore, the data structures returned by
9 : : * the grammar are "raw" parsetrees that still need to be analyzed by
10 : : * analyze.c and related files.
11 : : *
12 : : *
13 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
14 : : * Portions Copyright (c) 1994, Regents of the University of California
15 : : *
16 : : * IDENTIFICATION
17 : : * src/backend/parser/parser.c
18 : : *
19 : : *-------------------------------------------------------------------------
20 : : */
21 : :
22 : : #include "postgres.h"
23 : :
24 : : #include "gramparse.h"
25 : : #include "mb/pg_wchar.h"
26 : : #include "parser/parser.h"
27 : : #include "parser/scansup.h"
28 : :
29 : : static bool check_uescapechar(unsigned char escape);
30 : : static char *str_udeescape(const char *str, char escape,
31 : : int position, core_yyscan_t yyscanner);
32 : :
33 : :
34 : : /*
35 : : * raw_parser
36 : : * Given a query in string form, do lexical and grammatical analysis.
37 : : *
38 : : * Returns a list of raw (un-analyzed) parse trees. The contents of the
39 : : * list have the form required by the specified RawParseMode.
40 : : */
41 : : List *
42 : 71166 : raw_parser(const char *str, RawParseMode mode)
43 : : {
44 : 71166 : core_yyscan_t yyscanner;
45 : 71166 : base_yy_extra_type yyextra;
46 : 71166 : int yyresult;
47 : :
48 : : /* initialize the flex scanner */
49 : 71166 : yyscanner = scanner_init(str, &yyextra.core_yy_extra,
50 : : &ScanKeywords, ScanKeywordTokens);
51 : :
52 : : /* base_yylex() only needs us to initialize the lookahead token, if any */
53 [ + + ]: 71166 : if (mode == RAW_PARSE_DEFAULT)
54 : 66346 : yyextra.have_lookahead = false;
55 : : else
56 : : {
57 : : /* this array is indexed by RawParseMode enum */
58 : : static const int mode_token[] = {
59 : : [RAW_PARSE_DEFAULT] = 0,
60 : : [RAW_PARSE_TYPE_NAME] = MODE_TYPE_NAME,
61 : : [RAW_PARSE_PLPGSQL_EXPR] = MODE_PLPGSQL_EXPR,
62 : : [RAW_PARSE_PLPGSQL_ASSIGN1] = MODE_PLPGSQL_ASSIGN1,
63 : : [RAW_PARSE_PLPGSQL_ASSIGN2] = MODE_PLPGSQL_ASSIGN2,
64 : : [RAW_PARSE_PLPGSQL_ASSIGN3] = MODE_PLPGSQL_ASSIGN3,
65 : : };
66 : :
67 : 4820 : yyextra.have_lookahead = true;
68 : 4820 : yyextra.lookahead_token = mode_token[mode];
69 : 4820 : yyextra.lookahead_yylloc = 0;
70 : 4820 : yyextra.lookahead_end = NULL;
71 : : }
72 : :
73 : : /* initialize the bison parser */
74 : 71166 : parser_init(&yyextra);
75 : :
76 : : /* Parse! */
77 : 71166 : yyresult = base_yyparse(yyscanner);
78 : :
79 : : /* Clean up (release memory) */
80 : 71166 : scanner_finish(yyscanner);
81 : :
82 [ - + ]: 71166 : if (yyresult) /* error */
83 : 0 : return NIL;
84 : :
85 : 71166 : return yyextra.parsetree;
86 : 71166 : }
87 : :
88 : :
89 : : /*
90 : : * Intermediate filter between parser and core lexer (core_yylex in scan.l).
91 : : *
92 : : * This filter is needed because in some cases the standard SQL grammar
93 : : * requires more than one token lookahead. We reduce these cases to one-token
94 : : * lookahead by replacing tokens here, in order to keep the grammar LALR(1).
95 : : *
96 : : * Using a filter is simpler than trying to recognize multiword tokens
97 : : * directly in scan.l, because we'd have to allow for comments between the
98 : : * words. Furthermore it's not clear how to do that without re-introducing
99 : : * scanner backtrack, which would cost more performance than this filter
100 : : * layer does.
101 : : *
102 : : * We also use this filter to convert UIDENT and USCONST sequences into
103 : : * plain IDENT and SCONST tokens. While that could be handled by additional
104 : : * productions in the main grammar, it's more efficient to do it like this.
105 : : *
106 : : * The filter also provides a convenient place to translate between
107 : : * the core_YYSTYPE and YYSTYPE representations (which are really the
108 : : * same thing anyway, but notationally they're different).
109 : : */
110 : : int
111 : 1627956 : base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner)
112 : : {
113 : 1627956 : base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
114 : 1627956 : int cur_token;
115 : 1627956 : int next_token;
116 : 1627956 : int cur_token_length;
117 : 1627956 : YYLTYPE cur_yylloc;
118 : :
119 : : /* Get next token --- we might already have it */
120 [ + + ]: 1627956 : if (yyextra->have_lookahead)
121 : : {
122 : 11190 : cur_token = yyextra->lookahead_token;
123 : 11190 : lvalp->core_yystype = yyextra->lookahead_yylval;
124 : 11190 : *llocp = yyextra->lookahead_yylloc;
125 [ + + ]: 11190 : if (yyextra->lookahead_end)
126 : 6217 : *(yyextra->lookahead_end) = yyextra->lookahead_hold_char;
127 : 11190 : yyextra->have_lookahead = false;
128 : 11190 : }
129 : : else
130 : 1616766 : cur_token = core_yylex(&(lvalp->core_yystype), llocp, yyscanner);
131 : :
132 : : /*
133 : : * If this token isn't one that requires lookahead, just return it. If it
134 : : * does, determine the token length. (We could get that via strlen(), but
135 : : * since we have such a small set of possibilities, hardwiring seems
136 : : * feasible and more efficient --- at least for the fixed-length cases.)
137 : : */
138 [ + + + + : 1627956 : switch (cur_token)
+ + + ]
139 : : {
140 : : case FORMAT:
141 : 428 : cur_token_length = 6;
142 : 428 : break;
143 : : case NOT:
144 : 3769 : cur_token_length = 3;
145 : 3769 : break;
146 : : case NULLS_P:
147 : 122 : cur_token_length = 5;
148 : 122 : break;
149 : : case WITH:
150 : 1616 : cur_token_length = 4;
151 : 1616 : break;
152 : : case UIDENT:
153 : : case USCONST:
154 : 89 : cur_token_length = strlen(yyextra->core_yy_extra.scanbuf + *llocp);
155 : 89 : break;
156 : : case WITHOUT:
157 : 211 : cur_token_length = 7;
158 : 211 : break;
159 : : default:
160 : 1621721 : return cur_token;
161 : : }
162 : :
163 : : /*
164 : : * Identify end+1 of current token. core_yylex() has temporarily stored a
165 : : * '\0' here, and will undo that when we call it again. We need to redo
166 : : * it to fully revert the lookahead call for error reporting purposes.
167 : : */
168 : 18705 : yyextra->lookahead_end = yyextra->core_yy_extra.scanbuf +
169 : 12470 : *llocp + cur_token_length;
170 [ + - ]: 6235 : Assert(*(yyextra->lookahead_end) == '\0');
171 : :
172 : : /*
173 : : * Save and restore *llocp around the call. It might look like we could
174 : : * avoid this by just passing &lookahead_yylloc to core_yylex(), but that
175 : : * does not work because flex actually holds onto the last-passed pointer
176 : : * internally, and will use that for error reporting. We need any error
177 : : * reports to point to the current token, not the next one.
178 : : */
179 : 6235 : cur_yylloc = *llocp;
180 : :
181 : : /* Get next token, saving outputs into lookahead variables */
182 : 6235 : next_token = core_yylex(&(yyextra->lookahead_yylval), llocp, yyscanner);
183 : 6235 : yyextra->lookahead_token = next_token;
184 : 6235 : yyextra->lookahead_yylloc = *llocp;
185 : :
186 : 6235 : *llocp = cur_yylloc;
187 : :
188 : : /* Now revert the un-truncation of the current token */
189 : 6235 : yyextra->lookahead_hold_char = *(yyextra->lookahead_end);
190 : 6235 : *(yyextra->lookahead_end) = '\0';
191 : :
192 : 6235 : yyextra->have_lookahead = true;
193 : :
194 : : /* Replace cur_token if needed, based on lookahead */
195 [ + + + + : 6235 : switch (cur_token)
+ + + ]
196 : : {
197 : : case FORMAT:
198 : : /* Replace FORMAT by FORMAT_LA if it's followed by JSON */
199 [ + + ]: 428 : switch (next_token)
200 : : {
201 : : case JSON:
202 : 101 : cur_token = FORMAT_LA;
203 : 101 : break;
204 : : }
205 : 428 : break;
206 : :
207 : : case NOT:
208 : : /* Replace NOT by NOT_LA if it's followed by BETWEEN, IN, etc */
209 [ + + ]: 3769 : switch (next_token)
210 : : {
211 : : case BETWEEN:
212 : : case IN_P:
213 : : case LIKE:
214 : : case ILIKE:
215 : : case SIMILAR:
216 : 129 : cur_token = NOT_LA;
217 : 129 : break;
218 : : }
219 : 3769 : break;
220 : :
221 : : case NULLS_P:
222 : : /* Replace NULLS_P by NULLS_LA if it's followed by FIRST or LAST */
223 [ + + ]: 122 : switch (next_token)
224 : : {
225 : : case FIRST_P:
226 : : case LAST_P:
227 : 64 : cur_token = NULLS_LA;
228 : 64 : break;
229 : : }
230 : 122 : break;
231 : :
232 : : case WITH:
233 : : /* Replace WITH by WITH_LA if it's followed by TIME or ORDINALITY */
234 [ + + ]: 1616 : switch (next_token)
235 : : {
236 : : case TIME:
237 : : case ORDINALITY:
238 : 298 : cur_token = WITH_LA;
239 : 298 : break;
240 : : }
241 : 1616 : break;
242 : :
243 : : case WITHOUT:
244 : : /* Replace WITHOUT by WITHOUT_LA if it's followed by TIME */
245 [ + + ]: 211 : switch (next_token)
246 : : {
247 : : case TIME:
248 : 88 : cur_token = WITHOUT_LA;
249 : 88 : break;
250 : : }
251 : 211 : break;
252 : :
253 : : case UIDENT:
254 : : case USCONST:
255 : : /* Look ahead for UESCAPE */
256 [ + + ]: 81 : if (next_token == UESCAPE)
257 : : {
258 : : /* Yup, so get third token, which had better be SCONST */
259 : 6 : const char *escstr;
260 : :
261 : : /* Again save and restore *llocp */
262 : 6 : cur_yylloc = *llocp;
263 : :
264 : : /* Un-truncate current token so errors point to third token */
265 : 6 : *(yyextra->lookahead_end) = yyextra->lookahead_hold_char;
266 : :
267 : : /* Get third token */
268 : 12 : next_token = core_yylex(&(yyextra->lookahead_yylval),
269 : 6 : llocp, yyscanner);
270 : :
271 : : /* If we throw error here, it will point to third token */
272 [ + + ]: 6 : if (next_token != SCONST)
273 : 1 : scanner_yyerror("UESCAPE must be followed by a simple string literal",
274 : 1 : yyscanner);
275 : :
276 : 5 : escstr = yyextra->lookahead_yylval.str;
277 [ + + ]: 5 : if (strlen(escstr) != 1 || !check_uescapechar(escstr[0]))
278 : 1 : scanner_yyerror("invalid Unicode escape character",
279 : 1 : yyscanner);
280 : :
281 : : /* Now restore *llocp; errors will point to first token */
282 : 4 : *llocp = cur_yylloc;
283 : :
284 : : /* Apply Unicode conversion */
285 : 4 : lvalp->core_yystype.str =
286 : 8 : str_udeescape(lvalp->core_yystype.str,
287 : 4 : escstr[0],
288 : 4 : *llocp,
289 : 4 : yyscanner);
290 : :
291 : : /*
292 : : * We don't need to revert the un-truncation of UESCAPE. What
293 : : * we do want to do is clear have_lookahead, thereby consuming
294 : : * all three tokens.
295 : : */
296 : 4 : yyextra->have_lookahead = false;
297 : 4 : }
298 : : else
299 : : {
300 : : /* No UESCAPE, so convert using default escape character */
301 : 75 : lvalp->core_yystype.str =
302 : 150 : str_udeescape(lvalp->core_yystype.str,
303 : : '\\',
304 : 75 : *llocp,
305 : 75 : yyscanner);
306 : : }
307 : :
308 [ + + ]: 79 : if (cur_token == UIDENT)
309 : : {
310 : : /* It's an identifier, so truncate as appropriate */
311 : 6 : truncate_identifier(lvalp->core_yystype.str,
312 : 3 : strlen(lvalp->core_yystype.str),
313 : : true);
314 : 3 : cur_token = IDENT;
315 : 3 : }
316 [ - + ]: 76 : else if (cur_token == USCONST)
317 : : {
318 : 76 : cur_token = SCONST;
319 : 76 : }
320 : 79 : break;
321 : : }
322 : :
323 : 6233 : return cur_token;
324 : 1627954 : }
325 : :
326 : : /* convert hex digit (caller should have verified that) to value */
327 : : static unsigned int
328 : 488 : hexval(unsigned char c)
329 : : {
330 [ + - + + ]: 488 : if (c >= '0' && c <= '9')
331 : 415 : return c - '0';
332 [ + + - + ]: 73 : if (c >= 'a' && c <= 'f')
333 : 11 : return c - 'a' + 0xA;
334 [ + - ]: 62 : if (c >= 'A' && c <= 'F')
335 : 62 : return c - 'A' + 0xA;
336 [ # # # # ]: 0 : elog(ERROR, "invalid hexadecimal digit");
337 : 0 : return 0; /* not reached */
338 : 488 : }
339 : :
340 : : /* is Unicode code point acceptable? */
341 : : static void
342 : 119 : check_unicode_value(char32_t c)
343 : : {
344 [ + + ]: 119 : if (!is_valid_unicode_codepoint(c))
345 [ + - + - ]: 1 : ereport(ERROR,
346 : : (errcode(ERRCODE_SYNTAX_ERROR),
347 : : errmsg("invalid Unicode escape value")));
348 : 118 : }
349 : :
350 : : /* is 'escape' acceptable as Unicode escape character (UESCAPE syntax) ? */
351 : : static bool
352 : 5 : check_uescapechar(unsigned char escape)
353 : : {
354 : 5 : if (isxdigit(escape)
355 [ + - ]: 5 : || escape == '+'
356 [ + + ]: 5 : || escape == '\''
357 [ + - ]: 4 : || escape == '"'
358 [ + - - + ]: 4 : || scanner_isspace(escape))
359 : 1 : return false;
360 : : else
361 : 4 : return true;
362 : 5 : }
363 : :
364 : : /*
365 : : * Process Unicode escapes in "str", producing a palloc'd plain string
366 : : *
367 : : * escape: the escape character to use
368 : : * position: start position of U&'' or U&"" string token
369 : : * yyscanner: context information needed for error reports
370 : : */
371 : : static char *
372 : 87 : str_udeescape(const char *str, char escape,
373 : : int position, core_yyscan_t yyscanner)
374 : : {
375 : 87 : const char *in;
376 : 87 : char *new,
377 : : *out;
378 : 87 : size_t new_len;
379 : 87 : char16_t pair_first = 0;
380 : 87 : ScannerCallbackState scbstate;
381 : :
382 : : /*
383 : : * Guesstimate that result will be no longer than input, but allow enough
384 : : * padding for Unicode conversion.
385 : : */
386 : 87 : new_len = strlen(str) + MAX_UNICODE_EQUIVALENT_STRING + 1;
387 : 87 : new = palloc(new_len);
388 : :
389 : 87 : in = str;
390 : 87 : out = new;
391 [ + + ]: 436 : while (*in)
392 : : {
393 : : /* Enlarge string if needed */
394 : 356 : size_t out_dist = out - new;
395 : :
396 [ + - ]: 356 : if (out_dist > new_len - (MAX_UNICODE_EQUIVALENT_STRING + 1))
397 : : {
398 : 0 : new_len *= 2;
399 : 0 : new = repalloc(new, new_len);
400 : 0 : out = new + out_dist;
401 : 0 : }
402 : :
403 [ + + ]: 356 : if (in[0] == escape)
404 : : {
405 : : /*
406 : : * Any errors reported while processing this escape sequence will
407 : : * have an error cursor pointing at the escape.
408 : : */
409 : 244 : setup_scanner_errposition_callback(&scbstate, yyscanner,
410 : 122 : in - str + position + 3); /* 3 for U&" */
411 [ + + ]: 122 : if (in[1] == escape)
412 : : {
413 [ + + ]: 2 : if (pair_first)
414 : 1 : goto invalid_pair;
415 : 1 : *out++ = escape;
416 : 1 : in += 2;
417 : 1 : }
418 [ + + ]: 120 : else if (isxdigit((unsigned char) in[1]) &&
419 [ + - ]: 114 : isxdigit((unsigned char) in[2]) &&
420 [ + - + + ]: 114 : isxdigit((unsigned char) in[3]) &&
421 : 114 : isxdigit((unsigned char) in[4]))
422 : : {
423 : 113 : char32_t unicode;
424 : :
425 : 339 : unicode = (hexval(in[1]) << 12) +
426 : 226 : (hexval(in[2]) << 8) +
427 : 226 : (hexval(in[3]) << 4) +
428 : 113 : hexval(in[4]);
429 : 113 : check_unicode_value(unicode);
430 [ + + ]: 113 : if (pair_first)
431 : : {
432 [ - + ]: 1 : if (is_utf16_surrogate_second(unicode))
433 : : {
434 : 0 : unicode = surrogate_pair_to_codepoint(pair_first, unicode);
435 : 0 : pair_first = 0;
436 : 0 : }
437 : : else
438 : 1 : goto invalid_pair;
439 : 0 : }
440 [ - + ]: 112 : else if (is_utf16_surrogate_second(unicode))
441 : 0 : goto invalid_pair;
442 : :
443 [ + + ]: 112 : if (is_utf16_surrogate_first(unicode))
444 : 4 : pair_first = unicode;
445 : : else
446 : : {
447 : 108 : pg_unicode_to_server(unicode, (unsigned char *) out);
448 : 108 : out += strlen(out);
449 : : }
450 : 112 : in += 5;
451 [ + + ]: 113 : }
452 [ + + ]: 7 : else if (in[1] == '+' &&
453 : 5 : isxdigit((unsigned char) in[2]) &&
454 : 5 : isxdigit((unsigned char) in[3]) &&
455 : 5 : isxdigit((unsigned char) in[4]) &&
456 : 5 : isxdigit((unsigned char) in[5]) &&
457 : 5 : isxdigit((unsigned char) in[6]) &&
458 : 5 : isxdigit((unsigned char) in[7]))
459 : : {
460 : 5 : char32_t unicode;
461 : :
462 : 15 : unicode = (hexval(in[2]) << 20) +
463 : 10 : (hexval(in[3]) << 16) +
464 : 10 : (hexval(in[4]) << 12) +
465 : 10 : (hexval(in[5]) << 8) +
466 : 10 : (hexval(in[6]) << 4) +
467 : 5 : hexval(in[7]);
468 : 5 : check_unicode_value(unicode);
469 [ + + ]: 5 : if (pair_first)
470 : : {
471 [ - + ]: 1 : if (is_utf16_surrogate_second(unicode))
472 : : {
473 : 0 : unicode = surrogate_pair_to_codepoint(pair_first, unicode);
474 : 0 : pair_first = 0;
475 : 0 : }
476 : : else
477 : 1 : goto invalid_pair;
478 : 0 : }
479 [ - + ]: 4 : else if (is_utf16_surrogate_second(unicode))
480 : 0 : goto invalid_pair;
481 : :
482 [ + + ]: 4 : if (is_utf16_surrogate_first(unicode))
483 : 1 : pair_first = unicode;
484 : : else
485 : : {
486 : 3 : pg_unicode_to_server(unicode, (unsigned char *) out);
487 : 3 : out += strlen(out);
488 : : }
489 : 4 : in += 8;
490 [ + + ]: 5 : }
491 : : else
492 [ + - + - ]: 2 : ereport(ERROR,
493 : : (errcode(ERRCODE_SYNTAX_ERROR),
494 : : errmsg("invalid Unicode escape"),
495 : : errhint("Unicode escapes must be \\XXXX or \\+XXXXXX.")));
496 : :
497 : 117 : cancel_scanner_errposition_callback(&scbstate);
498 : 117 : }
499 : : else
500 : : {
501 [ + + ]: 234 : if (pair_first)
502 : 1 : goto invalid_pair;
503 : :
504 : 233 : *out++ = *in++;
505 : : }
506 [ + + + ]: 354 : }
507 : :
508 : : /* unfinished surrogate pair? */
509 [ + + ]: 80 : if (pair_first)
510 : 1 : goto invalid_pair;
511 : :
512 : 79 : *out = '\0';
513 : 79 : return new;
514 : :
515 : : /*
516 : : * We might get here with the error callback active, or not. Call
517 : : * scanner_errposition to make sure an error cursor appears; if the
518 : : * callback is active, this is duplicative but harmless.
519 : : */
520 : : invalid_pair:
521 [ + - + - ]: 5 : ereport(ERROR,
522 : : (errcode(ERRCODE_SYNTAX_ERROR),
523 : : errmsg("invalid Unicode surrogate pair"),
524 : : scanner_errposition(in - str + position + 3, /* 3 for U&" */
525 : : yyscanner)));
526 : 0 : return NULL; /* keep compiler quiet */
527 : 80 : }
|