Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Functions | Variables

pl_scanner.c File Reference

#include "plpgsql.h"
#include "mb/pg_wchar.h"
#include "parser/scanner.h"
#include "pl_gram.h"
Include dependency graph for pl_scanner.c:

Go to the source code of this file.

Data Structures

struct  TokenAuxData

Defines

#define PG_KEYWORD(a, b, c)   {a,b,c},
#define MAX_PUSHBACKS   4

Functions

static int internal_yylex (TokenAuxData *auxdata)
static void push_back_token (int token, TokenAuxData *auxdata)
static void location_lineno_init (void)
int plpgsql_yylex (void)
void plpgsql_push_back_token (int token)
bool plpgsql_token_is_unreserved_keyword (int token)
void plpgsql_append_source_text (StringInfo buf, int startlocation, int endlocation)
int plpgsql_peek (void)
void plpgsql_peek2 (int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc)
int plpgsql_scanner_errposition (int location)
void __attribute__ ((noreturn))
int plpgsql_location_to_lineno (int location)
int plpgsql_latest_lineno (void)
void plpgsql_scanner_init (const char *str)
void plpgsql_scanner_finish (void)

Variables

IdentifierLookup plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL
static const ScanKeyword reserved_keywords []
static const int num_reserved_keywords = lengthof(reserved_keywords)
static const ScanKeyword unreserved_keywords []
static const int num_unreserved_keywords = lengthof(unreserved_keywords)
static core_yyscan_t yyscanner = NULL
static core_yy_extra_type core_yy
static const char * scanorig
static int plpgsql_yyleng
static int num_pushbacks
static int pushback_token [MAX_PUSHBACKS]
static TokenAuxData pushback_auxdata [MAX_PUSHBACKS]
static const char * cur_line_start
static const char * cur_line_end
static int cur_line_num

Define Documentation

#define MAX_PUSHBACKS   4

Definition at line 184 of file pl_scanner.c.

Referenced by push_back_token().

#define PG_KEYWORD (   a,
  b,
  c 
)    {a,b,c},

Definition at line 23 of file pl_scanner.c.


Function Documentation

void __attribute__ ( (noreturn  ) 

Definition at line 531 of file pl_scanner.c.

References _, ereport, errcode(), errmsg(), ERROR, plpgsql_scanner_errposition(), plpgsql_yyleng, core_yy_extra_type::scanbuf, and yytext.

{
    char       *yytext = core_yy.scanbuf + plpgsql_yylloc;

    if (*yytext == '\0')
    {
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
        /* translator: %s is typically the translation of "syntax error" */
                 errmsg("%s at end of input", _(message)),
                 plpgsql_scanner_errposition(plpgsql_yylloc)));
    }
    else
    {
        /*
         * If we have done any lookahead then flex will have restored the
         * character after the end-of-token.  Zap it again so that we report
         * only the single token here.  This modifies scanbuf but we no longer
         * care about that.
         */
        yytext[plpgsql_yyleng] = '\0';

        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
        /* translator: first %s is typically the translation of "syntax error" */
                 errmsg("%s at or near \"%s\"", _(message), yytext),
                 plpgsql_scanner_errposition(plpgsql_yylloc)));
    }
}

static int internal_yylex ( TokenAuxData auxdata  )  [static]

Definition at line 341 of file pl_scanner.c.

References core_yylex(), TokenAuxData::leng, TokenAuxData::lloc, TokenAuxData::lval, num_pushbacks, pstrdup(), pushback_token, core_yy_extra_type::scanbuf, yyscanner, and yytext.

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

