Age Owner Branch data TLA 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-2025, 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 *
1706 tgl@sss.pgh.pa.us 42 :GIC 382579 : raw_parser(const char *str, RawParseMode mode)
43 : : {
44 : : core_yyscan_t yyscanner;
45 : : base_yy_extra_type yyextra;
46 : : int yyresult;
47 : :
48 : : /* initialize the flex scanner */
5780 49 : 382579 : 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 */
1706 53 [ + + ]: 382579 : if (mode == RAW_PARSE_DEFAULT)
54 : 356946 : 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 : 25633 : yyextra.have_lookahead = true;
68 : 25633 : yyextra.lookahead_token = mode_token[mode];
69 : 25633 : yyextra.lookahead_yylloc = 0;
70 : 25633 : yyextra.lookahead_end = NULL;
71 : : }
72 : :
73 : : /* initialize the bison parser */
5899 74 : 382579 : parser_init(&yyextra);
75 : :
76 : : /* Parse! */
77 : 382579 : yyresult = base_yyparse(yyscanner);
78 : :
79 : : /* Clean up (release memory) */
80 : 381963 : scanner_finish(yyscanner);
81 : :
10054 bruce@momjian.us 82 [ - + ]: 381963 : if (yyresult) /* error */
9100 tgl@sss.pgh.pa.us 83 :UIC 0 : return NIL;
84 : :
5899 tgl@sss.pgh.pa.us 85 :GIC 381963 : return yyextra.parsetree;
86 : : }
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
5780 111 : 9849920 : base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner)
112 : : {
5899 113 : 9849920 : base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
114 : : int cur_token;
115 : : int next_token;
116 : : int cur_token_length;
117 : : YYLTYPE cur_yylloc;
118 : :
119 : : /* Get next token --- we might already have it */
120 [ + + ]: 9849920 : if (yyextra->have_lookahead)
121 : : {
122 : 61769 : cur_token = yyextra->lookahead_token;
5780 123 : 61769 : lvalp->core_yystype = yyextra->lookahead_yylval;
5899 124 : 61769 : *llocp = yyextra->lookahead_yylloc;
1706 125 [ + + ]: 61769 : if (yyextra->lookahead_end)
126 : 36136 : *(yyextra->lookahead_end) = yyextra->lookahead_hold_char;
5899 127 : 61769 : yyextra->have_lookahead = false;
128 : : }
129 : : else
5780 130 : 9788151 : 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 : : */
7042 138 [ + + + + : 9849797 : switch (cur_token)
+ + + ]
139 : : {
892 alvherre@alvh.no-ip. 140 : 1599 : case FORMAT:
141 : 1599 : cur_token_length = 6;
142 : 1599 : break;
3832 tgl@sss.pgh.pa.us 143 : 21814 : case NOT:
144 : 21814 : cur_token_length = 3;
145 : 21814 : break;
6815 146 : 1136 : case NULLS_P:
3847 147 : 1136 : cur_token_length = 5;
148 : 1136 : break;
149 : 10626 : case WITH:
150 : 10626 : cur_token_length = 4;
151 : 10626 : break;
2063 152 : 277 : case UIDENT:
153 : : case USCONST:
154 : 277 : cur_token_length = strlen(yyextra->core_yy_extra.scanbuf + *llocp);
155 : 277 : break;
892 alvherre@alvh.no-ip. 156 : 744 : case WITHOUT:
157 : 744 : cur_token_length = 7;
158 : 744 : break;
3847 tgl@sss.pgh.pa.us 159 : 9813601 : default:
160 : 9813601 : 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 : 36196 : yyextra->lookahead_end = yyextra->core_yy_extra.scanbuf +
169 : 36196 : *llocp + cur_token_length;
170 [ - + ]: 36196 : 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 : 36196 : cur_yylloc = *llocp;
180 : :
181 : : /* Get next token, saving outputs into lookahead variables */
182 : 36196 : next_token = core_yylex(&(yyextra->lookahead_yylval), llocp, yyscanner);
183 : 36196 : yyextra->lookahead_token = next_token;
184 : 36196 : yyextra->lookahead_yylloc = *llocp;
185 : :
186 : 36196 : *llocp = cur_yylloc;
187 : :
188 : : /* Now revert the un-truncation of the current token */
189 : 36196 : yyextra->lookahead_hold_char = *(yyextra->lookahead_end);
190 : 36196 : *(yyextra->lookahead_end) = '\0';
191 : :
192 : 36196 : yyextra->have_lookahead = true;
193 : :
194 : : /* Replace cur_token if needed, based on lookahead */
195 [ + + + + : 36196 : switch (cur_token)
+ + - ]
196 : : {
892 alvherre@alvh.no-ip. 197 : 1599 : case FORMAT:
198 : : /* Replace FORMAT by FORMAT_LA if it's followed by JSON */
199 [ + + ]: 1599 : switch (next_token)
200 : : {
201 : 325 : case JSON:
202 : 325 : cur_token = FORMAT_LA;
203 : 325 : break;
204 : : }
205 : 1599 : break;
206 : :
3832 tgl@sss.pgh.pa.us 207 : 21814 : case NOT:
208 : : /* Replace NOT by NOT_LA if it's followed by BETWEEN, IN, etc */
209 [ + + ]: 21814 : switch (next_token)
210 : : {
211 : 1589 : case BETWEEN:
212 : : case IN_P:
213 : : case LIKE:
214 : : case ILIKE:
215 : : case SIMILAR:
216 : 1589 : cur_token = NOT_LA;
217 : 1589 : break;
218 : : }
219 : 21814 : break;
220 : :
3847 221 : 1136 : case NULLS_P:
222 : : /* Replace NULLS_P by NULLS_LA if it's followed by FIRST or LAST */
6815 223 [ + + ]: 1136 : switch (next_token)
224 : : {
225 : 1034 : case FIRST_P:
226 : : case LAST_P:
3847 227 : 1034 : cur_token = NULLS_LA;
6815 228 : 1034 : break;
229 : : }
230 : 1136 : break;
231 : :
232 : 10626 : case WITH:
233 : : /* Replace WITH by WITH_LA if it's followed by TIME or ORDINALITY */
6818 234 [ + + ]: 10626 : switch (next_token)
235 : : {
6157 peter_e@gmx.net 236 : 1426 : case TIME:
237 : : case ORDINALITY:
3847 tgl@sss.pgh.pa.us 238 : 1426 : cur_token = WITH_LA;
7042 239 : 1426 : break;
240 : : }
241 : 10626 : break;
242 : :
892 alvherre@alvh.no-ip. 243 : 744 : case WITHOUT:
244 : : /* Replace WITHOUT by WITHOUT_LA if it's followed by TIME */
245 [ + + ]: 744 : switch (next_token)
246 : : {
886 247 : 311 : case TIME:
892 248 : 311 : cur_token = WITHOUT_LA;
249 : 311 : break;
250 : : }
251 : 744 : break;
252 : :
2063 tgl@sss.pgh.pa.us 253 : 277 : case UIDENT:
254 : : case USCONST:
255 : : /* Look ahead for UESCAPE */
256 [ + + ]: 277 : if (next_token == UESCAPE)
257 : : {
258 : : /* Yup, so get third token, which had better be SCONST */
259 : : const char *escstr;
260 : :
261 : : /* Again save and restore *llocp */
262 : 22 : cur_yylloc = *llocp;
263 : :
264 : : /* Un-truncate current token so errors point to third token */
265 : 22 : *(yyextra->lookahead_end) = yyextra->lookahead_hold_char;
266 : :
267 : : /* Get third token */
268 : 22 : next_token = core_yylex(&(yyextra->lookahead_yylval),
269 : : llocp, yyscanner);
270 : :
271 : : /* If we throw error here, it will point to third token */
272 [ + + ]: 22 : if (next_token != SCONST)
273 : 3 : scanner_yyerror("UESCAPE must be followed by a simple string literal",
274 : : yyscanner);
275 : :
276 : 19 : escstr = yyextra->lookahead_yylval.str;
277 [ + - + + ]: 19 : if (strlen(escstr) != 1 || !check_uescapechar(escstr[0]))
278 : 3 : scanner_yyerror("invalid Unicode escape character",
279 : : yyscanner);
280 : :
281 : : /* Now restore *llocp; errors will point to first token */
282 : 16 : *llocp = cur_yylloc;
283 : :
284 : : /* Apply Unicode conversion */
285 : 16 : lvalp->core_yystype.str =
286 : 16 : str_udeescape(lvalp->core_yystype.str,
287 : 16 : escstr[0],
288 : : *llocp,
289 : : 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 : 16 : yyextra->have_lookahead = false;
297 : : }
298 : : else
299 : : {
300 : : /* No UESCAPE, so convert using default escape character */
301 : 231 : lvalp->core_yystype.str =
302 : 255 : str_udeescape(lvalp->core_yystype.str,
303 : : '\\',
304 : : *llocp,
305 : : yyscanner);
306 : : }
307 : :
308 [ + + ]: 247 : if (cur_token == UIDENT)
309 : : {
310 : : /* It's an identifier, so truncate as appropriate */
311 : 13 : truncate_identifier(lvalp->core_yystype.str,
312 : 13 : strlen(lvalp->core_yystype.str),
313 : : true);
314 : 13 : cur_token = IDENT;
315 : : }
316 [ + - ]: 234 : else if (cur_token == USCONST)
317 : : {
318 : 234 : cur_token = SCONST;
319 : : }
320 : 247 : break;
321 : : }
322 : :
7042 323 : 36166 : return cur_token;
324 : : }
325 : :
326 : : /* convert hex digit (caller should have verified that) to value */
327 : : static unsigned int
2063 328 : 1508 : hexval(unsigned char c)
329 : : {
330 [ + - + + ]: 1508 : if (c >= '0' && c <= '9')
331 : 1287 : return c - '0';
332 [ + + + - ]: 221 : if (c >= 'a' && c <= 'f')
333 : 33 : return c - 'a' + 0xA;
334 [ + - + - ]: 188 : if (c >= 'A' && c <= 'F')
335 : 188 : return c - 'A' + 0xA;
2063 tgl@sss.pgh.pa.us 336 [ # # ]:UIC 0 : elog(ERROR, "invalid hexadecimal digit");
337 : : return 0; /* not reached */
338 : : }
339 : :
340 : : /* is Unicode code point acceptable? */
341 : : static void
2010 tgl@sss.pgh.pa.us 342 :GIC 367 : check_unicode_value(pg_wchar c)
343 : : {
344 [ + + ]: 367 : if (!is_valid_unicode_codepoint(c))
2063 345 [ + - ]: 3 : ereport(ERROR,
346 : : (errcode(ERRCODE_SYNTAX_ERROR),
347 : : errmsg("invalid Unicode escape value")));
348 : 364 : }
349 : :
350 : : /* is 'escape' acceptable as Unicode escape character (UESCAPE syntax) ? */
351 : : static bool
352 : 19 : check_uescapechar(unsigned char escape)
353 : : {
354 [ + - ]: 19 : if (isxdigit(escape)
355 [ + + ]: 19 : || escape == '+'
356 [ + - ]: 16 : || escape == '\''
357 [ + - ]: 16 : || escape == '"'
358 [ - + ]: 16 : || scanner_isspace(escape))
359 : 3 : return false;
360 : : else
361 : 16 : return true;
362 : : }
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 : 271 : str_udeescape(const char *str, char escape,
373 : : int position, core_yyscan_t yyscanner)
374 : : {
375 : : const char *in;
376 : : char *new,
377 : : *out;
378 : : size_t new_len;
379 : 271 : pg_wchar pair_first = 0;
380 : : ScannerCallbackState scbstate;
381 : :
382 : : /*
383 : : * Guesstimate that result will be no longer than input, but allow enough
384 : : * padding for Unicode conversion.
385 : : */
2010 386 : 271 : new_len = strlen(str) + MAX_UNICODE_EQUIVALENT_STRING + 1;
387 : 271 : new = palloc(new_len);
388 : :
2063 389 : 271 : in = str;
390 : 271 : out = new;
391 [ + + ]: 1353 : while (*in)
392 : : {
393 : : /* Enlarge string if needed */
2010 394 : 1103 : size_t out_dist = out - new;
395 : :
396 [ - + ]: 1103 : if (out_dist > new_len - (MAX_UNICODE_EQUIVALENT_STRING + 1))
397 : : {
2010 tgl@sss.pgh.pa.us 398 :UIC 0 : new_len *= 2;
399 : 0 : new = repalloc(new, new_len);
400 : 0 : out = new + out_dist;
401 : : }
402 : :
2063 tgl@sss.pgh.pa.us 403 [ + + ]:GIC 1103 : 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 : : */
2010 409 : 379 : setup_scanner_errposition_callback(&scbstate, yyscanner,
410 : 379 : in - str + position + 3); /* 3 for U&" */
2063 411 [ + + ]: 379 : if (in[1] == escape)
412 : : {
413 [ + + ]: 6 : if (pair_first)
414 : 3 : goto invalid_pair;
415 : 3 : *out++ = escape;
416 : 3 : in += 2;
417 : : }
418 [ + + ]: 373 : else if (isxdigit((unsigned char) in[1]) &&
419 [ + - ]: 350 : isxdigit((unsigned char) in[2]) &&
420 [ + - ]: 350 : isxdigit((unsigned char) in[3]) &&
421 [ + + ]: 350 : isxdigit((unsigned char) in[4]))
422 : 344 : {
423 : : pg_wchar unicode;
424 : :
425 : 347 : unicode = (hexval(in[1]) << 12) +
426 : 347 : (hexval(in[2]) << 8) +
427 : 347 : (hexval(in[3]) << 4) +
428 : 347 : hexval(in[4]);
2010 429 : 347 : check_unicode_value(unicode);
2063 430 [ + + ]: 347 : if (pair_first)
431 : : {
432 [ - + ]: 3 : if (is_utf16_surrogate_second(unicode))
433 : : {
2063 tgl@sss.pgh.pa.us 434 :UIC 0 : unicode = surrogate_pair_to_codepoint(pair_first, unicode);
435 : 0 : pair_first = 0;
436 : : }
437 : : else
2063 tgl@sss.pgh.pa.us 438 :GIC 3 : goto invalid_pair;
439 : : }
440 [ - + ]: 344 : else if (is_utf16_surrogate_second(unicode))
2063 tgl@sss.pgh.pa.us 441 :UIC 0 : goto invalid_pair;
442 : :
2063 tgl@sss.pgh.pa.us 443 [ + + ]:GIC 344 : if (is_utf16_surrogate_first(unicode))
444 : 12 : pair_first = unicode;
445 : : else
446 : : {
2010 447 : 332 : pg_unicode_to_server(unicode, (unsigned char *) out);
448 : 332 : out += strlen(out);
449 : : }
2063 450 : 344 : in += 5;
451 : : }
452 [ + + ]: 26 : else if (in[1] == '+' &&
453 [ + - ]: 23 : isxdigit((unsigned char) in[2]) &&
454 [ + - ]: 23 : isxdigit((unsigned char) in[3]) &&
455 [ + - ]: 23 : isxdigit((unsigned char) in[4]) &&
456 [ + - ]: 23 : isxdigit((unsigned char) in[5]) &&
457 [ + + ]: 23 : isxdigit((unsigned char) in[6]) &&
458 [ + - ]: 20 : isxdigit((unsigned char) in[7]))
459 : 14 : {
460 : : pg_wchar unicode;
461 : :
462 : 20 : unicode = (hexval(in[2]) << 20) +
463 : 20 : (hexval(in[3]) << 16) +
464 : 20 : (hexval(in[4]) << 12) +
465 : 20 : (hexval(in[5]) << 8) +
466 : 20 : (hexval(in[6]) << 4) +
467 : 20 : hexval(in[7]);
2010 468 : 20 : check_unicode_value(unicode);
2063 469 [ + + ]: 17 : if (pair_first)
470 : : {
471 [ - + ]: 3 : if (is_utf16_surrogate_second(unicode))
472 : : {
2063 tgl@sss.pgh.pa.us 473 :UIC 0 : unicode = surrogate_pair_to_codepoint(pair_first, unicode);
474 : 0 : pair_first = 0;
475 : : }
476 : : else
2063 tgl@sss.pgh.pa.us 477 :GIC 3 : goto invalid_pair;
478 : : }
479 [ - + ]: 14 : else if (is_utf16_surrogate_second(unicode))
2063 tgl@sss.pgh.pa.us 480 :UIC 0 : goto invalid_pair;
481 : :
2063 tgl@sss.pgh.pa.us 482 [ + + ]:GIC 14 : if (is_utf16_surrogate_first(unicode))
483 : 3 : pair_first = unicode;
484 : : else
485 : : {
2010 486 : 11 : pg_unicode_to_server(unicode, (unsigned char *) out);
487 : 11 : out += strlen(out);
488 : : }
2063 489 : 14 : in += 8;
490 : : }
491 : : else
492 [ + - ]: 6 : ereport(ERROR,
493 : : (errcode(ERRCODE_SYNTAX_ERROR),
494 : : errmsg("invalid Unicode escape"),
495 : : errhint("Unicode escapes must be \\XXXX or \\+XXXXXX.")));
496 : :
2010 497 : 361 : cancel_scanner_errposition_callback(&scbstate);
498 : : }
499 : : else
500 : : {
2063 501 [ + + ]: 724 : if (pair_first)
502 : 3 : goto invalid_pair;
503 : :
504 : 721 : *out++ = *in++;
505 : : }
506 : : }
507 : :
508 : : /* unfinished surrogate pair? */
509 [ + + ]: 250 : if (pair_first)
510 : 3 : goto invalid_pair;
511 : :
512 : 247 : *out = '\0';
2010 513 : 247 : 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 : : */
2063 520 : 15 : invalid_pair:
521 [ + - ]: 15 : 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 : : return NULL; /* keep compiler quiet */
527 : : }
|