Age Owner Branch data TLA Line data Source code
1 : : %top{
2 : : /*-------------------------------------------------------------------------
3 : : *
4 : : * scan.l
5 : : * lexical scanner for PostgreSQL
6 : : *
7 : : * NOTE NOTE NOTE:
8 : : *
9 : : * The rules in this file must be kept in sync with src/fe_utils/psqlscan.l
10 : : * and src/interfaces/ecpg/preproc/pgc.l!
11 : : *
12 : : * The rules are designed so that the scanner never has to backtrack,
13 : : * in the sense that there is always a rule that can match the input
14 : : * consumed so far (the rule action may internally throw back some input
15 : : * with yyless(), however). As explained in the flex manual, this makes
16 : : * for a useful speed increase --- several percent faster when measuring
17 : : * raw parsing (Flex + Bison). The extra complexity is mostly in the rules
18 : : * for handling float numbers and continued string literals. If you change
19 : : * the lexical rules, verify that you haven't broken the no-backtrack
20 : : * property by running flex with the "-b" option and checking that the
21 : : * resulting "lex.backup" file says that no backing up is needed. (As of
22 : : * Postgres 9.2, this check is made automatically by the Makefile.)
23 : : *
24 : : *
25 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
26 : : * Portions Copyright (c) 1994, Regents of the University of California
27 : : *
28 : : * IDENTIFICATION
29 : : * src/backend/parser/scan.l
30 : : *
31 : : *-------------------------------------------------------------------------
32 : : */
33 : : #include "postgres.h"
34 : :
35 : : #include <ctype.h>
36 : : #include <unistd.h>
37 : :
38 : : #include "common/string.h"
39 : : #include "gramparse.h"
40 : : #include "nodes/miscnodes.h"
41 : : #include "parser/parser.h" /* only needed for GUC variables */
42 : : #include "parser/scansup.h"
43 : : #include "port/pg_bitutils.h"
44 : : #include "mb/pg_wchar.h"
45 : : #include "utils/builtins.h"
46 : : }
47 : :
48 : : %{
49 : :
50 : : /* LCOV_EXCL_START */
51 : :
52 : : /* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
53 : : #undef fprintf
54 : : #define fprintf(file, fmt, msg) fprintf_to_ereport(fmt, msg)
55 : :
56 : : static void
57 : : fprintf_to_ereport(const char *fmt, const char *msg)
58 : : {
59 : : ereport(ERROR, (errmsg_internal("%s", msg)));
60 : : }
61 : :
62 : : /*
63 : : * GUC variables. This is a DIRECT violation of the warning given at the
64 : : * head of gram.y, ie flex/bison code must not depend on any GUC variables;
65 : : * as such, changing their values can induce very unintuitive behavior.
66 : : * But we shall have to live with it until we can remove these variables.
67 : : */
68 : : int backslash_quote = BACKSLASH_QUOTE_SAFE_ENCODING;
69 : : bool escape_string_warning = true;
70 : : bool standard_conforming_strings = true;
71 : :
72 : : /*
73 : : * Constant data exported from this file. This array maps from the
74 : : * zero-based keyword numbers returned by ScanKeywordLookup to the
75 : : * Bison token numbers needed by gram.y. This is exported because
76 : : * callers need to pass it to scanner_init, if they are using the
77 : : * standard keyword list ScanKeywords.
78 : : */
79 : : #define PG_KEYWORD(kwname, value, category, collabel) value,
80 : :
81 : : const uint16 ScanKeywordTokens[] = {
82 : : #include "parser/kwlist.h"
83 : : };
84 : :
85 : : #undef PG_KEYWORD
86 : :
87 : : /*
88 : : * Set the type of YYSTYPE.
89 : : */
90 : : #define YYSTYPE core_YYSTYPE
91 : :
92 : : /*
93 : : * Set the type of yyextra. All state variables used by the scanner should
94 : : * be in yyextra, *not* statically allocated.
95 : : */
96 : : #define YY_EXTRA_TYPE core_yy_extra_type *
97 : :
98 : : /*
99 : : * Each call to yylex must set yylloc to the location of the found token
100 : : * (expressed as a byte offset from the start of the input text).
101 : : * When we parse a token that requires multiple lexer rules to process,
102 : : * this should be done in the first such rule, else yylloc will point
103 : : * into the middle of the token.
104 : : */
105 : : #define SET_YYLLOC() (*(yylloc) = yytext - yyextra->scanbuf)
106 : :
107 : : /*
108 : : * Advance yylloc by the given number of bytes.
109 : : */
110 : : #define ADVANCE_YYLLOC(delta) ( *(yylloc) += (delta) )
111 : :
112 : : /*
113 : : * Sometimes, we do want yylloc to point into the middle of a token; this is
114 : : * useful for instance to throw an error about an escape sequence within a
115 : : * string literal. But if we find no error there, we want to revert yylloc
116 : : * to the token start, so that that's the location reported to the parser.
117 : : * Use PUSH_YYLLOC/POP_YYLLOC to save/restore yylloc around such code.
118 : : * (Currently the implied "stack" is just one location, but someday we might
119 : : * need to nest these.)
120 : : */
121 : : #define PUSH_YYLLOC() (yyextra->save_yylloc = *(yylloc))
122 : : #define POP_YYLLOC() (*(yylloc) = yyextra->save_yylloc)
123 : :
124 : : #define startlit() ( yyextra->literallen = 0 )
125 : : static void addlit(char *ytext, int yleng, core_yyscan_t yyscanner);
126 : : static void addlitchar(unsigned char ychar, core_yyscan_t yyscanner);
127 : : static char *litbufdup(core_yyscan_t yyscanner);
128 : : static unsigned char unescape_single_char(unsigned char c, core_yyscan_t yyscanner);
129 : : static int process_integer_literal(const char *token, YYSTYPE *lval, int base);
130 : : static void addunicode(pg_wchar c, yyscan_t yyscanner);
131 : :
132 : : #define yyerror(msg) scanner_yyerror(msg, yyscanner)
133 : :
134 : : #define lexer_errposition() scanner_errposition(*(yylloc), yyscanner)
135 : :
136 : : static void check_string_escape_warning(unsigned char ychar, core_yyscan_t yyscanner);
137 : : static void check_escape_warning(core_yyscan_t yyscanner);
138 : :
139 : : /*
140 : : * Work around a bug in flex 2.5.35: it emits a couple of functions that
141 : : * it forgets to emit declarations for. Since we use -Wmissing-prototypes,
142 : : * this would cause warnings. Providing our own declarations should be
143 : : * harmless even when the bug gets fixed.
144 : : */
145 : : extern int core_yyget_column(yyscan_t yyscanner);
146 : : extern void core_yyset_column(int column_no, yyscan_t yyscanner);
147 : :
148 : : %}
149 : :
150 : : %option reentrant
151 : : %option bison-bridge
152 : : %option bison-locations
153 : : %option 8bit
154 : : %option never-interactive
155 : : %option nodefault
156 : : %option noinput
157 : : %option nounput
158 : : %option noyywrap
159 : : %option noyyalloc
160 : : %option noyyrealloc
161 : : %option noyyfree
162 : : %option warn
163 : : %option prefix="core_yy"
164 : :
165 : : /*
166 : : * OK, here is a short description of lex/flex rules behavior.
167 : : * The longest pattern which matches an input string is always chosen.
168 : : * For equal-length patterns, the first occurring in the rules list is chosen.
169 : : * INITIAL is the starting state, to which all non-conditional rules apply.
170 : : * Exclusive states change parsing rules while the state is active. When in
171 : : * an exclusive state, only those rules defined for that state apply.
172 : : *
173 : : * We use exclusive states for quoted strings, extended comments,
174 : : * and to eliminate parsing troubles for numeric strings.
175 : : * Exclusive states:
176 : : * <xb> bit string literal
177 : : * <xc> extended C-style comments
178 : : * <xd> delimited identifiers (double-quoted identifiers)
179 : : * <xh> hexadecimal byte string
180 : : * <xq> standard quoted strings
181 : : * <xqs> quote stop (detect continued strings)
182 : : * <xe> extended quoted strings (support backslash escape sequences)
183 : : * <xdolq> $foo$ quoted strings
184 : : * <xui> quoted identifier with Unicode escapes
185 : : * <xus> quoted string with Unicode escapes
186 : : * <xeu> Unicode surrogate pair in extended quoted string
187 : : *
188 : : * Remember to add an <<EOF>> case whenever you add a new exclusive state!
189 : : * The default one is probably not the right thing.
190 : : */
191 : :
192 : : %x xb
193 : : %x xc
194 : : %x xd
195 : : %x xh
196 : : %x xq
197 : : %x xqs
198 : : %x xe
199 : : %x xdolq
200 : : %x xui
201 : : %x xus
202 : : %x xeu
203 : :
204 : : /*
205 : : * In order to make the world safe for Windows and Mac clients as well as
206 : : * Unix ones, we accept either \n or \r as a newline. A DOS-style \r\n
207 : : * sequence will be seen as two successive newlines, but that doesn't cause
208 : : * any problems. Comments that start with -- and extend to the next
209 : : * newline are treated as equivalent to a single whitespace character.
210 : : *
211 : : * NOTE a fine point: if there is no newline following --, we will absorb
212 : : * everything to the end of the input as a comment. This is correct. Older
213 : : * versions of Postgres failed to recognize -- as a comment if the input
214 : : * did not end with a newline.
215 : : *
216 : : * non_newline_space tracks all the other space characters except newlines.
217 : : *
218 : : * XXX if you change the set of whitespace characters, fix scanner_isspace()
219 : : * to agree.
220 : : */
221 : :
222 : : space [ \t\n\r\f\v]
223 : : non_newline_space [ \t\f\v]
224 : : newline [\n\r]
225 : : non_newline [^\n\r]
226 : :
227 : : comment ("--"{non_newline}*)
228 : :
229 : : whitespace ({space}+|{comment})
230 : :
231 : : /*
232 : : * SQL requires at least one newline in the whitespace separating
233 : : * string literals that are to be concatenated. Silly, but who are we
234 : : * to argue? Note that {whitespace_with_newline} should not have * after
235 : : * it, whereas {whitespace} should generally have a * after it...
236 : : */
237 : :
238 : : special_whitespace ({space}+|{comment}{newline})
239 : : non_newline_whitespace ({non_newline_space}|{comment})
240 : : whitespace_with_newline ({non_newline_whitespace}*{newline}{special_whitespace}*)
241 : :
242 : : quote '
243 : : /* If we see {quote} then {quotecontinue}, the quoted string continues */
244 : : quotecontinue {whitespace_with_newline}{quote}
245 : :
246 : : /*
247 : : * {quotecontinuefail} is needed to avoid lexer backup when we fail to match
248 : : * {quotecontinue}. It might seem that this could just be {whitespace}*,
249 : : * but if there's a dash after {whitespace_with_newline}, it must be consumed
250 : : * to see if there's another dash --- which would start a {comment} and thus
251 : : * allow continuation of the {quotecontinue} token.
252 : : */
253 : : quotecontinuefail {whitespace}*"-"?
254 : :
255 : : /* Bit string
256 : : * It is tempting to scan the string for only those characters
257 : : * which are allowed. However, this leads to silently swallowed
258 : : * characters if illegal characters are included in the string.
259 : : * For example, if xbinside is [01] then B'ABCD' is interpreted
260 : : * as a zero-length string, and the ABCD' is lost!
261 : : * Better to pass the string forward and let the input routines
262 : : * validate the contents.
263 : : */
264 : : xbstart [bB]{quote}
265 : : xbinside [^']*
266 : :
267 : : /* Hexadecimal byte string */
268 : : xhstart [xX]{quote}
269 : : xhinside [^']*
270 : :
271 : : /* National character */
272 : : xnstart [nN]{quote}
273 : :
274 : : /* Quoted string that allows backslash escapes */
275 : : xestart [eE]{quote}
276 : : xeinside [^\\']+
277 : : xeescape [\\][^0-7]
278 : : xeoctesc [\\][0-7]{1,3}
279 : : xehexesc [\\]x[0-9A-Fa-f]{1,2}
280 : : xeunicode [\\](u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})
281 : : xeunicodefail [\\](u[0-9A-Fa-f]{0,3}|U[0-9A-Fa-f]{0,7})
282 : :
283 : : /* Extended quote
284 : : * xqdouble implements embedded quote, ''''
285 : : */
286 : : xqstart {quote}
287 : : xqdouble {quote}{quote}
288 : : xqinside [^']+
289 : :
290 : : /* $foo$ style quotes ("dollar quoting")
291 : : * The quoted string starts with $foo$ where "foo" is an optional string
292 : : * in the form of an identifier, except that it may not contain "$",
293 : : * and extends to the first occurrence of an identical string.
294 : : * There is *no* processing of the quoted text.
295 : : *
296 : : * {dolqfailed} is an error rule to avoid scanner backup when {dolqdelim}
297 : : * fails to match its trailing "$".
298 : : */
299 : : dolq_start [A-Za-z\200-\377_]
300 : : dolq_cont [A-Za-z\200-\377_0-9]
301 : : dolqdelim \$({dolq_start}{dolq_cont}*)?\$
302 : : dolqfailed \${dolq_start}{dolq_cont}*
303 : : dolqinside [^$]+
304 : :
305 : : /* Double quote
306 : : * Allows embedded spaces and other special characters into identifiers.
307 : : */
308 : : dquote \"
309 : : xdstart {dquote}
310 : : xdstop {dquote}
311 : : xddouble {dquote}{dquote}
312 : : xdinside [^"]+
313 : :
314 : : /* Quoted identifier with Unicode escapes */
315 : : xuistart [uU]&{dquote}
316 : :
317 : : /* Quoted string with Unicode escapes */
318 : : xusstart [uU]&{quote}
319 : :
320 : : /* error rule to avoid backup */
321 : : xufailed [uU]&
322 : :
323 : :
324 : : /* C-style comments
325 : : *
326 : : * The "extended comment" syntax closely resembles allowable operator syntax.
327 : : * The tricky part here is to get lex to recognize a string starting with
328 : : * slash-star as a comment, when interpreting it as an operator would produce
329 : : * a longer match --- remember lex will prefer a longer match! Also, if we
330 : : * have something like plus-slash-star, lex will think this is a 3-character
331 : : * operator whereas we want to see it as a + operator and a comment start.
332 : : * The solution is two-fold:
333 : : * 1. append {op_chars}* to xcstart so that it matches as much text as
334 : : * {operator} would. Then the tie-breaker (first matching rule of same
335 : : * length) ensures xcstart wins. We put back the extra stuff with yyless()
336 : : * in case it contains a star-slash that should terminate the comment.
337 : : * 2. In the operator rule, check for slash-star within the operator, and
338 : : * if found throw it back with yyless(). This handles the plus-slash-star
339 : : * problem.
340 : : * Dash-dash comments have similar interactions with the operator rule.
341 : : */
342 : : xcstart \/\*{op_chars}*
343 : : xcstop \*+\/
344 : : xcinside [^*/]+
345 : :
346 : : ident_start [A-Za-z\200-\377_]
347 : : ident_cont [A-Za-z\200-\377_0-9\$]
348 : :
349 : : identifier {ident_start}{ident_cont}*
350 : :
351 : : /* Assorted special-case operators and operator-like tokens */
352 : : typecast "::"
353 : : dot_dot \.\.
354 : : colon_equals ":="
355 : :
356 : : /*
357 : : * These operator-like tokens (unlike the above ones) also match the {operator}
358 : : * rule, which means that they might be overridden by a longer match if they
359 : : * are followed by a comment start or a + or - character. Accordingly, if you
360 : : * add to this list, you must also add corresponding code to the {operator}
361 : : * block to return the correct token in such cases. (This is not needed in
362 : : * psqlscan.l since the token value is ignored there.)
363 : : */
364 : : equals_greater "=>"
365 : : less_equals "<="
366 : : greater_equals ">="
367 : : less_greater "<>"
368 : : not_equals "!="
369 : :
370 : : /*
371 : : * "self" is the set of chars that should be returned as single-character
372 : : * tokens. "op_chars" is the set of chars that can make up "Op" tokens,
373 : : * which can be one or more characters long (but if a single-char token
374 : : * appears in the "self" set, it is not to be returned as an Op). Note
375 : : * that the sets overlap, but each has some chars that are not in the other.
376 : : *
377 : : * If you change either set, adjust the character lists appearing in the
378 : : * rule for "operator"!
379 : : */
380 : : self [,()\[\].;\:\+\-\*\/\%\^\<\>\=]
381 : : op_chars [\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
382 : : operator {op_chars}+
383 : :
384 : : /*
385 : : * Numbers
386 : : *
387 : : * Unary minus is not part of a number here. Instead we pass it separately to
388 : : * the parser, and there it gets coerced via doNegate().
389 : : *
390 : : * {numericfail} is used because we would like "1..10" to lex as 1, dot_dot, 10.
391 : : *
392 : : * {realfail} is added to prevent the need for scanner
393 : : * backup when the {real} rule fails to match completely.
394 : : */
395 : : decdigit [0-9]
396 : : hexdigit [0-9A-Fa-f]
397 : : octdigit [0-7]
398 : : bindigit [0-1]
399 : :
400 : : decinteger {decdigit}(_?{decdigit})*
401 : : hexinteger 0[xX](_?{hexdigit})+
402 : : octinteger 0[oO](_?{octdigit})+
403 : : bininteger 0[bB](_?{bindigit})+
404 : :
405 : : hexfail 0[xX]_?
406 : : octfail 0[oO]_?
407 : : binfail 0[bB]_?
408 : :
409 : : numeric (({decinteger}\.{decinteger}?)|(\.{decinteger}))
410 : : numericfail {decdigit}+\.\.
411 : :
412 : : real ({decinteger}|{numeric})[Ee][-+]?{decinteger}
413 : : realfail ({decinteger}|{numeric})[Ee][-+]
414 : :
415 : : decinteger_junk {decinteger}{ident_start}
416 : : hexinteger_junk {hexinteger}{ident_start}
417 : : octinteger_junk {octinteger}{ident_start}
418 : : bininteger_junk {bininteger}{ident_start}
419 : : numeric_junk {numeric}{ident_start}
420 : : real_junk {real}{ident_start}
421 : :
422 : : param \${decinteger}
423 : : param_junk \${decinteger}{ident_start}
424 : :
425 : : other .
426 : :
427 : : /*
428 : : * Dollar quoted strings are totally opaque, and no escaping is done on them.
429 : : * Other quoted strings must allow some special characters such as single-quote
430 : : * and newline.
431 : : * Embedded single-quotes are implemented both in the SQL standard
432 : : * style of two adjacent single quotes "''" and in the Postgres/Java style
433 : : * of escaped-quote "\'".
434 : : * Other embedded escaped characters are matched explicitly and the leading
435 : : * backslash is dropped from the string.
436 : : * Note that xcstart must appear before operator, as explained above!
437 : : * Also whitespace (comment) must appear before operator.
438 : : */
439 : :
440 : : %%
441 : :
442 : : {whitespace} {
443 : : /* ignore */
444 : : }
445 : :
446 : : {xcstart} {
447 : : /* Set location in case of syntax error in comment */
448 : : SET_YYLLOC();
449 : : yyextra->xcdepth = 0;
450 : : BEGIN(xc);
451 : : /* Put back any characters past slash-star; see above */
452 : : yyless(2);
453 : : }
454 : :
455 : : <xc>{
456 : : {xcstart} {
457 : : (yyextra->xcdepth)++;
458 : : /* Put back any characters past slash-star; see above */
459 : : yyless(2);
460 : : }
461 : :
462 : : {xcstop} {
463 : : if (yyextra->xcdepth <= 0)
464 : : BEGIN(INITIAL);
465 : : else
466 : : (yyextra->xcdepth)--;
467 : : }
468 : :
469 : : {xcinside} {
470 : : /* ignore */
471 : : }
472 : :
473 : : {op_chars} {
474 : : /* ignore */
475 : : }
476 : :
477 : : \*+ {
478 : : /* ignore */
479 : : }
480 : :
481 : : <<EOF>> {
482 : : yyerror("unterminated /* comment");
483 : : }
484 : : } /* <xc> */
485 : :
486 : : {xbstart} {
487 : : /* Binary bit type.
488 : : * At some point we should simply pass the string
489 : : * forward to the parser and label it there.
490 : : * In the meantime, place a leading "b" on the string
491 : : * to mark it for the input routine as a binary string.
492 : : */
493 : : SET_YYLLOC();
494 : : BEGIN(xb);
495 : : startlit();
496 : : addlitchar('b', yyscanner);
497 : : }
498 : : <xh>{xhinside} |
499 : : <xb>{xbinside} {
500 : : addlit(yytext, yyleng, yyscanner);
501 : : }
502 : : <xb><<EOF>> { yyerror("unterminated bit string literal"); }
503 : :
504 : : {xhstart} {
505 : : /* Hexadecimal bit type.
506 : : * At some point we should simply pass the string
507 : : * forward to the parser and label it there.
508 : : * In the meantime, place a leading "x" on the string
509 : : * to mark it for the input routine as a hex string.
510 : : */
511 : : SET_YYLLOC();
512 : : BEGIN(xh);
513 : : startlit();
514 : : addlitchar('x', yyscanner);
515 : : }
516 : : <xh><<EOF>> { yyerror("unterminated hexadecimal string literal"); }
517 : :
518 : : {xnstart} {
519 : : /* National character.
520 : : * We will pass this along as a normal character string,
521 : : * but preceded with an internally-generated "NCHAR".
522 : : */
523 : : int kwnum;
524 : :
525 : : SET_YYLLOC();
526 : : yyless(1); /* eat only 'n' this time */
527 : :
528 : : kwnum = ScanKeywordLookup("nchar",
529 : : yyextra->keywordlist);
530 : : if (kwnum >= 0)
531 : : {
532 : : yylval->keyword = GetScanKeyword(kwnum,
533 : : yyextra->keywordlist);
534 : : return yyextra->keyword_tokens[kwnum];
535 : : }
536 : : else
537 : : {
538 : : /* If NCHAR isn't a keyword, just return "n" */
539 : : yylval->str = pstrdup("n");
540 : : return IDENT;
541 : : }
542 : : }
543 : :
544 : : {xqstart} {
545 : : yyextra->warn_on_first_escape = true;
546 : : yyextra->saw_non_ascii = false;
547 : : SET_YYLLOC();
548 : : if (yyextra->standard_conforming_strings)
549 : : BEGIN(xq);
550 : : else
551 : : BEGIN(xe);
552 : : startlit();
553 : : }
554 : : {xestart} {
555 : : yyextra->warn_on_first_escape = false;
556 : : yyextra->saw_non_ascii = false;
557 : : SET_YYLLOC();
558 : : BEGIN(xe);
559 : : startlit();
560 : : }
561 : : {xusstart} {
562 : : SET_YYLLOC();
563 : : if (!yyextra->standard_conforming_strings)
564 : : ereport(ERROR,
565 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
566 : : errmsg("unsafe use of string constant with Unicode escapes"),
567 : : errdetail("String constants with Unicode escapes cannot be used when standard_conforming_strings is off."),
568 : : lexer_errposition()));
569 : : BEGIN(xus);
570 : : startlit();
571 : : }
572 : :
573 : : <xb,xh,xq,xe,xus>{quote} {
574 : : /*
575 : : * When we are scanning a quoted string and see an end
576 : : * quote, we must look ahead for a possible continuation.
577 : : * If we don't see one, we know the end quote was in fact
578 : : * the end of the string. To reduce the lexer table size,
579 : : * we use a single "xqs" state to do the lookahead for all
580 : : * types of strings.
581 : : */
582 : : yyextra->state_before_str_stop = YYSTATE;
583 : : BEGIN(xqs);
584 : : }
585 : : <xqs>{quotecontinue} {
586 : : /*
587 : : * Found a quote continuation, so return to the in-quote
588 : : * state and continue scanning the literal. Nothing is
589 : : * added to the literal's contents.
590 : : */
591 : : BEGIN(yyextra->state_before_str_stop);
592 : : }
593 : : <xqs>{quotecontinuefail} |
594 : : <xqs>{other} |
595 : : <xqs><<EOF>> {
596 : : /*
597 : : * Failed to see a quote continuation. Throw back
598 : : * everything after the end quote, and handle the string
599 : : * according to the state we were in previously.
600 : : */
601 : : yyless(0);
602 : : BEGIN(INITIAL);
603 : :
604 : : switch (yyextra->state_before_str_stop)
605 : : {
606 : : case xb:
607 : : yylval->str = litbufdup(yyscanner);
608 : : return BCONST;
609 : : case xh:
610 : : yylval->str = litbufdup(yyscanner);
611 : : return XCONST;
612 : : case xq:
613 : : case xe:
614 : : /*
615 : : * Check that the data remains valid, if it might
616 : : * have been made invalid by unescaping any chars.
617 : : */
618 : : if (yyextra->saw_non_ascii)
619 : : pg_verifymbstr(yyextra->literalbuf,
620 : : yyextra->literallen,
621 : : false);
622 : : yylval->str = litbufdup(yyscanner);
623 : : return SCONST;
624 : : case xus:
625 : : yylval->str = litbufdup(yyscanner);
626 : : return USCONST;
627 : : default:
628 : : yyerror("unhandled previous state in xqs");
629 : : }
630 : : }
631 : :
632 : : <xq,xe,xus>{xqdouble} {
633 : : addlitchar('\'', yyscanner);
634 : : }
635 : : <xq,xus>{xqinside} {
636 : : addlit(yytext, yyleng, yyscanner);
637 : : }
638 : : <xe>{xeinside} {
639 : : addlit(yytext, yyleng, yyscanner);
640 : : }
641 : : <xe>{xeunicode} {
642 : : pg_wchar c = strtoul(yytext + 2, NULL, 16);
643 : :
644 : : /*
645 : : * For consistency with other productions, issue any
646 : : * escape warning with cursor pointing to start of string.
647 : : * We might want to change that, someday.
648 : : */
649 : : check_escape_warning(yyscanner);
650 : :
651 : : /* Remember start of overall string token ... */
652 : : PUSH_YYLLOC();
653 : : /* ... and set the error cursor to point at this esc seq */
654 : : SET_YYLLOC();
655 : :
656 : : if (is_utf16_surrogate_first(c))
657 : : {
658 : : yyextra->utf16_first_part = c;
659 : : BEGIN(xeu);
660 : : }
661 : : else if (is_utf16_surrogate_second(c))
662 : : yyerror("invalid Unicode surrogate pair");
663 : : else
664 : : addunicode(c, yyscanner);
665 : :
666 : : /* Restore yylloc to be start of string token */
667 : : POP_YYLLOC();
668 : : }
669 : : <xeu>{xeunicode} {
670 : : pg_wchar c = strtoul(yytext + 2, NULL, 16);
671 : :
672 : : /* Remember start of overall string token ... */
673 : : PUSH_YYLLOC();
674 : : /* ... and set the error cursor to point at this esc seq */
675 : : SET_YYLLOC();
676 : :
677 : : if (!is_utf16_surrogate_second(c))
678 : : yyerror("invalid Unicode surrogate pair");
679 : :
680 : : c = surrogate_pair_to_codepoint(yyextra->utf16_first_part, c);
681 : :
682 : : addunicode(c, yyscanner);
683 : :
684 : : /* Restore yylloc to be start of string token */
685 : : POP_YYLLOC();
686 : :
687 : : BEGIN(xe);
688 : : }
689 : : <xeu>. |
690 : : <xeu>\n |
691 : : <xeu><<EOF>> {
692 : : /* Set the error cursor to point at missing esc seq */
693 : : SET_YYLLOC();
694 : : yyerror("invalid Unicode surrogate pair");
695 : : }
696 : : <xe,xeu>{xeunicodefail} {
697 : : /* Set the error cursor to point at malformed esc seq */
698 : : SET_YYLLOC();
699 : : ereport(ERROR,
700 : : (errcode(ERRCODE_INVALID_ESCAPE_SEQUENCE),
701 : : errmsg("invalid Unicode escape"),
702 : : errhint("Unicode escapes must be \\uXXXX or \\UXXXXXXXX."),
703 : : lexer_errposition()));
704 : : }
705 : : <xe>{xeescape} {
706 : : if (yytext[1] == '\'')
707 : : {
708 : : if (yyextra->backslash_quote == BACKSLASH_QUOTE_OFF ||
709 : : (yyextra->backslash_quote == BACKSLASH_QUOTE_SAFE_ENCODING &&
710 : : PG_ENCODING_IS_CLIENT_ONLY(pg_get_client_encoding())))
711 : : ereport(ERROR,
712 : : (errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
713 : : errmsg("unsafe use of \\' in a string literal"),
714 : : errhint("Use '' to write quotes in strings. \\' is insecure in client-only encodings."),
715 : : lexer_errposition()));
716 : : }
717 : : check_string_escape_warning(yytext[1], yyscanner);
718 : : addlitchar(unescape_single_char(yytext[1], yyscanner),
719 : : yyscanner);
720 : : }
721 : : <xe>{xeoctesc} {
722 : : unsigned char c = strtoul(yytext + 1, NULL, 8);
723 : :
724 : : check_escape_warning(yyscanner);
725 : : addlitchar(c, yyscanner);
726 : : if (c == '\0' || IS_HIGHBIT_SET(c))
727 : : yyextra->saw_non_ascii = true;
728 : : }
729 : : <xe>{xehexesc} {
730 : : unsigned char c = strtoul(yytext + 2, NULL, 16);
731 : :
732 : : check_escape_warning(yyscanner);
733 : : addlitchar(c, yyscanner);
734 : : if (c == '\0' || IS_HIGHBIT_SET(c))
735 : : yyextra->saw_non_ascii = true;
736 : : }
737 : : <xe>. {
738 : : /* This is only needed for \ just before EOF */
739 : : addlitchar(yytext[0], yyscanner);
740 : : }
741 : : <xq,xe,xus><<EOF>> { yyerror("unterminated quoted string"); }
742 : :
743 : : {dolqdelim} {
744 : : SET_YYLLOC();
745 : : yyextra->dolqstart = pstrdup(yytext);
746 : : BEGIN(xdolq);
747 : : startlit();
748 : : }
749 : : {dolqfailed} {
750 : : SET_YYLLOC();
751 : : /* throw back all but the initial "$" */
752 : : yyless(1);
753 : : /* and treat it as {other} */
754 : : return yytext[0];
755 : : }
756 : : <xdolq>{dolqdelim} {
757 : : if (strcmp(yytext, yyextra->dolqstart) == 0)
758 : : {
759 : : pfree(yyextra->dolqstart);
760 : : yyextra->dolqstart = NULL;
761 : : BEGIN(INITIAL);
762 : : yylval->str = litbufdup(yyscanner);
763 : : return SCONST;
764 : : }
765 : : else
766 : : {
767 : : /*
768 : : * When we fail to match $...$ to dolqstart, transfer
769 : : * the $... part to the output, but put back the final
770 : : * $ for rescanning. Consider $delim$...$junk$delim$
771 : : */
772 : : addlit(yytext, yyleng - 1, yyscanner);
773 : : yyless(yyleng - 1);
774 : : }
775 : : }
776 : : <xdolq>{dolqinside} {
777 : : addlit(yytext, yyleng, yyscanner);
778 : : }
779 : : <xdolq>{dolqfailed} {
780 : : addlit(yytext, yyleng, yyscanner);
781 : : }
782 : : <xdolq>. {
783 : : /* This is only needed for $ inside the quoted text */
784 : : addlitchar(yytext[0], yyscanner);
785 : : }
786 : : <xdolq><<EOF>> { yyerror("unterminated dollar-quoted string"); }
787 : :
788 : : {xdstart} {
789 : : SET_YYLLOC();
790 : : BEGIN(xd);
791 : : startlit();
792 : : }
793 : : {xuistart} {
794 : : SET_YYLLOC();
795 : : BEGIN(xui);
796 : : startlit();
797 : : }
798 : : <xd>{xdstop} {
799 : : char *ident;
800 : :
801 : : BEGIN(INITIAL);
802 : : if (yyextra->literallen == 0)
803 : : yyerror("zero-length delimited identifier");
804 : : ident = litbufdup(yyscanner);
805 : : if (yyextra->literallen >= NAMEDATALEN)
806 : : truncate_identifier(ident, yyextra->literallen, true);
807 : : yylval->str = ident;
808 : : return IDENT;
809 : : }
810 : : <xui>{dquote} {
811 : : BEGIN(INITIAL);
812 : : if (yyextra->literallen == 0)
813 : : yyerror("zero-length delimited identifier");
814 : : /* can't truncate till after we de-escape the ident */
815 : : yylval->str = litbufdup(yyscanner);
816 : : return UIDENT;
817 : : }
818 : : <xd,xui>{xddouble} {
819 : : addlitchar('"', yyscanner);
820 : : }
821 : : <xd,xui>{xdinside} {
822 : : addlit(yytext, yyleng, yyscanner);
823 : : }
824 : : <xd,xui><<EOF>> { yyerror("unterminated quoted identifier"); }
825 : :
826 : : {xufailed} {
827 : : char *ident;
828 : :
829 : : SET_YYLLOC();
830 : : /* throw back all but the initial u/U */
831 : : yyless(1);
832 : : /* and treat it as {identifier} */
833 : : ident = downcase_truncate_identifier(yytext, yyleng, true);
834 : : yylval->str = ident;
835 : : return IDENT;
836 : : }
837 : :
838 : : {typecast} {
839 : : SET_YYLLOC();
840 : : return TYPECAST;
841 : : }
842 : :
843 : : {dot_dot} {
844 : : SET_YYLLOC();
845 : : return DOT_DOT;
846 : : }
847 : :
848 : : {colon_equals} {
849 : : SET_YYLLOC();
850 : : return COLON_EQUALS;
851 : : }
852 : :
853 : : {equals_greater} {
854 : : SET_YYLLOC();
855 : : return EQUALS_GREATER;
856 : : }
857 : :
858 : : {less_equals} {
859 : : SET_YYLLOC();
860 : : return LESS_EQUALS;
861 : : }
862 : :
863 : : {greater_equals} {
864 : : SET_YYLLOC();
865 : : return GREATER_EQUALS;
866 : : }
867 : :
868 : : {less_greater} {
869 : : /* We accept both "<>" and "!=" as meaning NOT_EQUALS */
870 : : SET_YYLLOC();
871 : : return NOT_EQUALS;
872 : : }
873 : :
874 : : {not_equals} {
875 : : /* We accept both "<>" and "!=" as meaning NOT_EQUALS */
876 : : SET_YYLLOC();
877 : : return NOT_EQUALS;
878 : : }
879 : :
880 : : {self} {
881 : : SET_YYLLOC();
882 : : return yytext[0];
883 : : }
884 : :
885 : : {operator} {
886 : : /*
887 : : * Check for embedded slash-star or dash-dash; those
888 : : * are comment starts, so operator must stop there.
889 : : * Note that slash-star or dash-dash at the first
890 : : * character will match a prior rule, not this one.
891 : : */
892 : : int nchars = yyleng;
893 : : char *slashstar = strstr(yytext, "/*");
894 : : char *dashdash = strstr(yytext, "--");
895 : :
896 : : if (slashstar && dashdash)
897 : : {
898 : : /* if both appear, take the first one */
899 : : if (slashstar > dashdash)
900 : : slashstar = dashdash;
901 : : }
902 : : else if (!slashstar)
903 : : slashstar = dashdash;
904 : : if (slashstar)
905 : : nchars = slashstar - yytext;
906 : :
907 : : /*
908 : : * For SQL compatibility, '+' and '-' cannot be the
909 : : * last char of a multi-char operator unless the operator
910 : : * contains chars that are not in SQL operators.
911 : : * The idea is to lex '=-' as two operators, but not
912 : : * to forbid operator names like '?-' that could not be
913 : : * sequences of SQL operators.
914 : : */
915 : : if (nchars > 1 &&
916 : : (yytext[nchars - 1] == '+' ||
917 : : yytext[nchars - 1] == '-'))
918 : : {
919 : : int ic;
920 : :
921 : : for (ic = nchars - 2; ic >= 0; ic--)
922 : : {
923 : : char c = yytext[ic];
924 : : if (c == '~' || c == '!' || c == '@' ||
925 : : c == '#' || c == '^' || c == '&' ||
926 : : c == '|' || c == '`' || c == '?' ||
927 : : c == '%')
928 : : break;
929 : : }
930 : : if (ic < 0)
931 : : {
932 : : /*
933 : : * didn't find a qualifying character, so remove
934 : : * all trailing [+-]
935 : : */
936 : : do {
937 : : nchars--;
938 : : } while (nchars > 1 &&
939 : : (yytext[nchars - 1] == '+' ||
940 : : yytext[nchars - 1] == '-'));
941 : : }
942 : : }
943 : :
944 : : SET_YYLLOC();
945 : :
946 : : if (nchars < yyleng)
947 : : {
948 : : /* Strip the unwanted chars from the token */
949 : : yyless(nchars);
950 : : /*
951 : : * If what we have left is only one char, and it's
952 : : * one of the characters matching "self", then
953 : : * return it as a character token the same way
954 : : * that the "self" rule would have.
955 : : */
956 : : if (nchars == 1 &&
957 : : strchr(",()[].;:+-*/%^<>=", yytext[0]))
958 : : return yytext[0];
959 : : /*
960 : : * Likewise, if what we have left is two chars, and
961 : : * those match the tokens ">=", "<=", "=>", "<>" or
962 : : * "!=", then we must return the appropriate token
963 : : * rather than the generic Op.
964 : : */
965 : : if (nchars == 2)
966 : : {
967 : : if (yytext[0] == '=' && yytext[1] == '>')
968 : : return EQUALS_GREATER;
969 : : if (yytext[0] == '>' && yytext[1] == '=')
970 : : return GREATER_EQUALS;
971 : : if (yytext[0] == '<' && yytext[1] == '=')
972 : : return LESS_EQUALS;
973 : : if (yytext[0] == '<' && yytext[1] == '>')
974 : : return NOT_EQUALS;
975 : : if (yytext[0] == '!' && yytext[1] == '=')
976 : : return NOT_EQUALS;
977 : : }
978 : : }
979 : :
980 : : /*
981 : : * Complain if operator is too long. Unlike the case
982 : : * for identifiers, we make this an error not a notice-
983 : : * and-truncate, because the odds are we are looking at
984 : : * a syntactic mistake anyway.
985 : : */
986 : : if (nchars >= NAMEDATALEN)
987 : : yyerror("operator too long");
988 : :
989 : : yylval->str = pstrdup(yytext);
990 : : return Op;
991 : : }
992 : :
993 : : {param} {
994 : : SET_YYLLOC();
995 : : yylval->ival = atol(yytext + 1);
996 : : return PARAM;
997 : : }
998 : : {param_junk} {
999 : : SET_YYLLOC();
1000 : : yyerror("trailing junk after parameter");
1001 : : }
1002 : :
1003 : : {decinteger} {
1004 : : SET_YYLLOC();
1005 : : return process_integer_literal(yytext, yylval, 10);
1006 : : }
1007 : : {hexinteger} {
1008 : : SET_YYLLOC();
1009 : : return process_integer_literal(yytext, yylval, 16);
1010 : : }
1011 : : {octinteger} {
1012 : : SET_YYLLOC();
1013 : : return process_integer_literal(yytext, yylval, 8);
1014 : : }
1015 : : {bininteger} {
1016 : : SET_YYLLOC();
1017 : : return process_integer_literal(yytext, yylval, 2);
1018 : : }
1019 : : {hexfail} {
1020 : : SET_YYLLOC();
1021 : : yyerror("invalid hexadecimal integer");
1022 : : }
1023 : : {octfail} {
1024 : : SET_YYLLOC();
1025 : : yyerror("invalid octal integer");
1026 : : }
1027 : : {binfail} {
1028 : : SET_YYLLOC();
1029 : : yyerror("invalid binary integer");
1030 : : }
1031 : : {numeric} {
1032 : : SET_YYLLOC();
1033 : : yylval->str = pstrdup(yytext);
1034 : : return FCONST;
1035 : : }
1036 : : {numericfail} {
1037 : : /* throw back the .., and treat as integer */
1038 : : yyless(yyleng - 2);
1039 : : SET_YYLLOC();
1040 : : return process_integer_literal(yytext, yylval, 10);
1041 : : }
1042 : : {real} {
1043 : : SET_YYLLOC();
1044 : : yylval->str = pstrdup(yytext);
1045 : : return FCONST;
1046 : : }
1047 : : {realfail} {
1048 : : SET_YYLLOC();
1049 : : yyerror("trailing junk after numeric literal");
1050 : : }
1051 : : {decinteger_junk} {
1052 : : SET_YYLLOC();
1053 : : yyerror("trailing junk after numeric literal");
1054 : : }
1055 : : {hexinteger_junk} {
1056 : : SET_YYLLOC();
1057 : : yyerror("trailing junk after numeric literal");
1058 : : }
1059 : : {octinteger_junk} {
1060 : : SET_YYLLOC();
1061 : : yyerror("trailing junk after numeric literal");
1062 : : }
1063 : : {bininteger_junk} {
1064 : : SET_YYLLOC();
1065 : : yyerror("trailing junk after numeric literal");
1066 : : }
1067 : : {numeric_junk} {
1068 : : SET_YYLLOC();
1069 : : yyerror("trailing junk after numeric literal");
1070 : : }
1071 : : {real_junk} {
1072 : : SET_YYLLOC();
1073 : : yyerror("trailing junk after numeric literal");
1074 : : }
1075 : :
1076 : :
1077 : : {identifier} {
1078 : : int kwnum;
1079 : : char *ident;
1080 : :
1081 : : SET_YYLLOC();
1082 : :
1083 : : /* Is it a keyword? */
1084 : : kwnum = ScanKeywordLookup(yytext,
1085 : : yyextra->keywordlist);
1086 : : if (kwnum >= 0)
1087 : : {
1088 : : yylval->keyword = GetScanKeyword(kwnum,
1089 : : yyextra->keywordlist);
1090 : : return yyextra->keyword_tokens[kwnum];
1091 : : }
1092 : :
1093 : : /*
1094 : : * No. Convert the identifier to lower case, and truncate
1095 : : * if necessary.
1096 : : */
1097 : : ident = downcase_truncate_identifier(yytext, yyleng, true);
1098 : : yylval->str = ident;
1099 : : return IDENT;
1100 : : }
1101 : :
1102 : : {other} {
1103 : : SET_YYLLOC();
1104 : : return yytext[0];
1105 : : }
1106 : :
1107 : : <<EOF>> {
1108 : : SET_YYLLOC();
1109 : : yyterminate();
1110 : : }
1111 : :
1112 : : %%
1113 : :
1114 : : /* LCOV_EXCL_STOP */
1115 : :
1116 : : /*
1117 : : * Arrange access to yyextra for subroutines of the main yylex() function.
1118 : : * We expect each subroutine to have a yyscanner parameter. Rather than
1119 : : * use the yyget_xxx functions, which might or might not get inlined by the
1120 : : * compiler, we cheat just a bit and cast yyscanner to the right type.
1121 : : */
1122 : : #undef yyextra
1123 : : #define yyextra (((struct yyguts_t *) yyscanner)->yyextra_r)
1124 : :
1125 : : /* Likewise for a couple of other things we need. */
1126 : : #undef yylloc
1127 : : #define yylloc (((struct yyguts_t *) yyscanner)->yylloc_r)
1128 : : #undef yyleng
1129 : : #define yyleng (((struct yyguts_t *) yyscanner)->yyleng_r)
1130 : :
1131 : :
1132 : : /*
1133 : : * scanner_errposition
1134 : : * Report a lexer or grammar error cursor position, if possible.
1135 : : *
1136 : : * This is expected to be used within an ereport() call, or via an error
1137 : : * callback such as setup_scanner_errposition_callback(). The return value
1138 : : * is a dummy (always 0, in fact).
1139 : : *
1140 : : * Note that this can only be used for messages emitted during raw parsing
1141 : : * (essentially, scan.l, parser.c, and gram.y), since it requires the
1142 : : * yyscanner struct to still be available.
1143 : : */
1144 : : int
5270 tgl@sss.pgh.pa.us 1145 :CBC 597 : scanner_errposition(int location, core_yyscan_t yyscanner)
1146 : : {
1147 : : int pos;
1148 : :
5704 1149 [ - + ]: 597 : if (location < 0)
1481 tgl@sss.pgh.pa.us 1150 :UBC 0 : return 0; /* no-op if location is unknown */
1151 : :
1152 : : /* Convert byte offset to character number */
5389 tgl@sss.pgh.pa.us 1153 :CBC 597 : pos = pg_mbstrlen_with_len(yyextra->scanbuf, location) + 1;
1154 : : /* And pass it to the ereport mechanism */
1481 1155 : 597 : return errposition(pos);
1156 : : }
1157 : :
1158 : : /*
1159 : : * Error context callback for inserting scanner error location.
1160 : : *
1161 : : * Note that this will be called for *any* error occurring while the
1162 : : * callback is installed. We avoid inserting an irrelevant error location
1163 : : * if the error is a query cancel --- are there any other important cases?
1164 : : */
1165 : : static void
1500 1166 : 18 : scb_error_callback(void *arg)
1167 : : {
1168 : 18 : ScannerCallbackState *scbstate = (ScannerCallbackState *) arg;
1169 : :
1170 [ + - ]: 18 : if (geterrcode() != ERRCODE_QUERY_CANCELED)
1171 : 18 : (void) scanner_errposition(scbstate->location, scbstate->yyscanner);
1172 : 18 : }
1173 : :
1174 : : /*
1175 : : * setup_scanner_errposition_callback
1176 : : * Arrange for non-scanner errors to report an error position
1177 : : *
1178 : : * Sometimes the scanner calls functions that aren't part of the scanner
1179 : : * subsystem and can't reasonably be passed the yyscanner pointer; yet
1180 : : * we would like any errors thrown in those functions to be tagged with an
1181 : : * error location. Use this function to set up an error context stack
1182 : : * entry that will accomplish that. Usage pattern:
1183 : : *
1184 : : * declare a local variable "ScannerCallbackState scbstate"
1185 : : * ...
1186 : : * setup_scanner_errposition_callback(&scbstate, yyscanner, location);
1187 : : * call function that might throw error;
1188 : : * cancel_scanner_errposition_callback(&scbstate);
1189 : : */
1190 : : void
1191 : 271 : setup_scanner_errposition_callback(ScannerCallbackState *scbstate,
1192 : : core_yyscan_t yyscanner,
1193 : : int location)
1194 : : {
1195 : : /* Setup error traceback support for ereport() */
1196 : 271 : scbstate->yyscanner = yyscanner;
1197 : 271 : scbstate->location = location;
1198 : 271 : scbstate->errcallback.callback = scb_error_callback;
1199 : 271 : scbstate->errcallback.arg = (void *) scbstate;
1200 : 271 : scbstate->errcallback.previous = error_context_stack;
1201 : 271 : error_context_stack = &scbstate->errcallback;
1202 : 271 : }
1203 : :
1204 : : /*
1205 : : * Cancel a previously-set-up errposition callback.
1206 : : */
1207 : : void
1208 : 253 : cancel_scanner_errposition_callback(ScannerCallbackState *scbstate)
1209 : : {
1210 : : /* Pop the error context stack */
1211 : 253 : error_context_stack = scbstate->errcallback.previous;
1212 : 253 : }
1213 : :
1214 : : /*
1215 : : * scanner_yyerror
1216 : : * Report a lexer or grammar error.
1217 : : *
1218 : : * The message's cursor position is whatever YYLLOC was last set to,
1219 : : * ie, the start of the current token if called within yylex(), or the
1220 : : * most recently lexed token if called from the grammar.
1221 : : * This is OK for syntax error messages from the Bison parser, because Bison
1222 : : * parsers report error as soon as the first unparsable token is reached.
1223 : : * Beware of using yyerror for other purposes, as the cursor position might
1224 : : * be misleading!
1225 : : */
1226 : : void
5270 1227 : 440 : scanner_yyerror(const char *message, core_yyscan_t yyscanner)
1228 : : {
5389 1229 : 440 : const char *loc = yyextra->scanbuf + *yylloc;
1230 : :
7910 1231 [ + + ]: 440 : if (*loc == YY_END_OF_BUFFER_CHAR)
1232 : : {
7661 1233 [ + - ]: 9 : ereport(ERROR,
1234 : : (errcode(ERRCODE_SYNTAX_ERROR),
1235 : : /* translator: %s is typically the translation of "syntax error" */
1236 : : errmsg("%s at end of input", _(message)),
1237 : : lexer_errposition()));
1238 : : }
1239 : : else
1240 : : {
1241 [ + - ]: 431 : ereport(ERROR,
1242 : : (errcode(ERRCODE_SYNTAX_ERROR),
1243 : : /* translator: first %s is typically the translation of "syntax error" */
1244 : : errmsg("%s at or near \"%s\"", _(message), loc),
1245 : : lexer_errposition()));
1246 : : }
1247 : : }
1248 : :
1249 : :
1250 : : /*
1251 : : * Called before any actual parsing is done
1252 : : */
1253 : : core_yyscan_t
5388 1254 : 379811 : scanner_init(const char *str,
1255 : : core_yy_extra_type *yyext,
1256 : : const ScanKeywordList *keywordlist,
1257 : : const uint16 *keyword_tokens)
1258 : : {
5389 1259 : 379811 : Size slen = strlen(str);
1260 : : yyscan_t scanner;
1261 : :
1262 [ - + ]: 379811 : if (yylex_init(&scanner) != 0)
5389 tgl@sss.pgh.pa.us 1263 [ # # ]:UBC 0 : elog(ERROR, "yylex_init() failed: %m");
1264 : :
5270 tgl@sss.pgh.pa.us 1265 :CBC 379811 : core_yyset_extra(yyext, scanner);
1266 : :
1925 1267 : 379811 : yyext->keywordlist = keywordlist;
1268 : 379811 : yyext->keyword_tokens = keyword_tokens;
1269 : :
3370 1270 : 379811 : yyext->backslash_quote = backslash_quote;
1271 : 379811 : yyext->escape_string_warning = escape_string_warning;
1272 : 379811 : yyext->standard_conforming_strings = standard_conforming_strings;
1273 : :
1274 : : /*
1275 : : * Make a scan buffer with special termination needed by flex.
1276 : : */
5389 1277 : 379811 : yyext->scanbuf = (char *) palloc(slen + 2);
1278 : 379811 : yyext->scanbuflen = slen;
1279 : 379811 : memcpy(yyext->scanbuf, str, slen);
1280 : 379811 : yyext->scanbuf[slen] = yyext->scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
1281 : 379811 : yy_scan_buffer(yyext->scanbuf, slen + 2, scanner);
1282 : :
1283 : : /* initialize literal buffer to a reasonable but expansible size */
1284 : 379811 : yyext->literalalloc = 1024;
1285 : 379811 : yyext->literalbuf = (char *) palloc(yyext->literalalloc);
1286 : 379811 : yyext->literallen = 0;
1287 : :
1288 : 379811 : return scanner;
1289 : : }
1290 : :
1291 : :
1292 : : /*
1293 : : * Called after parsing is done to clean up after scanner_init()
1294 : : */
1295 : : void
5270 1296 : 379150 : scanner_finish(core_yyscan_t yyscanner)
1297 : : {
1298 : : /*
1299 : : * We don't bother to call yylex_destroy(), because all it would do is
1300 : : * pfree a small amount of control storage. It's cheaper to leak the
1301 : : * storage until the parsing context is destroyed. The amount of space
1302 : : * involved is usually negligible compared to the output parse tree
1303 : : * anyway.
1304 : : *
1305 : : * We do bother to pfree the scanbuf and literal buffer, but only if they
1306 : : * represent a nontrivial amount of space. The 8K cutoff is arbitrary.
1307 : : */
5389 1308 [ + + ]: 379150 : if (yyextra->scanbuflen >= 8192)
1309 : 37 : pfree(yyextra->scanbuf);
1310 [ + + ]: 379150 : if (yyextra->literalalloc >= 8192)
1311 : 16 : pfree(yyextra->literalbuf);
8030 peter_e@gmx.net 1312 : 379150 : }
1313 : :
1314 : :
1315 : : static void
5270 tgl@sss.pgh.pa.us 1316 : 387798 : addlit(char *ytext, int yleng, core_yyscan_t yyscanner)
1317 : : {
1318 : : /* enlarge buffer if needed */
5389 1319 [ + + ]: 387798 : if ((yyextra->literallen + yleng) >= yyextra->literalalloc)
1320 : : {
1018 drowley@postgresql.o 1321 : 109 : yyextra->literalalloc = pg_nextpower2_32(yyextra->literallen + yleng + 1);
5389 tgl@sss.pgh.pa.us 1322 : 109 : yyextra->literalbuf = (char *) repalloc(yyextra->literalbuf,
1323 : 109 : yyextra->literalalloc);
1324 : : }
1325 : : /* append new data */
1326 : 387798 : memcpy(yyextra->literalbuf + yyextra->literallen, ytext, yleng);
1327 : 387798 : yyextra->literallen += yleng;
8945 1328 : 387798 : }
1329 : :
1330 : :
1331 : : static void
5270 1332 : 10784 : addlitchar(unsigned char ychar, core_yyscan_t yyscanner)
1333 : : {
1334 : : /* enlarge buffer if needed */
5389 1335 [ - + ]: 10784 : if ((yyextra->literallen + 1) >= yyextra->literalalloc)
1336 : : {
5389 tgl@sss.pgh.pa.us 1337 :UBC 0 : yyextra->literalalloc *= 2;
1338 : 0 : yyextra->literalbuf = (char *) repalloc(yyextra->literalbuf,
1339 : 0 : yyextra->literalalloc);
1340 : : }
1341 : : /* append new data */
5389 tgl@sss.pgh.pa.us 1342 :CBC 10784 : yyextra->literalbuf[yyextra->literallen] = ychar;
1343 : 10784 : yyextra->literallen += 1;
10141 scrappy@hub.org 1344 : 10784 : }
1345 : :
1346 : :
1347 : : /*
1348 : : * Create a palloc'd copy of literalbuf, adding a trailing null.
1349 : : */
1350 : : static char *
5270 tgl@sss.pgh.pa.us 1351 : 388725 : litbufdup(core_yyscan_t yyscanner)
1352 : : {
5389 1353 : 388725 : int llen = yyextra->literallen;
1354 : : char *new;
1355 : :
1356 : 388725 : new = palloc(llen + 1);
1357 : 388725 : memcpy(new, yyextra->literalbuf, llen);
1358 : 388725 : new[llen] = '\0';
8030 peter_e@gmx.net 1359 : 388725 : return new;
1360 : : }
1361 : :
1362 : : /*
1363 : : * Process {decinteger}, {hexinteger}, etc. Note this will also do the right
1364 : : * thing with {numeric}, ie digits and a decimal point.
1365 : : */
1366 : : static int
487 peter@eisentraut.org 1367 : 246423 : process_integer_literal(const char *token, YYSTYPE *lval, int base)
1368 : : {
435 dean.a.rasheed@gmail 1369 : 246423 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1370 : : int32 val;
1371 : :
1372 : 246423 : val = pg_strtoint32_safe(token, (Node *) &escontext);
1373 [ + + ]: 246423 : if (escontext.error_occurred)
1374 : : {
1375 : : /* integer too large (or contains decimal pt), treat it as a float */
5267 tgl@sss.pgh.pa.us 1376 : 801 : lval->str = pstrdup(token);
1377 : 801 : return FCONST;
1378 : : }
1379 : 245622 : lval->ival = val;
1380 : 245622 : return ICONST;
1381 : : }
1382 : :
1383 : : static void
5270 1384 : 69 : addunicode(pg_wchar c, core_yyscan_t yyscanner)
1385 : : {
1386 : : ScannerCallbackState scbstate;
1387 : : char buf[MAX_UNICODE_EQUIVALENT_STRING + 1];
1388 : :
1500 1389 [ + + ]: 69 : if (!is_valid_unicode_codepoint(c))
5270 1390 : 3 : yyerror("invalid Unicode escape value");
1391 : :
1392 : : /*
1393 : : * We expect that pg_unicode_to_server() will complain about any
1394 : : * unconvertible code point, so we don't have to set saw_non_ascii.
1395 : : */
1500 1396 : 66 : setup_scanner_errposition_callback(&scbstate, yyscanner, *(yylloc));
1397 : 66 : pg_unicode_to_server(c, (unsigned char *) buf);
1398 : 66 : cancel_scanner_errposition_callback(&scbstate);
1399 : 66 : addlit(buf, strlen(buf), yyscanner);
5270 1400 : 66 : }
1401 : :
1402 : : static unsigned char
1403 : 2993 : unescape_single_char(unsigned char c, core_yyscan_t yyscanner)
1404 : : {
8030 peter_e@gmx.net 1405 [ + + + + : 2993 : switch (c)
+ - + ]
1406 : : {
1407 : 13 : case 'b':
1408 : 13 : return '\b';
1409 : 1 : case 'f':
1410 : 1 : return '\f';
1411 : 630 : case 'n':
1412 : 630 : return '\n';
1413 : 36 : case 'r':
1414 : 36 : return '\r';
1415 : 10 : case 't':
1416 : 10 : return '\t';
283 michael@paquier.xyz 1417 :UNC 0 : case 'v':
1418 : 0 : return '\v';
8030 peter_e@gmx.net 1419 :CBC 2303 : default:
1420 : : /* check for backslash followed by non-7-bit-ASCII */
5474 tgl@sss.pgh.pa.us 1421 [ + - - + ]: 2303 : if (c == '\0' || IS_HIGHBIT_SET(c))
5389 tgl@sss.pgh.pa.us 1422 :UBC 0 : yyextra->saw_non_ascii = true;
1423 : :
8030 peter_e@gmx.net 1424 :CBC 2303 : return c;
1425 : : }
1426 : : }
1427 : :
1428 : : static void
5270 tgl@sss.pgh.pa.us 1429 : 2993 : check_string_escape_warning(unsigned char ychar, core_yyscan_t yyscanner)
1430 : : {
6614 bruce@momjian.us 1431 [ + + ]: 2993 : if (ychar == '\'')
1432 : : {
3370 tgl@sss.pgh.pa.us 1433 [ - + - - ]: 18 : if (yyextra->warn_on_first_escape && yyextra->escape_string_warning)
6614 bruce@momjian.us 1434 [ # # ]:UBC 0 : ereport(WARNING,
1435 : : (errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
1436 : : errmsg("nonstandard use of \\' in a string literal"),
1437 : : errhint("Use '' to write quotes in strings, or use the escape string syntax (E'...')."),
1438 : : lexer_errposition()));
5389 tgl@sss.pgh.pa.us 1439 :CBC 18 : yyextra->warn_on_first_escape = false; /* warn only once per string */
1440 : : }
6614 bruce@momjian.us 1441 [ + + ]: 2975 : else if (ychar == '\\')
1442 : : {
3370 tgl@sss.pgh.pa.us 1443 [ + + + + ]: 2285 : if (yyextra->warn_on_first_escape && yyextra->escape_string_warning)
6614 bruce@momjian.us 1444 [ + - ]: 31 : ereport(WARNING,
1445 : : (errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
1446 : : errmsg("nonstandard use of \\\\ in a string literal"),
1447 : : errhint("Use the escape string syntax for backslashes, e.g., E'\\\\'."),
1448 : : lexer_errposition()));
5389 tgl@sss.pgh.pa.us 1449 : 2285 : yyextra->warn_on_first_escape = false; /* warn only once per string */
1450 : : }
1451 : : else
1452 : 690 : check_escape_warning(yyscanner);
6614 bruce@momjian.us 1453 : 2993 : }
1454 : :
1455 : : static void
5270 tgl@sss.pgh.pa.us 1456 : 828 : check_escape_warning(core_yyscan_t yyscanner)
1457 : : {
3370 1458 [ - + - - ]: 828 : if (yyextra->warn_on_first_escape && yyextra->escape_string_warning)
6867 bruce@momjian.us 1459 [ # # ]:UBC 0 : ereport(WARNING,
1460 : : (errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
1461 : : errmsg("nonstandard use of escape in a string literal"),
1462 : : errhint("Use the escape string syntax for escapes, e.g., E'\\r\\n'."),
1463 : : lexer_errposition()));
2948 tgl@sss.pgh.pa.us 1464 :CBC 828 : yyextra->warn_on_first_escape = false; /* warn only once per string */
5389 1465 : 828 : }
1466 : :
1467 : : /*
1468 : : * Interface functions to make flex use palloc() instead of malloc().
1469 : : * It'd be better to make these static, but flex insists otherwise.
1470 : : */
1471 : :
1472 : : void *
5270 1473 : 1139433 : core_yyalloc(yy_size_t bytes, core_yyscan_t yyscanner)
1474 : : {
5389 1475 : 1139433 : return palloc(bytes);
1476 : : }
1477 : :
1478 : : void *
5270 tgl@sss.pgh.pa.us 1479 :UBC 0 : core_yyrealloc(void *ptr, yy_size_t bytes, core_yyscan_t yyscanner)
1480 : : {
5389 1481 [ # # ]: 0 : if (ptr)
1482 : 0 : return repalloc(ptr, bytes);
1483 : : else
1484 : 0 : return palloc(bytes);
1485 : : }
1486 : :
1487 : : void
5270 1488 : 0 : core_yyfree(void *ptr, core_yyscan_t yyscanner)
1489 : : {
5389 1490 [ # # ]: 0 : if (ptr)
1491 : 0 : pfree(ptr);
6867 bruce@momjian.us 1492 : 0 : }
|