{
    int         token;
    const char *yytext;

    if (num_pushbacks > 0)
    {
        num_pushbacks--;
        token = pushback_token[num_pushbacks];
        *auxdata = pushback_auxdata[num_pushbacks];
    }
    else
    {
        token = core_yylex(&auxdata->lval.core_yystype,
                           &auxdata->lloc,
                           yyscanner);

        /* remember the length of yytext before it gets changed */
        yytext = core_yy.scanbuf + auxdata->lloc;
        auxdata->leng = strlen(yytext);

        /* Check for << >> and #, which the core considers operators */
        if (token == Op)
        {
            if (strcmp(auxdata->lval.str, "<<") == 0)
                token = LESS_LESS;
            else if (strcmp(auxdata->lval.str, ">>") == 0)
                token = GREATER_GREATER;
            else if (strcmp(auxdata->lval.str, "#") == 0)
                token = '#';
        }

        /* The core returns PARAM as ival, but we treat it like IDENT */
        else if (token == PARAM)
        {
            auxdata->lval.str = pstrdup(yytext);
        }
    }

    return token;
}

static void location_lineno_init ( void   )  [static]
void plpgsql_append_source_text ( StringInfo  buf,
int  startlocation,
int  endlocation 
)

Definition at line 437 of file pl_scanner.c.

References appendBinaryStringInfo(), Assert, and scanorig.

{
    Assert(startlocation <= endlocation);
    appendBinaryStringInfo(buf, scanorig + startlocation,
                           endlocation - startlocation);
}

int plpgsql_latest_lineno ( void   ) 

Definition at line 605 of file pl_scanner.c.

References cur_line_num.

Referenced by plpgsql_compile_error_callback().

{
    return cur_line_num;
}

int plpgsql_location_to_lineno ( int  location  ) 

Definition at line 571 of file pl_scanner.c.

References cur_line_end, cur_line_num, cur_line_start, location_lineno_init(), NULL, and scanorig.

{
    const char *loc;

    if (location < 0 || scanorig == NULL)
        return 0;               /* garbage in, garbage out */
    loc = scanorig + location;

    /* be correct, but not fast, if input location goes backwards */
    if (loc < cur_line_start)
        location_lineno_init();

    while (cur_line_end != NULL && loc > cur_line_end)
    {
        cur_line_start = cur_line_end + 1;
        cur_line_num++;
        cur_line_end = strchr(cur_line_start, '\n');
    }

    return cur_line_num;
}

int plpgsql_peek ( void   ) 

Definition at line 453 of file pl_scanner.c.

References internal_yylex(), and push_back_token().

{
    int         tok1;
    TokenAuxData aux1;

    tok1 = internal_yylex(&aux1);
    push_back_token(tok1, &aux1);
    return tok1;
}

void plpgsql_peek2 ( int *  tok1_p,
int *  tok2_p,
int *  tok1_loc,
int *  tok2_loc 
)

Definition at line 472 of file pl_scanner.c.

References internal_yylex(), TokenAuxData::lloc, and push_back_token().

{
    int         tok1,
                tok2;
    TokenAuxData aux1,
                aux2;

    tok1 = internal_yylex(&aux1);
    tok2 = internal_yylex(&aux2);

    *tok1_p = tok1;
    if (tok1_loc)
        *tok1_loc = aux1.lloc;
    *tok2_p = tok2;
    if (tok2_loc)
        *tok2_loc = aux2.lloc;

    push_back_token(tok2, &aux2);
    push_back_token(tok1, &aux1);
}

void plpgsql_push_back_token ( int  token  ) 

Definition at line 403 of file pl_scanner.c.

References TokenAuxData::leng, TokenAuxData::lloc, TokenAuxData::lval, plpgsql_yyleng, and push_back_token().

{
    TokenAuxData auxdata;

    auxdata.lval = plpgsql_yylval;
    auxdata.lloc = plpgsql_yylloc;
    auxdata.leng = plpgsql_yyleng;
    push_back_token(token, &auxdata);
}

int plpgsql_scanner_errposition ( int  location  ) 

Definition at line 505 of file pl_scanner.c.

References internalerrposition(), internalerrquery(), NULL, pg_mbstrlen_with_len(), and scanorig.

Referenced by __attribute__().

{
    int         pos;

    if (location < 0 || scanorig == NULL)
        return 0;               /* no-op if location is unknown */

    /* Convert byte offset to character number */
    pos = pg_mbstrlen_with_len(scanorig, location) + 1;
    /* And pass it to the ereport mechanism */
    (void) internalerrposition(pos);
    /* Also pass the function body string */
    return internalerrquery(scanorig);
}

