PostgreSQL Source Code git master
pl_scanner.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * pl_scanner.c
4 * lexical scanning for PL/pgSQL
5 *
6 *
7 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
9 *
10 *
11 * IDENTIFICATION
12 * src/pl/plpgsql/src/pl_scanner.c
13 *
14 *-------------------------------------------------------------------------
15 */
16#include "postgres.h"
17
18#include "mb/pg_wchar.h"
19#include "parser/scanner.h"
20
21#include "plpgsql.h"
22#include "pl_gram.h" /* must be after parser/scanner.h */
23
24
25/* Klugy flag to tell scanner how to look up identifiers */
27
28/*
29 * A word about keywords:
30 *
31 * We keep reserved and unreserved keywords in separate headers. Be careful
32 * not to put the same word in both headers. Also be sure that pl_gram.y's
33 * unreserved_keyword production agrees with the unreserved header. The
34 * reserved keywords are passed to the core scanner, so they will be
35 * recognized before (and instead of) any variable name. Unreserved words
36 * are checked for separately, usually after determining that the identifier
37 * isn't a known variable name. If plpgsql_IdentifierLookup is DECLARE then
38 * no variable names will be recognized, so the unreserved words always work.
39 * (Note in particular that this helps us avoid reserving keywords that are
40 * only needed in DECLARE sections.)
41 *
42 * In certain contexts it is desirable to prefer recognizing an unreserved
43 * keyword over recognizing a variable name. In particular, at the start
44 * of a statement we should prefer unreserved keywords unless the statement
45 * looks like an assignment (i.e., first token is followed by ':=' or '[').
46 * This rule allows most statement-introducing keywords to be kept unreserved.
47 * (We still have to reserve initial keywords that might follow a block
48 * label, unfortunately, since the method used to determine if we are at
49 * start of statement doesn't recognize such cases. We'd also have to
50 * reserve any keyword that could legitimately be followed by ':=' or '['.)
51 * Some additional cases are handled in pl_gram.y using tok_is_keyword().
52 *
53 * We try to avoid reserving more keywords than we have to; but there's
54 * little point in not reserving a word if it's reserved in the core grammar.
55 * Currently, the following words are reserved here but not in the core:
56 * BEGIN BY DECLARE EXECUTE FOREACH IF LOOP STRICT WHILE
57 */
58
59/* ScanKeywordList lookup data for PL/pgSQL keywords */
60#include "pl_reserved_kwlist_d.h"
61#include "pl_unreserved_kwlist_d.h"
62
63/* Token codes for PL/pgSQL keywords */
64#define PG_KEYWORD(kwname, value) value,
65
67#include "pl_reserved_kwlist.h"
68};
69
72};
73
74#undef PG_KEYWORD
75
76/*
77 * This macro must recognize all tokens that can immediately precede a
78 * PL/pgSQL executable statement (that is, proc_sect or proc_stmt in the
79 * grammar). Fortunately, there are not very many, so hard-coding in this
80 * fashion seems sufficient.
81 */
82#define AT_STMT_START(prev_token) \
83 ((prev_token) == ';' || \
84 (prev_token) == K_BEGIN || \
85 (prev_token) == K_THEN || \
86 (prev_token) == K_ELSE || \
87 (prev_token) == K_LOOP)
88
89
90/* Auxiliary data about a token (other than the token type) */
91typedef struct
92{
93 YYSTYPE lval; /* semantic information */
94 YYLTYPE lloc; /* offset in scanbuf */
95 int leng; /* length in bytes */
97
98#define MAX_PUSHBACKS 4
99
100/*
101 * Scanner working state.
102 */
104{
105 /* The stuff the core lexer needs */
107
108 /* The original input string */
109 const char *scanorig;
110
111 /*
112 * Current token's length (corresponds to plpgsql_yylval and
113 * plpgsql_yylloc)
114 */
116
117 /* Current token's code (corresponds to plpgsql_yylval and plpgsql_yylloc) */
119
120 /* Token pushback stack */
124
125 /* State for plpgsql_location_to_lineno() */
126 const char *cur_line_start;
127 const char *cur_line_end;
129};
130
131/* Internal functions */
132static int internal_yylex(TokenAuxData *auxdata, yyscan_t yyscanner);
133static void push_back_token(int token, TokenAuxData *auxdata, yyscan_t yyscanner);
134static void location_lineno_init(yyscan_t yyscanner);
135
136/*
137 * This is normally provided by the generated flex code, but we don't have
138 * that here, so we make a minimal version ourselves.
139 */
141{
143};
144
145/* see scan.l */
146#undef yyextra
147#define yyextra (((struct yyguts_t *) yyscanner)->yyextra_r)
148
149
150/*
151 * This is the yylex routine called from the PL/pgSQL grammar.
152 * It is a wrapper around the core lexer, with the ability to recognize
153 * PL/pgSQL variables and return them as special T_DATUM tokens. If a
154 * word or compound word does not match any variable name, or if matching
155 * is turned off by plpgsql_IdentifierLookup, it is returned as
156 * T_WORD or T_CWORD respectively, or as an unreserved keyword if it
157 * matches one of those.
158 */
159int
160plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
161{
162 int tok1;
163 TokenAuxData aux1;
164 int kwnum;
165
166 tok1 = internal_yylex(&aux1, yyscanner);
167 if (tok1 == IDENT || tok1 == PARAM)
168 {
169 int tok2;
170 TokenAuxData aux2;
171
172 tok2 = internal_yylex(&aux2, yyscanner);
173 if (tok2 == '.')
174 {
175 int tok3;
176 TokenAuxData aux3;
177
178 tok3 = internal_yylex(&aux3, yyscanner);
179 if (tok3 == IDENT)
180 {
181 int tok4;
182 TokenAuxData aux4;
183
184 tok4 = internal_yylex(&aux4, yyscanner);
185 if (tok4 == '.')
186 {
187 int tok5;
188 TokenAuxData aux5;
189
190 tok5 = internal_yylex(&aux5, yyscanner);
191 if (tok5 == IDENT)
192 {
193 if (plpgsql_parse_tripword(aux1.lval.str,
194 aux3.lval.str,
195 aux5.lval.str,
196 &aux1.lval.wdatum,
197 &aux1.lval.cword))
198 tok1 = T_DATUM;
199 else
200 tok1 = T_CWORD;
201 /* Adjust token length to include A.B.C */
202 aux1.leng = aux5.lloc - aux1.lloc + aux5.leng;
203 }
204 else
205 {
206 /* not A.B.C, so just process A.B */
207 push_back_token(tok5, &aux5, yyscanner);
208 push_back_token(tok4, &aux4, yyscanner);
209 if (plpgsql_parse_dblword(aux1.lval.str,
210 aux3.lval.str,
211 &aux1.lval.wdatum,
212 &aux1.lval.cword))
213 tok1 = T_DATUM;
214 else
215 tok1 = T_CWORD;
216 /* Adjust token length to include A.B */
217 aux1.leng = aux3.lloc - aux1.lloc + aux3.leng;
218 }
219 }
220 else
221 {
222 /* not A.B.C, so just process A.B */
223 push_back_token(tok4, &aux4, yyscanner);
224 if (plpgsql_parse_dblword(aux1.lval.str,
225 aux3.lval.str,
226 &aux1.lval.wdatum,
227 &aux1.lval.cword))
228 tok1 = T_DATUM;
229 else
230 tok1 = T_CWORD;
231 /* Adjust token length to include A.B */
232 aux1.leng = aux3.lloc - aux1.lloc + aux3.leng;
233 }
234 }
235 else
236 {
237 /* not A.B, so just process A */
238 push_back_token(tok3, &aux3, yyscanner);
239 push_back_token(tok2, &aux2, yyscanner);
240 if (plpgsql_parse_word(aux1.lval.str,
241 yyextra->core_yy_extra.scanbuf + aux1.lloc,
242 true,
243 &aux1.lval.wdatum,
244 &aux1.lval.word))
245 tok1 = T_DATUM;
246 else if (!aux1.lval.word.quoted &&
247 (kwnum = ScanKeywordLookup(aux1.lval.word.ident,
248 &UnreservedPLKeywords)) >= 0)
249 {
250 aux1.lval.keyword = GetScanKeyword(kwnum,
251 &UnreservedPLKeywords);
252 tok1 = UnreservedPLKeywordTokens[kwnum];
253 }
254 else
255 tok1 = T_WORD;
256 }
257 }
258 else
259 {
260 /* not A.B, so just process A */
261 push_back_token(tok2, &aux2, yyscanner);
262
263 /*
264 * See if it matches a variable name, except in the context where
265 * we are at start of statement and the next token isn't
266 * assignment or '['. In that case, it couldn't validly be a
267 * variable name, and skipping the lookup allows variable names to
268 * be used that would conflict with plpgsql or core keywords that
269 * introduce statements (e.g., "comment"). Without this special
270 * logic, every statement-introducing keyword would effectively be
271 * reserved in PL/pgSQL, which would be unpleasant.
272 *
273 * If it isn't a variable name, try to match against unreserved
274 * plpgsql keywords. If not one of those either, it's T_WORD.
275 *
276 * Note: we must call plpgsql_parse_word even if we don't want to
277 * do variable lookup, because it sets up aux1.lval.word for the
278 * non-variable cases.
279 */
280 if (plpgsql_parse_word(aux1.lval.str,
281 yyextra->core_yy_extra.scanbuf + aux1.lloc,
282 (!AT_STMT_START(yyextra->plpgsql_yytoken) ||
283 (tok2 == '=' || tok2 == COLON_EQUALS ||
284 tok2 == '[')),
285 &aux1.lval.wdatum,
286 &aux1.lval.word))
287 tok1 = T_DATUM;
288 else if (!aux1.lval.word.quoted &&
289 (kwnum = ScanKeywordLookup(aux1.lval.word.ident,
290 &UnreservedPLKeywords)) >= 0)
291 {
292 aux1.lval.keyword = GetScanKeyword(kwnum,
293 &UnreservedPLKeywords);
294 tok1 = UnreservedPLKeywordTokens[kwnum];
295 }
296 else
297 tok1 = T_WORD;
298 }
299 }
300 else
301 {
302 /*
303 * Not a potential plpgsql variable name, just return the data.
304 *
305 * Note that we also come through here if the grammar pushed back a
306 * T_DATUM, T_CWORD, T_WORD, or unreserved-keyword token returned by a
307 * previous lookup cycle; thus, pushbacks do not incur extra lookup
308 * work, since we'll never do the above code twice for the same token.
309 * This property also makes it safe to rely on the old value of
310 * plpgsql_yytoken in the is-this-start-of-statement test above.
311 */
312 }
313
314 *yylvalp = aux1.lval;
315 *yyllocp = aux1.lloc;
316 yyextra->plpgsql_yyleng = aux1.leng;
317 yyextra->plpgsql_yytoken = tok1;
318 return tok1;
319}
320
321/*
322 * Return the length of the token last returned by plpgsql_yylex().
323 *
324 * In the case of compound tokens, the length includes all the parts.
325 */
326int
328{
329 return yyextra->plpgsql_yyleng;
330}
331
332/*
333 * Internal yylex function. This wraps the core lexer and adds one feature:
334 * a token pushback stack. We also make a couple of trivial single-token
335 * translations from what the core lexer does to what we want, in particular
336 * interfacing from the core_YYSTYPE to YYSTYPE union.
337 */
338static int
340{
341 int token;
342 const char *yytext;
343
344 if (yyextra->num_pushbacks > 0)
345 {
346 yyextra->num_pushbacks--;
347 token = yyextra->pushback_token[yyextra->num_pushbacks];
348 *auxdata = yyextra->pushback_auxdata[yyextra->num_pushbacks];
349 }
350 else
351 {
352 token = core_yylex(&auxdata->lval.core_yystype,
353 &auxdata->lloc,
354 yyscanner);
355
356 /* remember the length of yytext before it gets changed */
357 yytext = yyextra->core_yy_extra.scanbuf + auxdata->lloc;
358 auxdata->leng = strlen(yytext);
359
360 /* Check for << >> and #, which the core considers operators */
361 if (token == Op)
362 {
363 if (strcmp(auxdata->lval.str, "<<") == 0)
364 token = LESS_LESS;
365 else if (strcmp(auxdata->lval.str, ">>") == 0)
366 token = GREATER_GREATER;
367 else if (strcmp(auxdata->lval.str, "#") == 0)
368 token = '#';
369 }
370
371 /* The core returns PARAM as ival, but we treat it like IDENT */
372 else if (token == PARAM)
373 {
374 auxdata->lval.str = pstrdup(yytext);
375 }
376 }
377
378 return token;
379}
380
381/*
382 * Push back a token to be re-read by next internal_yylex() call.
383 */
384static void
386{
387 if (yyextra->num_pushbacks >= MAX_PUSHBACKS)
388 elog(ERROR, "too many tokens pushed back");
389 yyextra->pushback_token[yyextra->num_pushbacks] = token;
390 yyextra->pushback_auxdata[yyextra->num_pushbacks] = *auxdata;
391 yyextra->num_pushbacks++;
392}
393
394/*
395 * Push back a single token to be re-read by next plpgsql_yylex() call.
396 *
397 * NOTE: this does not cause yylval or yylloc to "back up". Also, it
398 * is not a good idea to push back a token code other than what you read.
399 */
400void
401plpgsql_push_back_token(int token, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
402{
403 TokenAuxData auxdata;
404
405 auxdata.lval = *yylvalp;
406 auxdata.lloc = *yyllocp;
407 auxdata.leng = yyextra->plpgsql_yyleng;
408 push_back_token(token, &auxdata, yyscanner);
409}
410
411/*
412 * Tell whether a token is an unreserved keyword.
413 *
414 * (If it is, its lowercased form was returned as the token value, so we
415 * do not need to offer that data here.)
416 */
417bool
419{
420 int i;
421
422 for (i = 0; i < lengthof(UnreservedPLKeywordTokens); i++)
423 {
425 return true;
426 }
427 return false;
428}
429
430/*
431 * Append the function text starting at startlocation and extending to
432 * (not including) endlocation onto the existing contents of "buf".
433 */
434void
436 int startlocation, int endlocation,
437 yyscan_t yyscanner)
438{
439 Assert(startlocation <= endlocation);
440 appendBinaryStringInfo(buf, yyextra->scanorig + startlocation,
441 endlocation - startlocation);
442}
443
444/*
445 * Peek one token ahead in the input stream. Only the token code is
446 * made available, not any of the auxiliary info such as location.
447 *
448 * NB: no variable or unreserved keyword lookup is performed here, they will
449 * be returned as IDENT. Reserved keywords are resolved as usual.
450 */
451int
453{
454 int tok1;
455 TokenAuxData aux1;
456
457 tok1 = internal_yylex(&aux1, yyscanner);
458 push_back_token(tok1, &aux1, yyscanner);
459 return tok1;
460}
461
462/*
463 * Peek two tokens ahead in the input stream. The first token and its
464 * location in the query are returned in *tok1_p and *tok1_loc, second token
465 * and its location in *tok2_p and *tok2_loc.
466 *
467 * NB: no variable or unreserved keyword lookup is performed here, they will
468 * be returned as IDENT. Reserved keywords are resolved as usual.
469 */
470void
471plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc, yyscan_t yyscanner)
472{
473 int tok1,
474 tok2;
475 TokenAuxData aux1,
476 aux2;
477
478 tok1 = internal_yylex(&aux1, yyscanner);
479 tok2 = internal_yylex(&aux2, yyscanner);
480
481 *tok1_p = tok1;
482 if (tok1_loc)
483 *tok1_loc = aux1.lloc;
484 *tok2_p = tok2;
485 if (tok2_loc)
486 *tok2_loc = aux2.lloc;
487
488 push_back_token(tok2, &aux2, yyscanner);
489 push_back_token(tok1, &aux1, yyscanner);
490}
491
492/*
493 * plpgsql_scanner_errposition
494 * Report an error cursor position, if possible.
495 *
496 * This is expected to be used within an ereport() call. The return value
497 * is a dummy (always 0, in fact).
498 *
499 * Note that this can only be used for messages emitted during initial
500 * parsing of a plpgsql function, since it requires the scanorig string
501 * to still be available.
502 */
503int
504plpgsql_scanner_errposition(int location, yyscan_t yyscanner)
505{
506 int pos;
507
508 if (location < 0 || yyextra->scanorig == NULL)
509 return 0; /* no-op if location is unknown */
510
511 /* Convert byte offset to character number */
512 pos = pg_mbstrlen_with_len(yyextra->scanorig, location) + 1;
513 /* And pass it to the ereport mechanism */
514 (void) internalerrposition(pos);
515 /* Also pass the function body string */
516 return internalerrquery(yyextra->scanorig);
517}
518
519/*
520 * plpgsql_yyerror
521 * Report a lexer or grammar error.
522 *
523 * The message's cursor position refers to the current token (the one
524 * last returned by plpgsql_yylex()).
525 * This is OK for syntax error messages from the Bison parser, because Bison
526 * parsers report error as soon as the first unparsable token is reached.
527 * Beware of using yyerror for other purposes, as the cursor position might
528 * be misleading!
529 */
530void
531plpgsql_yyerror(YYLTYPE *yyllocp, yyscan_t yyscanner, const char *message)
532{
533 char *yytext = yyextra->core_yy_extra.scanbuf + *yyllocp;
534
535 if (*yytext == '\0')
536 {
538 (errcode(ERRCODE_SYNTAX_ERROR),
539 /* translator: %s is typically the translation of "syntax error" */
540 errmsg("%s at end of input", _(message)),
541 plpgsql_scanner_errposition(*yyllocp, yyscanner)));
542 }
543 else
544 {
545 /*
546 * If we have done any lookahead then flex will have restored the
547 * character after the end-of-token. Zap it again so that we report
548 * only the single token here. This modifies scanbuf but we no longer
549 * care about that.
550 */
551 yytext[yyextra->plpgsql_yyleng] = '\0';
552
554 (errcode(ERRCODE_SYNTAX_ERROR),
555 /* translator: first %s is typically the translation of "syntax error" */
556 errmsg("%s at or near \"%s\"", _(message), yytext),
557 plpgsql_scanner_errposition(*yyllocp, yyscanner)));
558 }
559}
560
561/*
562 * Given a location (a byte offset in the function source text),
563 * return a line number.
564 *
565 * We expect that this is typically called for a sequence of increasing
566 * location values, so optimize accordingly by tracking the endpoints
567 * of the "current" line.
568 */
569int
570plpgsql_location_to_lineno(int location, yyscan_t yyscanner)
571{
572 const char *loc;
573
574 if (location < 0 || yyextra->scanorig == NULL)
575 return 0; /* garbage in, garbage out */
576 loc = yyextra->scanorig + location;
577
578 /* be correct, but not fast, if input location goes backwards */
579 if (loc < yyextra->cur_line_start)
580 location_lineno_init(yyscanner);
581
582 while (yyextra->cur_line_end != NULL && loc > yyextra->cur_line_end)
583 {
584 yyextra->cur_line_start = yyextra->cur_line_end + 1;
585 yyextra->cur_line_num++;
586 yyextra->cur_line_end = strchr(yyextra->cur_line_start, '\n');
587 }
588
589 return yyextra->cur_line_num;
590}
591
592/* initialize or reset the state for plpgsql_location_to_lineno */
593static void
595{
596 yyextra->cur_line_start = yyextra->scanorig;
597 yyextra->cur_line_num = 1;
598
599 yyextra->cur_line_end = strchr(yyextra->cur_line_start, '\n');
600}
601
602/* return the most recently computed lineno */
603int
605{
606 return yyextra->cur_line_num;
607}
608
609
610/*
611 * Called before any actual parsing is done
612 *
613 * Note: the passed "str" must remain valid until plpgsql_scanner_finish().
614 * Although it is not fed directly to flex, we need the original string
615 * to cite in error messages.
616 */
619{
620 yyscan_t yyscanner;
622
623 /* Start up the core scanner */
624 yyscanner = scanner_init(str, (core_yy_extra_type *) yyext,
625 &ReservedPLKeywords, ReservedPLKeywordTokens);
626
627 /*
628 * scanorig points to the original string, which unlike the scanner's
629 * scanbuf won't be modified on-the-fly by flex. Notice that although
630 * yytext points into scanbuf, we rely on being able to apply locations
631 * (offsets from string start) to scanorig as well.
632 */
633 yyext->scanorig = str;
634
635 /* Other setup */
637 yyext->plpgsql_yytoken = 0;
638
639 yyext->num_pushbacks = 0;
640
641 location_lineno_init(yyscanner);
642
643 return yyscanner;
644}
645
646/*
647 * Called after parsing is done to clean up after plpgsql_scanner_init()
648 */
649void
651{
652 /* release storage */
653 scanner_finish(yyscanner);
654}
#define Assert(condition)
Definition: c.h:815
uint16_t uint16
Definition: c.h:487
#define lengthof(array)
Definition: c.h:745
void * yyscan_t
Definition: cubedata.h:67
int internalerrquery(const char *query)
Definition: elog.c:1482
int internalerrposition(int cursorpos)
Definition: elog.c:1462
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define _(x)
Definition: elog.c:90
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
#define palloc0_object(type)
Definition: fe_memutils.h:75
const char * str
#define token
Definition: indent_globs.h:126
int i
Definition: isn.c:72
int ScanKeywordLookup(const char *str, const ScanKeywordList *keywords)
Definition: kwlookup.c:38
static const char * GetScanKeyword(int n, const ScanKeywordList *keywords)
Definition: kwlookup.h:39
int pg_mbstrlen_with_len(const char *mbstr, int limit)
Definition: mbutils.c:1057
char * pstrdup(const char *in)
Definition: mcxt.c:1696
static char * buf
Definition: pg_test_fsync.c:72
bool plpgsql_parse_dblword(char *word1, char *word2, PLwdatum *wdatum, PLcword *cword)
Definition: pl_comp.c:1453
bool plpgsql_parse_word(char *word1, const char *yytxt, bool lookup, PLwdatum *wdatum, PLword *word)
Definition: pl_comp.c:1398
bool plpgsql_parse_tripword(char *word1, char *word2, char *word3, PLwdatum *wdatum, PLcword *cword)
Definition: pl_comp.c:1534
#define AT_STMT_START(prev_token)
Definition: pl_scanner.c:82
void plpgsql_append_source_text(StringInfo buf, int startlocation, int endlocation, yyscan_t yyscanner)
Definition: pl_scanner.c:435
void plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc, yyscan_t yyscanner)
Definition: pl_scanner.c:471
int plpgsql_token_length(yyscan_t yyscanner)
Definition: pl_scanner.c:327
int plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
Definition: pl_scanner.c:160
static const uint16 UnreservedPLKeywordTokens[]
Definition: pl_scanner.c:70
IdentifierLookup plpgsql_IdentifierLookup
Definition: pl_scanner.c:26
void plpgsql_scanner_finish(yyscan_t yyscanner)
Definition: pl_scanner.c:650
#define yyextra
Definition: pl_scanner.c:147
bool plpgsql_token_is_unreserved_keyword(int token)
Definition: pl_scanner.c:418
static const uint16 ReservedPLKeywordTokens[]
Definition: pl_scanner.c:66
static void push_back_token(int token, TokenAuxData *auxdata, yyscan_t yyscanner)
Definition: pl_scanner.c:385
yyscan_t plpgsql_scanner_init(const char *str)
Definition: pl_scanner.c:618
int plpgsql_scanner_errposition(int location, yyscan_t yyscanner)
Definition: pl_scanner.c:504
static int internal_yylex(TokenAuxData *auxdata, yyscan_t yyscanner)
Definition: pl_scanner.c:339
void plpgsql_push_back_token(int token, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
Definition: pl_scanner.c:401
int plpgsql_peek(yyscan_t yyscanner)
Definition: pl_scanner.c:452
int plpgsql_location_to_lineno(int location, yyscan_t yyscanner)
Definition: pl_scanner.c:570
void plpgsql_yyerror(YYLTYPE *yyllocp, yyscan_t yyscanner, const char *message)
Definition: pl_scanner.c:531
static void location_lineno_init(yyscan_t yyscanner)
Definition: pl_scanner.c:594
int plpgsql_latest_lineno(yyscan_t yyscanner)
Definition: pl_scanner.c:604
#define MAX_PUSHBACKS
Definition: pl_scanner.c:98
IdentifierLookup
Definition: plpgsql.h:1188
@ IDENTIFIER_LOOKUP_NORMAL
Definition: plpgsql.h:1189
const char * YYLTYPE
int YYSTYPE
Definition: psqlscanslash.l:39
core_yyscan_t scanner_init(const char *str, core_yy_extra_type *yyext, const ScanKeywordList *keywordlist, const uint16 *keyword_tokens)
Definition: scan.l:1249
void scanner_finish(core_yyscan_t yyscanner)
Definition: scan.l:1291
int core_yylex(core_YYSTYPE *yylval_param, YYLTYPE *yylloc_param, core_yyscan_t yyscanner)
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:281
YYLTYPE lloc
Definition: pl_scanner.c:94
YYSTYPE lval
Definition: pl_scanner.c:93
const char * cur_line_end
Definition: pl_scanner.c:127
core_yy_extra_type core_yy_extra
Definition: pl_scanner.c:106
const char * scanorig
Definition: pl_scanner.c:109
TokenAuxData pushback_auxdata[MAX_PUSHBACKS]
Definition: pl_scanner.c:123
int pushback_token[MAX_PUSHBACKS]
Definition: pl_scanner.c:122
const char * cur_line_start
Definition: pl_scanner.c:126
struct plpgsql_yy_extra_type * yyextra_r
Definition: pl_scanner.c:142