#include "postgres.h"
#include "mb/pg_wchar.h"
#include "parser/scanner.h"
#include "plpgsql.h"
#include "pl_gram.h"
__thread IdentifierLookup plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
#include "pl_reserved_kwlist_d.h"
#include "pl_unreserved_kwlist_d.h"
#define PG_KEYWORD(kwname, value) value,
static const uint16 ReservedPLKeywordTokens[] = {
#include "pl_reserved_kwlist.h"
};
static const uint16 UnreservedPLKeywordTokens[] = {
#include "pl_unreserved_kwlist.h"
};
#undef PG_KEYWORD
#define AT_STMT_START(prev_token) \
((prev_token) == ';' || \
(prev_token) == K_BEGIN || \
(prev_token) == K_THEN || \
(prev_token) == K_ELSE || \
(prev_token) == K_LOOP)
typedef struct
{
YYSTYPE lval;
YYLTYPE lloc;
int leng;
} TokenAuxData;
#define MAX_PUSHBACKS 4
struct plpgsql_yy_extra_type
{
core_yy_extra_type core_yy_extra;
const char *scanorig;
int plpgsql_yyleng;
int plpgsql_yytoken;
int num_pushbacks;
int pushback_token[MAX_PUSHBACKS];
TokenAuxData pushback_auxdata[MAX_PUSHBACKS];
const char *cur_line_start;
const char *cur_line_end;
int cur_line_num;
};
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);
struct yyguts_t
{
struct plpgsql_yy_extra_type *yyextra_r;
};
#undef yyextra
#define yyextra (((struct yyguts_t *) yyscanner)->yyextra_r)
int
plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
{
int tok1;
TokenAuxData aux1;
int kwnum;
tok1 = internal_yylex(&aux1, yyscanner);
if (tok1 == IDENT || tok1 == PARAM)
{
int tok2;
TokenAuxData aux2;
tok2 = internal_yylex(&aux2, yyscanner);
if (tok2 == '.')
{
int tok3;
TokenAuxData aux3;
tok3 = internal_yylex(&aux3, yyscanner);
if (tok3 == IDENT)
{
int tok4;
TokenAuxData aux4;
tok4 = internal_yylex(&aux4, yyscanner);
if (tok4 == '.')
{
int tok5;
TokenAuxData aux5;
tok5 = internal_yylex(&aux5, yyscanner);
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;
aux1.leng = aux5.lloc - aux1.lloc + aux5.leng;
}
else
{
push_back_token(tok5, &aux5, yyscanner);
push_back_token(tok4, &aux4, yyscanner);
if (plpgsql_parse_dblword(aux1.lval.str,
aux3.lval.str,
&aux1.lval.wdatum,
&aux1.lval.cword))
tok1 = T_DATUM;
else
tok1 = T_CWORD;
aux1.leng = aux3.lloc - aux1.lloc + aux3.leng;
}
}
else
{
push_back_token(tok4, &aux4, yyscanner);
if (plpgsql_parse_dblword(aux1.lval.str,
aux3.lval.str,
&aux1.lval.wdatum,
&aux1.lval.cword))
tok1 = T_DATUM;
else
tok1 = T_CWORD;
aux1.leng = aux3.lloc - aux1.lloc + aux3.leng;
}
}
else
{
push_back_token(tok3, &aux3, yyscanner);
push_back_token(tok2, &aux2, yyscanner);
if (plpgsql_parse_word(aux1.lval.str,
yyextra->core_yy_extra.scanbuf + aux1.lloc,
true,
&aux1.lval.wdatum,
&aux1.lval.word))
tok1 = T_DATUM;
else if (!aux1.lval.word.quoted &&
(kwnum = ScanKeywordLookup(aux1.lval.word.ident,
&UnreservedPLKeywords)) >= 0)
{
aux1.lval.keyword = GetScanKeyword(kwnum,
&UnreservedPLKeywords);
tok1 = UnreservedPLKeywordTokens[kwnum];
}
else
tok1 = T_WORD;
}
}
else
{
push_back_token(tok2, &aux2, yyscanner);
if (plpgsql_parse_word(aux1.lval.str,
yyextra->core_yy_extra.scanbuf + aux1.lloc,
(!AT_STMT_START(yyextra->plpgsql_yytoken) ||
(tok2 == '=' || tok2 == COLON_EQUALS ||
tok2 == '[')),
&aux1.lval.wdatum,
&aux1.lval.word))
tok1 = T_DATUM;
else if (!aux1.lval.word.quoted &&
(kwnum = ScanKeywordLookup(aux1.lval.word.ident,
&UnreservedPLKeywords)) >= 0)
{
aux1.lval.keyword = GetScanKeyword(kwnum,
&UnreservedPLKeywords);
tok1 = UnreservedPLKeywordTokens[kwnum];
}
else
tok1 = T_WORD;
}
}
else
{
}
*yylvalp = aux1.lval;
*yyllocp = aux1.lloc;
yyextra->plpgsql_yyleng = aux1.leng;
yyextra->plpgsql_yytoken = tok1;
return tok1;
}
int
plpgsql_token_length(yyscan_t yyscanner)
{
return yyextra->plpgsql_yyleng;
}
static int
internal_yylex(TokenAuxData *auxdata, yyscan_t yyscanner)
{
int token;
const char *yytext;
if (yyextra->num_pushbacks > 0)
{
yyextra->num_pushbacks--;
token = yyextra->pushback_token[yyextra->num_pushbacks];
*auxdata = yyextra->pushback_auxdata[yyextra->num_pushbacks];
}
else
{
token = core_yylex(&auxdata->lval.core_yystype,
&auxdata->lloc,
yyscanner);
yytext = yyextra->core_yy_extra.scanbuf + auxdata->lloc;
auxdata->leng = strlen(yytext);
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 = '#';
}
else if (token == PARAM)
{
auxdata->lval.str = pstrdup(yytext);
}
else if (token == SQL_COMMENT || token == C_COMMENT)
{
token = internal_yylex(auxdata, yyscanner);
}
}
return token;
}
static void
push_back_token(int token, TokenAuxData *auxdata, yyscan_t yyscanner)
{
if (yyextra->num_pushbacks >= MAX_PUSHBACKS)
elog(ERROR, "too many tokens pushed back");
yyextra->pushback_token[yyextra->num_pushbacks] = token;
yyextra->pushback_auxdata[yyextra->num_pushbacks] = *auxdata;
yyextra->num_pushbacks++;
}
void
plpgsql_push_back_token(int token, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
{
TokenAuxData auxdata;
auxdata.lval = *yylvalp;
auxdata.lloc = *yyllocp;
auxdata.leng = yyextra->plpgsql_yyleng;
push_back_token(token, &auxdata, yyscanner);
}
bool
plpgsql_token_is_unreserved_keyword(int token)
{
int i;
for (i = 0; i < lengthof(UnreservedPLKeywordTokens); i++)
{
if (UnreservedPLKeywordTokens[i] == token)
return true;
}
return false;
}
void
plpgsql_append_source_text(StringInfo buf,
int startlocation, int endlocation,
yyscan_t yyscanner)
{
Assert(startlocation <= endlocation);
appendBinaryStringInfo(buf, yyextra->scanorig + startlocation,
endlocation - startlocation);
}
int
plpgsql_peek(yyscan_t yyscanner)
{
int tok1;
TokenAuxData aux1;
tok1 = internal_yylex(&aux1, yyscanner);
push_back_token(tok1, &aux1, yyscanner);
return tok1;
}
void
plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc, yyscan_t yyscanner)
{
int tok1,
tok2;
TokenAuxData aux1,
aux2;
tok1 = internal_yylex(&aux1, yyscanner);
tok2 = internal_yylex(&aux2, yyscanner);
*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, yyscanner);
push_back_token(tok1, &aux1, yyscanner);
}
int
plpgsql_scanner_errposition(int location, yyscan_t yyscanner)
{
int pos;
if (location < 0 || yyextra->scanorig == NULL)
return 0;
pos = pg_mbstrlen_with_len(yyextra->scanorig, location) + 1;
(void) internalerrposition(pos);
return internalerrquery(yyextra->scanorig);
}
void
plpgsql_yyerror(YYLTYPE *yyllocp, PLpgSQL_stmt_block **plpgsql_parse_result_p, yyscan_t yyscanner, const char *message)
{
char *yytext = yyextra->core_yy_extra.scanbuf + *yyllocp;
if (*yytext == '\0')
{
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("%s at end of input", _(message)),
plpgsql_scanner_errposition(*yyllocp, yyscanner)));
}
else
{
yytext[yyextra->plpgsql_yyleng] = '\0';
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("%s at or near \"%s\"", _(message), yytext),
plpgsql_scanner_errposition(*yyllocp, yyscanner)));
}
}
int
plpgsql_location_to_lineno(int location, yyscan_t yyscanner)
{
const char *loc;
if (location < 0 || yyextra->scanorig == NULL)
return 0;
loc = yyextra->scanorig + location;
if (loc < yyextra->cur_line_start)
location_lineno_init(yyscanner);
while (yyextra->cur_line_end != NULL && loc > yyextra->cur_line_end)
{
yyextra->cur_line_start = yyextra->cur_line_end + 1;
yyextra->cur_line_num++;
yyextra->cur_line_end = strchr(yyextra->cur_line_start, '\n');
}
return yyextra->cur_line_num;
}
static void
location_lineno_init(yyscan_t yyscanner)
{
yyextra->cur_line_start = yyextra->scanorig;
yyextra->cur_line_num = 1;
yyextra->cur_line_end = strchr(yyextra->cur_line_start, '\n');
}
int
plpgsql_latest_lineno(yyscan_t yyscanner)
{
return yyextra->cur_line_num;
}
yyscan_t
plpgsql_scanner_init(const char *str)
{
yyscan_t yyscanner;
struct plpgsql_yy_extra_type *yyext = palloc0_object(struct plpgsql_yy_extra_type);
yyscanner = scanner_init(str, (core_yy_extra_type *) yyext,
&ReservedPLKeywords, ReservedPLKeywordTokens);
yyext->scanorig = str;
plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
yyext->plpgsql_yytoken = 0;
yyext->num_pushbacks = 0;
location_lineno_init(yyscanner);
return yyscanner;
}
void
plpgsql_scanner_finish(yyscan_t yyscanner)
{
scanner_finish(yyscanner);
}