void plpgsql_scanner_finish ( void   ) 

Definition at line 645 of file pl_scanner.c.

References scanner_finish(), scanorig, and yyscanner.

Referenced by do_compile(), and plpgsql_compile_inline().

{
    /* release storage */
    scanner_finish(yyscanner);
    /* avoid leaving any dangling pointers */
    yyscanner = NULL;
    scanorig = NULL;
}

void plpgsql_scanner_init ( const char *  str  ) 

Definition at line 619 of file pl_scanner.c.

References location_lineno_init(), num_pushbacks, num_reserved_keywords, plpgsql_IdentifierLookup, scanner_init(), scanorig, and yyscanner.

Referenced by do_compile(), and plpgsql_compile_inline().

{
    /* Start up the core scanner */
    yyscanner = scanner_init(str, &core_yy,
                             reserved_keywords, num_reserved_keywords);

    /*
     * scanorig points to the original string, which unlike the scanner's
     * scanbuf won't be modified on-the-fly by flex.  Notice that although
     * yytext points into scanbuf, we rely on being able to apply locations
     * (offsets from string start) to scanorig as well.
     */
    scanorig = str;

    /* Other setup */
    plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;

    num_pushbacks = 0;

    location_lineno_init();
}

bool plpgsql_token_is_unreserved_keyword ( int  token  ) 

Definition at line 420 of file pl_scanner.c.

References i, num_unreserved_keywords, and value.

{
    int         i;

    for (i = 0; i < num_unreserved_keywords; i++)
    {
        if (unreserved_keywords[i].value == token)
            return true;
    }
    return false;
}

int plpgsql_yylex ( void   ) 

Definition at line 211 of file pl_scanner.c.

References internal_yylex(), TokenAuxData::leng, TokenAuxData::lloc, TokenAuxData::lval, ScanKeyword::name, num_unreserved_keywords, plpgsql_parse_dblword(), plpgsql_parse_tripword(), plpgsql_parse_word(), plpgsql_yyleng, push_back_token(), core_yy_extra_type::scanbuf, ScanKeywordLookup(), and ScanKeyword::value.

{
    int         tok1;
    TokenAuxData aux1;
    const ScanKeyword *kw;

    tok1 = internal_yylex(&aux1);
    if (tok1 == IDENT || tok1 == PARAM)
    {
        int         tok2;
        TokenAuxData aux2;

        tok2 = internal_yylex(&aux2);
        if (tok2 == '.')
        {
            int         tok3;
            TokenAuxData aux3;

            tok3 = internal_yylex(&aux3);
            if (tok3 == IDENT)
            {
                int         tok4;
                TokenAuxData aux4;

                tok4 = internal_yylex(&aux4);
                if (tok4 == '.')
                {
                    int         tok5;
                    TokenAuxData aux5;

                    tok5 = internal_yylex(&aux5);
                    if (tok5 == IDENT)
                    {
                        if (plpgsql_parse_tripword(aux1.lval.str,
                                                   aux3.lval.str,
                                                   aux5.lval.str,
                                                   &aux1.lval.wdatum,
                                                   &aux1.lval.cword))
                            tok1 = T_DATUM;
                        else
                            tok1 = T_CWORD;
                    }
                    else
                    {
                        /* not A.B.C, so just process A.B */
                        push_back_token(tok5, &aux5);
                        push_back_token(tok4, &aux4);
                        if (plpgsql_parse_dblword(aux1.lval.str,
                                                  aux3.lval.str,
                                                  &aux1.lval.wdatum,
                                                  &aux1.lval.cword))
                            tok1 = T_DATUM;
                        else
                            tok1 = T_CWORD;
                    }
                }
                else
                {
                    /* not A.B.C, so just process A.B */
                    push_back_token(tok4, &aux4);
                    if (plpgsql_parse_dblword(aux1.lval.str,
                                              aux3.lval.str,
                                              &aux1.lval.wdatum,
                                              &aux1.lval.cword))
                        tok1 = T_DATUM;
                    else
                        tok1 = T_CWORD;
                }
            }
            else
            {
                /* not A.B, so just process A */
                push_back_token(tok3, &aux3);
                push_back_token(tok2, &aux2);
                if (plpgsql_parse_word(aux1.lval.str,
                                       core_yy.scanbuf + aux1.lloc,
                                       &aux1.lval.wdatum,
                                       &aux1.lval.word))
                    tok1 = T_DATUM;
                else if (!aux1.lval.word.quoted &&
                         (kw = ScanKeywordLookup(aux1.lval.word.ident,
                                                 unreserved_keywords,
                                                 num_unreserved_keywords)))
                {
                    aux1.lval.keyword = kw->name;
                    tok1 = kw->value;
                }
                else
                    tok1 = T_WORD;
            }
        }
        else
        {
            /* not A.B, so just process A */
            push_back_token(tok2, &aux2);
            if (plpgsql_parse_word(aux1.lval.str,
                                   core_yy.scanbuf + aux1.lloc,
                                   &aux1.lval.wdatum,
                                   &aux1.lval.word))
                tok1 = T_DATUM;
            else if (!aux1.lval.word.quoted &&
                     (kw = ScanKeywordLookup(aux1.lval.word.ident,
                                             unreserved_keywords,
                                             num_unreserved_keywords)))
            {
                aux1.lval.keyword = kw->name;
                tok1 = kw->value;
            }
            else
                tok1 = T_WORD;
        }
    }
    else
    {
        /* Not a potential plpgsql variable name, just return the data */
    }

    plpgsql_yylval = aux1.lval;
    plpgsql_yylloc = aux1.lloc;
    plpgsql_yyleng = aux1.leng;
    return tok1;
}

