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