PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pl_scanner.c File Reference
#include "postgres.h"
#include "mb/pg_wchar.h"
#include "parser/scanner.h"
#include "plpgsql.h"
#include "pl_gram.h"
#include "pl_reserved_kwlist_d.h"
#include "pl_unreserved_kwlist_d.h"
#include "pl_reserved_kwlist.h"
#include "pl_unreserved_kwlist.h"
Include dependency graph for pl_scanner.c:

Go to the source code of this file.

Data Structures

struct  TokenAuxData
 
struct  plpgsql_yy_extra_type
 
struct  yyguts_t
 

Macros

#define PG_KEYWORD(kwname, value)   value,
 
#define AT_STMT_START(prev_token)
 
#define MAX_PUSHBACKS   4
 
#define yyextra   (((struct yyguts_t *) yyscanner)->yyextra_r)
 

Functions

static int internal_yylex (TokenAuxData *auxdata, yyscan_t yyscanner)
 
static void push_back_token (int token, TokenAuxData *auxdata, yyscan_t yyscanner)
 
static void location_lineno_init (yyscan_t yyscanner)
 
int plpgsql_yylex (YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
 
int plpgsql_token_length (yyscan_t yyscanner)
 
void plpgsql_push_back_token (int token, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
 
bool plpgsql_token_is_unreserved_keyword (int token)
 
void plpgsql_append_source_text (StringInfo buf, int startlocation, int endlocation, yyscan_t yyscanner)
 
int plpgsql_peek (yyscan_t yyscanner)
 
void plpgsql_peek2 (int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc, yyscan_t yyscanner)
 
int plpgsql_scanner_errposition (int location, yyscan_t yyscanner)
 
void plpgsql_yyerror (YYLTYPE *yyllocp, PLpgSQL_stmt_block **plpgsql_parse_result_p, yyscan_t yyscanner, const char *message)
 
int plpgsql_location_to_lineno (int location, yyscan_t yyscanner)
 
int plpgsql_latest_lineno (yyscan_t yyscanner)
 
yyscan_t plpgsql_scanner_init (const char *str)
 
void plpgsql_scanner_finish (yyscan_t yyscanner)
 

Variables

IdentifierLookup plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL
 
static const uint16 ReservedPLKeywordTokens []
 
static const uint16 UnreservedPLKeywordTokens []
 

Macro Definition Documentation

◆ AT_STMT_START

#define AT_STMT_START (   prev_token)
Value:
((prev_token) == ';' || \
(prev_token) == K_BEGIN || \
(prev_token) == K_THEN || \
(prev_token) == K_ELSE || \
static int fb(int x)

Definition at line 82 of file pl_scanner.c.

91{
92 YYSTYPE lval; /* semantic information */
93 YYLTYPE lloc; /* offset in scanbuf */
94 int leng; /* length in bytes */
96
97#define MAX_PUSHBACKS 4
98
99/*
100 * Scanner working state.
101 */
103{
104 /* The stuff the core lexer needs */
106
107 /* The original input string */
108 const char *scanorig;
109
110 /*
111 * Current token's length (corresponds to plpgsql_yylval and
112 * plpgsql_yylloc)
113 */
114 int plpgsql_yyleng;
115
116 /* Current token's code (corresponds to plpgsql_yylval and plpgsql_yylloc) */
117 int plpgsql_yytoken;
118
119 /* Token pushback stack */
120 int num_pushbacks;
123
124 /* State for plpgsql_location_to_lineno() */
125 const char *cur_line_start;
126 const char *cur_line_end;
127 int cur_line_num;
128};
129
130/* Internal functions */
131static int internal_yylex(TokenAuxData *auxdata, yyscan_t yyscanner);
132static void push_back_token(int token, TokenAuxData *auxdata, yyscan_t yyscanner);
133static void location_lineno_init(yyscan_t yyscanner);
134
135/*
136 * This is normally provided by the generated flex code, but we don't have
137 * that here, so we make a minimal version ourselves.
138 */
139struct yyguts_t
140{
142};
143
144/* see scan.l */
145#undef yyextra
146#define yyextra (((struct yyguts_t *) yyscanner)->yyextra_r)
147
148
149/*
150 * This is the yylex routine called from the PL/pgSQL grammar.
151 * It is a wrapper around the core lexer, with the ability to recognize
152 * PL/pgSQL variables and return them as special T_DATUM tokens. If a
153 * word or compound word does not match any variable name, or if matching
154 * is turned off by plpgsql_IdentifierLookup, it is returned as
155 * T_WORD or T_CWORD respectively, or as an unreserved keyword if it
156 * matches one of those.
157 */
158int
160{
161 int tok1;
163 int kwnum;
164
165 tok1 = internal_yylex(&aux1, yyscanner);
166 if (tok1 == IDENT || tok1 == PARAM)
167 {
168 int tok2;
170
171 tok2 = internal_yylex(&aux2, yyscanner);
172 if (tok2 == '.')
173 {
174 int tok3;
176
177 tok3 = internal_yylex(&aux3, yyscanner);
178 if (tok3 == IDENT)
179 {
180 int tok4;
182
183 tok4 = internal_yylex(&aux4, yyscanner);
184 if (tok4 == '.')
185 {
186 int tok5;
188
189 tok5 = internal_yylex(&aux5, yyscanner);
190 if (tok5 == IDENT)
191 {
192 if (plpgsql_parse_tripword(aux1.lval.str,
193 aux3.lval.str,
194 aux5.lval.str,
195 &aux1.lval.wdatum,
196 &aux1.lval.cword))
197 tok1 = T_DATUM;
198 else
199 tok1 = T_CWORD;
200 /* Adjust token length to include A.B.C */
201 aux1.leng = aux5.lloc - aux1.lloc + aux5.leng;
202 }
203 else
204 {
205 /* not A.B.C, so just process A.B */
206 push_back_token(tok5, &aux5, yyscanner);
207 push_back_token(tok4, &aux4, yyscanner);
208 if (plpgsql_parse_dblword(aux1.lval.str,
209 aux3.lval.str,
210 &aux1.lval.wdatum,
211 &aux1.lval.cword))
212 tok1 = T_DATUM;
213 else
214 tok1 = T_CWORD;
215 /* Adjust token length to include A.B */
216 aux1.leng = aux3.lloc - aux1.lloc + aux3.leng;
217 }
218 }
219 else
220 {
221 /* not A.B.C, so just process A.B */
222 push_back_token(tok4, &aux4, yyscanner);
223 if (plpgsql_parse_dblword(aux1.lval.str,
224 aux3.lval.str,
225 &aux1.lval.wdatum,
226 &aux1.lval.cword))
227 tok1 = T_DATUM;
228 else
229 tok1 = T_CWORD;
230 /* Adjust token length to include A.B */
231 aux1.leng = aux3.lloc - aux1.lloc + aux3.leng;
232 }
233 }
234 else
235 {
236 /* not A.B, so just process A */
237 push_back_token(tok3, &aux3, yyscanner);
238 push_back_token(tok2, &aux2, yyscanner);
239 if (plpgsql_parse_word(aux1.lval.str,
240 yyextra->core_yy_extra.scanbuf + aux1.lloc,
241 true,
242 &aux1.lval.wdatum,
243 &aux1.lval.word))
244 tok1 = T_DATUM;
245 else if (!aux1.lval.word.quoted &&
246 (kwnum = ScanKeywordLookup(aux1.lval.word.ident,
247 &UnreservedPLKeywords)) >= 0)
248 {
249 aux1.lval.keyword = GetScanKeyword(kwnum,
252 }
253 else
254 tok1 = T_WORD;
255 }
256 }
257 else
258 {
259 /* not A.B, so just process A */
260 push_back_token(tok2, &aux2, yyscanner);
261
262 /*
263 * See if it matches a variable name, except in the context where
264 * we are at start of statement and the next token isn't
265 * assignment or '['. In that case, it couldn't validly be a
266 * variable name, and skipping the lookup allows variable names to
267 * be used that would conflict with plpgsql or core keywords that
268 * introduce statements (e.g., "comment"). Without this special
269 * logic, every statement-introducing keyword would effectively be
270 * reserved in PL/pgSQL, which would be unpleasant.
271 *
272 * If it isn't a variable name, try to match against unreserved
273 * plpgsql keywords. If not one of those either, it's T_WORD.
274 *
275 * Note: we must call plpgsql_parse_word even if we don't want to
276 * do variable lookup, because it sets up aux1.lval.word for the
277 * non-variable cases.
278 */
279 if (plpgsql_parse_word(aux1.lval.str,
280 yyextra->core_yy_extra.scanbuf + aux1.lloc,
281 (!AT_STMT_START(yyextra->plpgsql_yytoken) ||
282 (tok2 == '=' || tok2 == COLON_EQUALS ||
283 tok2 == '[')),
284 &aux1.lval.wdatum,
285 &aux1.lval.word))
286 tok1 = T_DATUM;
287 else if (!aux1.lval.word.quoted &&
288 (kwnum = ScanKeywordLookup(aux1.lval.word.ident,
289 &UnreservedPLKeywords)) >= 0)
290 {
291 aux1.lval.keyword = GetScanKeyword(kwnum,
294 }
295 else
296 tok1 = T_WORD;
297 }
298 }
299 else
300 {
301 /*
302 * Not a potential plpgsql variable name, just return the data.
303 *
304 * Note that we also come through here if the grammar pushed back a
305 * T_DATUM, T_CWORD, T_WORD, or unreserved-keyword token returned by a
306 * previous lookup cycle; thus, pushbacks do not incur extra lookup
307 * work, since we'll never do the above code twice for the same token.
308 * This property also makes it safe to rely on the old value of
309 * plpgsql_yytoken in the is-this-start-of-statement test above.
310 */
311 }
312
313 *yylvalp = aux1.lval;
314 *yyllocp = aux1.lloc;
315 yyextra->plpgsql_yyleng = aux1.leng;
316 yyextra->plpgsql_yytoken = tok1;
317 return tok1;
318}
319
320/*
321 * Return the length of the token last returned by plpgsql_yylex().
322 *
323 * In the case of compound tokens, the length includes all the parts.
324 */
325int
327{
328 return yyextra->plpgsql_yyleng;
329}
330
331/*
332 * Internal yylex function. This wraps the core lexer and adds one feature:
333 * a token pushback stack. We also make a couple of trivial single-token
334 * translations from what the core lexer does to what we want, in particular
335 * interfacing from the core_YYSTYPE to YYSTYPE union.
336 */
337static int
339{
340 int token;
341 const char *yytext;
342
343 if (yyextra->num_pushbacks > 0)
344 {
345 yyextra->num_pushbacks--;
346 token = yyextra->pushback_token[yyextra->num_pushbacks];
347 *auxdata = yyextra->pushback_auxdata[yyextra->num_pushbacks];
348 }
349 else
350 {
351 token = core_yylex(&auxdata->lval.core_yystype,
352 &auxdata->lloc,
353 yyscanner);
354
355 /* remember the length of yytext before it gets changed */
356 yytext = yyextra->core_yy_extra.scanbuf + auxdata->lloc;
357 auxdata->leng = strlen(yytext);
358
359 /* Check for << >> and #, which the core considers operators */
360 if (token == Op)
361 {
362 if (strcmp(auxdata->lval.str, "<<") == 0)
364 else if (strcmp(auxdata->lval.str, ">>") == 0)
366 else if (strcmp(auxdata->lval.str, "#") == 0)
367 token = '#';
368 }
369
370 /* The core returns PARAM as ival, but we treat it like IDENT */
371 else if (token == PARAM)
372 {
373 auxdata->lval.str = pstrdup(yytext);
374 }
375 }
376
377 return token;
378}
379
380/*
381 * Push back a token to be re-read by next internal_yylex() call.
382 */
383static void
385{
386 if (yyextra->num_pushbacks >= MAX_PUSHBACKS)
387 elog(ERROR, "too many tokens pushed back");
388 yyextra->pushback_token[yyextra->num_pushbacks] = token;
389 yyextra->pushback_auxdata[yyextra->num_pushbacks] = *auxdata;
390 yyextra->num_pushbacks++;
391}
392
393/*
394 * Push back a single token to be re-read by next plpgsql_yylex() call.
395 *
396 * NOTE: this does not cause yylval or yylloc to "back up". Also, it
397 * is not a good idea to push back a token code other than what you read.
398 */
399void
401{
403
405 auxdata.lloc = *yyllocp;
406 auxdata.leng = yyextra->plpgsql_yyleng;
407 push_back_token(token, &auxdata, yyscanner);
408}
409
410/*
411 * Tell whether a token is an unreserved keyword.
412 *
413 * (If it is, its lowercased form was returned as the token value, so we
414 * do not need to offer that data here.)
415 */
416bool
418{
419 int i;
420
421 for (i = 0; i < lengthof(UnreservedPLKeywordTokens); i++)
422 {
424 return true;
425 }
426 return false;
427}
428
429/*
430 * Append the function text starting at startlocation and extending to
431 * (not including) endlocation onto the existing contents of "buf".
432 */
433void
435 int startlocation, int endlocation,
436 yyscan_t yyscanner)
437{
441}
442
443/*
444 * Peek one token ahead in the input stream. Only the token code is
445 * made available, not any of the auxiliary info such as location.
446 *
447 * NB: no variable or unreserved keyword lookup is performed here, they will
448 * be returned as IDENT. Reserved keywords are resolved as usual.
449 */
450int
451plpgsql_peek(yyscan_t yyscanner)
452{
453 int tok1;
455
456 tok1 = internal_yylex(&aux1, yyscanner);
457 push_back_token(tok1, &aux1, yyscanner);
458 return tok1;
459}
460
461/*
462 * Peek two tokens ahead in the input stream. The first token and its
463 * location in the query are returned in *tok1_p and *tok1_loc, second token
464 * and its location in *tok2_p and *tok2_loc.
465 *
466 * NB: no variable or unreserved keyword lookup is performed here, they will
467 * be returned as IDENT. Reserved keywords are resolved as usual.
468 */
469void
470plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc, yyscan_t yyscanner)
471{
472 int tok1,
473 tok2;
475 aux2;
476
477 tok1 = internal_yylex(&aux1, yyscanner);
478 tok2 = internal_yylex(&aux2, yyscanner);
479
480 *tok1_p = tok1;
481 if (tok1_loc)
482 *tok1_loc = aux1.lloc;
483 *tok2_p = tok2;
484 if (tok2_loc)
485 *tok2_loc = aux2.lloc;
486
487 push_back_token(tok2, &aux2, yyscanner);
488 push_back_token(tok1, &aux1, yyscanner);
489}
490
491/*
492 * plpgsql_scanner_errposition
493 * Report an error cursor position, if possible.
494 *
495 * This is expected to be used within an ereport() call. The return value
496 * is a dummy (always 0, in fact).
497 *
498 * Note that this can only be used for messages emitted during initial
499 * parsing of a plpgsql function, since it requires the scanorig string
500 * to still be available.
501 */
502int
503plpgsql_scanner_errposition(int location, yyscan_t yyscanner)
504{
505 int pos;
506
508 return 0; /* no-op if location is unknown */
509
510 /* Convert byte offset to character number */
511 pos = pg_mbstrlen_with_len(yyextra->scanorig, location) + 1;
512 /* And pass it to the ereport mechanism */
514 /* Also pass the function body string */
515 return internalerrquery(yyextra->scanorig);
516}
517
518/*
519 * plpgsql_yyerror
520 * Report a lexer or grammar error.
521 *
522 * The message's cursor position refers to the current token (the one
523 * last returned by plpgsql_yylex()).
524 * This is OK for syntax error messages from the Bison parser, because Bison
525 * parsers report error as soon as the first unparsable token is reached.
526 * Beware of using yyerror for other purposes, as the cursor position might
527 * be misleading!
528 *
529 * (The second argument is enforced by Bison to match the second argument of
530 * yyparse(), but it is not used here.)
531 */
532void
534{
535 char *yytext = yyextra->core_yy_extra.scanbuf + *yyllocp;
536
537 if (*yytext == '\0')
538 {
541 /* translator: %s is typically the translation of "syntax error" */
542 errmsg("%s at end of input", _(message)),
544 }
545 else
546 {
547 /*
548 * If we have done any lookahead then flex will have restored the
549 * character after the end-of-token. Zap it again so that we report
550 * only the single token here. This modifies scanbuf but we no longer
551 * care about that.
552 */
553 yytext[yyextra->plpgsql_yyleng] = '\0';
554
557 /* translator: first %s is typically the translation of "syntax error" */
558 errmsg("%s at or near \"%s\"", _(message), yytext),
560 }
561}
562
563/*
564 * Given a location (a byte offset in the function source text),
565 * return a line number.
566 *
567 * We expect that this is typically called for a sequence of increasing
568 * location values, so optimize accordingly by tracking the endpoints
569 * of the "current" line.
570 */
571int
572plpgsql_location_to_lineno(int location, yyscan_t yyscanner)
573{
574 const char *loc;
575
577 return 0; /* garbage in, garbage out */
578 loc = yyextra->scanorig + location;
579
580 /* be correct, but not fast, if input location goes backwards */
582 location_lineno_init(yyscanner);
583
584 while (yyextra->cur_line_end != NULL && loc > yyextra->cur_line_end)
585 {
586 yyextra->cur_line_start = yyextra->cur_line_end + 1;
587 yyextra->cur_line_num++;
588 yyextra->cur_line_end = strchr(yyextra->cur_line_start, '\n');
589 }
590
591 return yyextra->cur_line_num;
592}
593
594/* initialize or reset the state for plpgsql_location_to_lineno */
595static void
597{
598 yyextra->cur_line_start = yyextra->scanorig;
599 yyextra->cur_line_num = 1;
600
601 yyextra->cur_line_end = strchr(yyextra->cur_line_start, '\n');
602}
603
604/* return the most recently computed lineno */
605int
607{
608 return yyextra->cur_line_num;
609}
610
611
612/*
613 * Called before any actual parsing is done
614 *
615 * Note: the passed "str" must remain valid until plpgsql_scanner_finish().
616 * Although it is not fed directly to flex, we need the original string
617 * to cite in error messages.
618 */
620plpgsql_scanner_init(const char *str)
621{
622 yyscan_t yyscanner;
624
625 /* Start up the core scanner */
626 yyscanner = scanner_init(str, (core_yy_extra_type *) yyext,
628
629 /*
630 * scanorig points to the original string, which unlike the scanner's
631 * scanbuf won't be modified on-the-fly by flex. Notice that although
632 * yytext points into scanbuf, we rely on being able to apply locations
633 * (offsets from string start) to scanorig as well.
634 */
635 yyext->scanorig = str;
636
637 /* Other setup */
639 yyext->plpgsql_yytoken = 0;
640
641 yyext->num_pushbacks = 0;
642
643 location_lineno_init(yyscanner);
644
645 return yyscanner;
646}
647
648/*
649 * Called after parsing is done to clean up after plpgsql_scanner_init()
650 */
651void
653{
654 /* release storage */
655 scanner_finish(yyscanner);
656}
#define Assert(condition)
Definition c.h:873
#define lengthof(array)
Definition c.h:803
void * yyscan_t
Definition cubedata.h:65
int internalerrquery(const char *query)
Definition elog.c:1516
int internalerrposition(int cursorpos)
Definition elog.c:1496
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define _(x)
Definition elog.c:91
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
#define palloc0_object(type)
Definition fe_memutils.h:75
const char * str
#define token
int i
Definition isn.c:77
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:1060
char * pstrdup(const char *in)
Definition mcxt.c:1781
static char buf[DEFAULT_XLOG_SEG_SIZE]
bool plpgsql_parse_dblword(char *word1, char *word2, PLwdatum *wdatum, PLcword *cword)
Definition pl_comp.c:1358
bool plpgsql_parse_word(char *word1, const char *yytxt, bool lookup, PLwdatum *wdatum, PLword *word)
Definition pl_comp.c:1303
bool plpgsql_parse_tripword(char *word1, char *word2, char *word3, PLwdatum *wdatum, PLcword *cword)
Definition pl_comp.c:1439
#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:653
#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:621
void plpgsql_yyerror(YYLTYPE *yyllocp, PLpgSQL_stmt_block **plpgsql_parse_result_p, yyscan_t yyscanner, const char *message)
Definition pl_scanner.c:534
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:573
static void location_lineno_init(yyscan_t yyscanner)
Definition pl_scanner.c:597
int plpgsql_latest_lineno(yyscan_t yyscanner)
Definition pl_scanner.c:607
#define MAX_PUSHBACKS
Definition pl_scanner.c:98
@ IDENTIFIER_LOOKUP_NORMAL
Definition plpgsql.h:1180
const char * YYLTYPE
int YYSTYPE
core_yyscan_t scanner_init(const char *str, core_yy_extra_type *yyext, const ScanKeywordList *keywordlist, const uint16 *keyword_tokens)
Definition scan.l:1224
void scanner_finish(core_yyscan_t yyscanner)
Definition scan.l:1264
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
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

◆ MAX_PUSHBACKS

#define MAX_PUSHBACKS   4

Definition at line 98 of file pl_scanner.c.

◆ PG_KEYWORD

#define PG_KEYWORD (   kwname,
  value 
)    value,

Definition at line 64 of file pl_scanner.c.

◆ yyextra

#define yyextra   (((struct yyguts_t *) yyscanner)->yyextra_r)

Definition at line 147 of file pl_scanner.c.

Function Documentation

◆ internal_yylex()

static int internal_yylex ( TokenAuxData auxdata,
yyscan_t  yyscanner 
)
static

Definition at line 339 of file pl_scanner.c.

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)
365 else if (strcmp(auxdata->lval.str, ">>") == 0)
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}

References core_yylex(), fb(), pstrdup(), token, and yyextra.

Referenced by plpgsql_peek(), plpgsql_peek2(), and plpgsql_yylex().

◆ location_lineno_init()

static void location_lineno_init ( yyscan_t  yyscanner)
static

Definition at line 597 of file pl_scanner.c.

598{
599 yyextra->cur_line_start = yyextra->scanorig;
600 yyextra->cur_line_num = 1;
601
602 yyextra->cur_line_end = strchr(yyextra->cur_line_start, '\n');
603}

References fb(), and yyextra.

Referenced by plpgsql_location_to_lineno(), and plpgsql_scanner_init().

◆ plpgsql_append_source_text()

void plpgsql_append_source_text ( StringInfo  buf,
int  startlocation,
int  endlocation,
yyscan_t  yyscanner 
)

Definition at line 435 of file pl_scanner.c.

References appendBinaryStringInfo(), Assert, buf, fb(), and yyextra.

◆ plpgsql_latest_lineno()

int plpgsql_latest_lineno ( yyscan_t  yyscanner)

Definition at line 607 of file pl_scanner.c.

608{
609 return yyextra->cur_line_num;
610}

References yyextra.

Referenced by plpgsql_compile_error_callback().

◆ plpgsql_location_to_lineno()

int plpgsql_location_to_lineno ( int  location,
yyscan_t  yyscanner 
)

Definition at line 573 of file pl_scanner.c.

574{
575 const char *loc;
576
577 if (location < 0 || yyextra->scanorig == NULL)
578 return 0; /* garbage in, garbage out */
579 loc = yyextra->scanorig + location;
580
581 /* be correct, but not fast, if input location goes backwards */
582 if (loc < yyextra->cur_line_start)
583 location_lineno_init(yyscanner);
584
585 while (yyextra->cur_line_end != NULL && loc > yyextra->cur_line_end)
586 {
587 yyextra->cur_line_start = yyextra->cur_line_end + 1;
588 yyextra->cur_line_num++;
589 yyextra->cur_line_end = strchr(yyextra->cur_line_start, '\n');
590 }
591
592 return yyextra->cur_line_num;
593}

References plpgsql_yy_extra_type::cur_line_start, fb(), location_lineno_init(), plpgsql_yy_extra_type::scanorig, and yyextra.

◆ plpgsql_peek()

int plpgsql_peek ( yyscan_t  yyscanner)

Definition at line 452 of file pl_scanner.c.

453{
454 int tok1;
456
457 tok1 = internal_yylex(&aux1, yyscanner);
458 push_back_token(tok1, &aux1, yyscanner);
459 return tok1;
460}

References fb(), internal_yylex(), and push_back_token().

◆ plpgsql_peek2()

void plpgsql_peek2 ( int tok1_p,
int tok2_p,
int tok1_loc,
int tok2_loc,
yyscan_t  yyscanner 
)

Definition at line 471 of file pl_scanner.c.

472{
473 int tok1,
474 tok2;
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}

References fb(), internal_yylex(), and push_back_token().

◆ plpgsql_push_back_token()

void plpgsql_push_back_token ( int  token,
YYSTYPE yylvalp,
YYLTYPE yyllocp,
yyscan_t  yyscanner 
)

Definition at line 401 of file pl_scanner.c.

402{
404
406 auxdata.lloc = *yyllocp;
407 auxdata.leng = yyextra->plpgsql_yyleng;
408 push_back_token(token, &auxdata, yyscanner);
409}

References fb(), TokenAuxData::lval, push_back_token(), and yyextra.

◆ plpgsql_scanner_errposition()

int plpgsql_scanner_errposition ( int  location,
yyscan_t  yyscanner 
)

Definition at line 504 of file pl_scanner.c.

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 */
515 /* Also pass the function body string */
516 return internalerrquery(yyextra->scanorig);
517}

References fb(), internalerrposition(), internalerrquery(), pg_mbstrlen_with_len(), plpgsql_yy_extra_type::scanorig, and yyextra.

Referenced by plpgsql_yyerror().

◆ plpgsql_scanner_finish()

void plpgsql_scanner_finish ( yyscan_t  yyscanner)

Definition at line 653 of file pl_scanner.c.

654{
655 /* release storage */
656 scanner_finish(yyscanner);
657}

References scanner_finish().

Referenced by plpgsql_compile_callback(), and plpgsql_compile_inline().

◆ plpgsql_scanner_init()

yyscan_t plpgsql_scanner_init ( const char str)

Definition at line 621 of file pl_scanner.c.

622{
623 yyscan_t yyscanner;
625
626 /* Start up the core scanner */
627 yyscanner = scanner_init(str, (core_yy_extra_type *) yyext,
629
630 /*
631 * scanorig points to the original string, which unlike the scanner's
632 * scanbuf won't be modified on-the-fly by flex. Notice that although
633 * yytext points into scanbuf, we rely on being able to apply locations
634 * (offsets from string start) to scanorig as well.
635 */
636 yyext->scanorig = str;
637
638 /* Other setup */
640 yyext->plpgsql_yytoken = 0;
641
642 yyext->num_pushbacks = 0;
643
644 location_lineno_init(yyscanner);
645
646 return yyscanner;
647}

References fb(), IDENTIFIER_LOOKUP_NORMAL, location_lineno_init(), palloc0_object, plpgsql_IdentifierLookup, ReservedPLKeywordTokens, scanner_init(), and str.

Referenced by plpgsql_compile_callback(), and plpgsql_compile_inline().

◆ plpgsql_token_is_unreserved_keyword()

bool plpgsql_token_is_unreserved_keyword ( int  token)

Definition at line 418 of file pl_scanner.c.

419{
420 int i;
421
422 for (i = 0; i < lengthof(UnreservedPLKeywordTokens); i++)
423 {
425 return true;
426 }
427 return false;
428}

References i, lengthof, and UnreservedPLKeywordTokens.

◆ plpgsql_token_length()

int plpgsql_token_length ( yyscan_t  yyscanner)

Definition at line 327 of file pl_scanner.c.

328{
329 return yyextra->plpgsql_yyleng;
330}

References yyextra.

◆ plpgsql_yyerror()

void plpgsql_yyerror ( YYLTYPE yyllocp,
PLpgSQL_stmt_block **  plpgsql_parse_result_p,
yyscan_t  yyscanner,
const char message 
)

Definition at line 534 of file pl_scanner.c.

535{
536 char *yytext = yyextra->core_yy_extra.scanbuf + *yyllocp;
537
538 if (*yytext == '\0')
539 {
542 /* translator: %s is typically the translation of "syntax error" */
543 errmsg("%s at end of input", _(message)),
545 }
546 else
547 {
548 /*
549 * If we have done any lookahead then flex will have restored the
550 * character after the end-of-token. Zap it again so that we report
551 * only the single token here. This modifies scanbuf but we no longer
552 * care about that.
553 */
554 yytext[yyextra->plpgsql_yyleng] = '\0';
555
558 /* translator: first %s is typically the translation of "syntax error" */
559 errmsg("%s at or near \"%s\"", _(message), yytext),
561 }
562}

References _, ereport, errcode(), errmsg(), ERROR, fb(), plpgsql_scanner_errposition(), and yyextra.

◆ plpgsql_yylex()

int plpgsql_yylex ( YYSTYPE yylvalp,
YYLTYPE yyllocp,
yyscan_t  yyscanner 
)

Definition at line 160 of file pl_scanner.c.

161{
162 int tok1;
164 int kwnum;
165
166 tok1 = internal_yylex(&aux1, yyscanner);
167 if (tok1 == IDENT || tok1 == PARAM)
168 {
169 int tok2;
171
172 tok2 = internal_yylex(&aux2, yyscanner);
173 if (tok2 == '.')
174 {
175 int tok3;
177
178 tok3 = internal_yylex(&aux3, yyscanner);
179 if (tok3 == IDENT)
180 {
181 int tok4;
183
184 tok4 = internal_yylex(&aux4, yyscanner);
185 if (tok4 == '.')
186 {
187 int tok5;
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,
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,
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}

References AT_STMT_START, fb(), GetScanKeyword(), internal_yylex(), plpgsql_parse_dblword(), plpgsql_parse_tripword(), plpgsql_parse_word(), push_back_token(), ScanKeywordLookup(), UnreservedPLKeywordTokens, and yyextra.

◆ push_back_token()

static void push_back_token ( int  token,
TokenAuxData auxdata,
yyscan_t  yyscanner 
)
static

Definition at line 385 of file pl_scanner.c.

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}

References elog, ERROR, fb(), MAX_PUSHBACKS, token, and yyextra.

Referenced by plpgsql_peek(), plpgsql_peek2(), plpgsql_push_back_token(), and plpgsql_yylex().

Variable Documentation

◆ plpgsql_IdentifierLookup

◆ ReservedPLKeywordTokens

const uint16 ReservedPLKeywordTokens[]
static
Initial value:
= {
}

Definition at line 66 of file pl_scanner.c.

Referenced by plpgsql_scanner_init().

◆ UnreservedPLKeywordTokens

const uint16 UnreservedPLKeywordTokens[]
static
Initial value:
= {
}

Definition at line 70 of file pl_scanner.c.

Referenced by plpgsql_token_is_unreserved_keyword(), and plpgsql_yylex().