static void push_back_token ( int  token,
TokenAuxData auxdata 
) [static]

Definition at line 387 of file pl_scanner.c.

References elog, ERROR, MAX_PUSHBACKS, num_pushbacks, and pushback_token.

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

{
    if (num_pushbacks >= MAX_PUSHBACKS)
        elog(ERROR, "too many tokens pushed back");
    pushback_token[num_pushbacks] = token;
    pushback_auxdata[num_pushbacks] = *auxdata;
    num_pushbacks++;
}


Variable Documentation

Definition at line 175 of file pl_scanner.c.

const char* cur_line_end [static]

Definition at line 192 of file pl_scanner.c.

Referenced by location_lineno_init(), and plpgsql_location_to_lineno().

int cur_line_num [static]
const char* cur_line_start [static]

Definition at line 191 of file pl_scanner.c.

Referenced by location_lineno_init(), and plpgsql_location_to_lineno().

int num_pushbacks [static]

Definition at line 186 of file pl_scanner.c.

Referenced by internal_yylex(), plpgsql_scanner_init(), and push_back_token().

const int num_reserved_keywords = lengthof(reserved_keywords) [static]

Definition at line 105 of file pl_scanner.c.

Referenced by plpgsql_scanner_init().

const int num_unreserved_keywords = lengthof(unreserved_keywords) [static]

Definition at line 155 of file pl_scanner.c.

Referenced by plpgsql_token_is_unreserved_keyword(), and plpgsql_yylex().

IdentifierLookup plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL
int plpgsql_yyleng [static]

Definition at line 181 of file pl_scanner.c.

Referenced by __attribute__(), plpgsql_push_back_token(), and plpgsql_yylex().

TokenAuxData pushback_auxdata[MAX_PUSHBACKS] [static]

Definition at line 188 of file pl_scanner.c.

int pushback_token[MAX_PUSHBACKS] [static]

Definition at line 187 of file pl_scanner.c.

Referenced by internal_yylex(), and push_back_token().

const ScanKeyword reserved_keywords[] [static]

Definition at line 61 of file pl_scanner.c.

const char* scanorig [static]
const ScanKeyword unreserved_keywords[] [static]

Definition at line 107 of file pl_scanner.c.

core_yyscan_t yyscanner = NULL [static]