From 5821e9ce7ff85f7304c56f8ff0483f2e07b3be8e Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Thu, 26 Dec 2024 00:08:25 +0100 Subject: [PATCH v3 3/4] plpgsql: pure parser --- src/pl/plpgsql/src/nls.mk | 2 +- src/pl/plpgsql/src/pl_gram.y | 602 ++++++++++++++++---------------- src/pl/plpgsql/src/pl_scanner.c | 20 +- src/pl/plpgsql/src/plpgsql.h | 8 +- 4 files changed, 318 insertions(+), 314 deletions(-) diff --git a/src/pl/plpgsql/src/nls.mk b/src/pl/plpgsql/src/nls.mk index ec7c7035add..eb06336675c 100644 --- a/src/pl/plpgsql/src/nls.mk +++ b/src/pl/plpgsql/src/nls.mk @@ -6,5 +6,5 @@ GETTEXT_FILES = pl_comp.c \ pl_funcs.c \ pl_handler.c \ pl_scanner.c -GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS) yyerror:2 plpgsql_yyerror:2 +GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS) yyerror:3 plpgsql_yyerror:3 GETTEXT_FLAGS = $(BACKEND_COMMON_GETTEXT_FLAGS) diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index e8f81d287a1..cb5c2dca186 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -28,10 +28,6 @@ #include "pl_gram.h" -/* silence -Wmissing-variable-declarations */ -extern int plpgsql_yychar; -extern int plpgsql_yynerrs; - /* Location tracking support --- simpler than bison's default */ #define YYLLOC_DEFAULT(Current, Rhs, N) \ do { \ @@ -63,7 +59,7 @@ static bool tok_is_keyword(int token, union YYSTYPE *lval, int kw_token, const char *kw_str); static void word_is_not_variable(PLword *word, int location); static void cword_is_not_variable(PLcword *cword, int location); -static void current_token_is_not_variable(int tok, yyscan_t yyscanner); +static void current_token_is_not_variable(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); static PLpgSQL_expr *read_sql_construct(int until, int until2, int until3, @@ -73,31 +69,33 @@ static PLpgSQL_expr *read_sql_construct(int until, bool valid_sql, int *startloc, int *endtoken, + YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); -static PLpgSQL_expr *read_sql_expression(int until, - const char *expected, yyscan_t yyscanner); +static PLpgSQL_expr *read_sql_expression(int until, const char *expected, + YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); static PLpgSQL_expr *read_sql_expression2(int until, int until2, - const char *expected, - int *endtoken, yyscan_t yyscanner); -static PLpgSQL_expr *read_sql_stmt(yyscan_t yyscanner); -static PLpgSQL_type *read_datatype(int tok, yyscan_t yyscanner); + const char *expected, int *endtoken, + YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); +static PLpgSQL_expr *read_sql_stmt(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); +static PLpgSQL_type *read_datatype(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); static PLpgSQL_stmt *make_execsql_stmt(int firsttoken, int location, - PLword *word, yyscan_t yyscanner); -static PLpgSQL_stmt_fetch *read_fetch_direction(yyscan_t yyscanner); + PLword *word, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); +static PLpgSQL_stmt_fetch *read_fetch_direction(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); static void complete_direction(PLpgSQL_stmt_fetch *fetch, - bool *check_FROM, yyscan_t yyscanner); -static PLpgSQL_stmt *make_return_stmt(int location, yyscan_t yyscanner); -static PLpgSQL_stmt *make_return_next_stmt(int location, yyscan_t yyscanner); -static PLpgSQL_stmt *make_return_query_stmt(int location, yyscan_t yyscanner); + bool *check_FROM, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); +static PLpgSQL_stmt *make_return_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); +static PLpgSQL_stmt *make_return_next_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); +static PLpgSQL_stmt *make_return_query_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); static PLpgSQL_stmt *make_case(int location, PLpgSQL_expr *t_expr, List *case_when_list, List *else_stmts); static char *NameOfDatum(PLwdatum *wdatum); static void check_assignable(PLpgSQL_datum *datum, int location); -static void read_into_target(PLpgSQL_variable **target, - bool *strict, yyscan_t yyscanner); +static void read_into_target(PLpgSQL_variable **target, bool *strict, + YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); static PLpgSQL_row *read_into_scalar_list(char *initial_name, PLpgSQL_datum *initial_datum, int initial_location, + YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); static PLpgSQL_row *make_scalar_list1(char *initial_name, PLpgSQL_datum *initial_datum, @@ -109,15 +107,16 @@ static PLpgSQL_type *parse_datatype(const char *string, int location); static void check_labels(const char *start_label, const char *end_label, int end_location); -static PLpgSQL_expr *read_cursor_args(PLpgSQL_var *cursor, - int until, yyscan_t yyscanner); -static List *read_raise_options(yyscan_t yyscanner); +static PLpgSQL_expr *read_cursor_args(PLpgSQL_var *cursor, int until, + YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); +static List *read_raise_options(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); static void check_raise_parameters(PLpgSQL_stmt_raise *stmt); %} %parse-param {yyscan_t yyscanner} %lex-param {yyscan_t yyscanner} +%pure-parser %expect 0 %name-prefix="plpgsql_yy" %locations @@ -581,7 +580,7 @@ opt_scrollable : decl_cursor_query : { - $$ = read_sql_stmt(yyscanner); + $$ = read_sql_stmt(&yylval, &yylloc, yyscanner); } ; @@ -710,7 +709,7 @@ decl_varname : T_WORD if (plpgsql_ns_lookup(plpgsql_ns_top(), true, $1.ident, NULL, NULL, NULL) != NULL) - yyerror(yyscanner, "duplicate declaration"); + yyerror(&yylloc, yyscanner, "duplicate declaration"); if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR || plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_SHADOWVAR) @@ -738,7 +737,7 @@ decl_varname : T_WORD if (plpgsql_ns_lookup(plpgsql_ns_top(), true, $1, NULL, NULL, NULL) != NULL) - yyerror(yyscanner, "duplicate declaration"); + yyerror(&yylloc, yyscanner, "duplicate declaration"); if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR || plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_SHADOWVAR) @@ -770,7 +769,7 @@ decl_datatype : * consume it, and then we must tell bison to forget * it. */ - $$ = read_datatype(yychar, yyscanner); + $$ = read_datatype(yychar, &yylval, &yylloc, yyscanner); yyclearin; } ; @@ -803,7 +802,7 @@ decl_defval : ';' { $$ = NULL; } | decl_defkey { - $$ = read_sql_expression(';', ";", yyscanner); + $$ = read_sql_expression(';', ";", &yylval, &yylloc, yyscanner); } ; @@ -891,7 +890,7 @@ stmt_perform : K_PERFORM new->cmd_type = PLPGSQL_STMT_PERFORM; new->lineno = plpgsql_location_to_lineno(@1); new->stmtid = ++plpgsql_curr_compile->nstatements; - plpgsql_push_back_token(K_PERFORM); + plpgsql_push_back_token(K_PERFORM, &yylval, &yylloc); /* * Since PERFORM isn't legal SQL, we have to cheat to @@ -905,7 +904,7 @@ stmt_perform : K_PERFORM RAW_PARSE_DEFAULT, false, false, &startloc, NULL, - yyscanner); + &yylval, &yylloc, yyscanner); /* overwrite "perform" ... */ memcpy(new->expr->query, " SELECT", 7); /* left-justify to get rid of the leading space */ @@ -927,8 +926,8 @@ stmt_call : K_CALL new->cmd_type = PLPGSQL_STMT_CALL; new->lineno = plpgsql_location_to_lineno(@1); new->stmtid = ++plpgsql_curr_compile->nstatements; - plpgsql_push_back_token(K_CALL); - new->expr = read_sql_stmt(yyscanner); + plpgsql_push_back_token(K_CALL, &yylval, &yylloc); + new->expr = read_sql_stmt(&yylval, &yylloc, yyscanner); new->is_call = true; /* Remember we may need a procedure resource owner */ @@ -946,8 +945,8 @@ stmt_call : K_CALL new->cmd_type = PLPGSQL_STMT_CALL; new->lineno = plpgsql_location_to_lineno(@1); new->stmtid = ++plpgsql_curr_compile->nstatements; - plpgsql_push_back_token(K_DO); - new->expr = read_sql_stmt(yyscanner); + plpgsql_push_back_token(K_DO, &yylval, &yylloc); + new->expr = read_sql_stmt(&yylval, &yylloc, yyscanner); new->is_call = false; /* Remember we may need a procedure resource owner */ @@ -987,12 +986,12 @@ stmt_assign : T_DATUM new->stmtid = ++plpgsql_curr_compile->nstatements; new->varno = $1.datum->dno; /* Push back the head name to include it in the stmt */ - plpgsql_push_back_token(T_DATUM); + plpgsql_push_back_token(T_DATUM, &yylval, &yylloc); new->expr = read_sql_construct(';', 0, 0, ";", pmode, false, true, NULL, NULL, - yyscanner); + &yylval, &yylloc, yyscanner); $$ = (PLpgSQL_stmt *) new; } @@ -1099,7 +1098,7 @@ getdiag_list_item : getdiag_target assign_operator getdiag_item getdiag_item : { - int tok = yylex(yyscanner); + int tok = yylex(&yylval, &yylloc, yyscanner); if (tok_is_keyword(tok, &yylval, K_ROW_COUNT, "row_count")) @@ -1141,7 +1140,7 @@ getdiag_item : K_RETURNED_SQLSTATE, "returned_sqlstate")) $$ = PLPGSQL_GETDIAG_RETURNED_SQLSTATE; else - yyerror(yyscanner, "unrecognized GET DIAGNOSTICS item"); + yyerror(&yylloc, yyscanner, "unrecognized GET DIAGNOSTICS item"); } ; @@ -1228,14 +1227,14 @@ stmt_case : K_CASE opt_expr_until_when case_when_list opt_case_else K_END K_CAS opt_expr_until_when : { PLpgSQL_expr *expr = NULL; - int tok = yylex(yyscanner); + int tok = yylex(&yylval, &yylloc, yyscanner); if (tok != K_WHEN) { - plpgsql_push_back_token(tok); - expr = read_sql_expression(K_WHEN, "WHEN", yyscanner); + plpgsql_push_back_token(tok, &yylval, &yylloc); + expr = read_sql_expression(K_WHEN, "WHEN", &yylval, &yylloc, yyscanner); } - plpgsql_push_back_token(K_WHEN); + plpgsql_push_back_token(K_WHEN, &yylval, &yylloc); $$ = expr; } ; @@ -1353,7 +1352,7 @@ stmt_for : opt_loop_label K_FOR for_control loop_body for_control : for_variable K_IN { - int tok = yylex(yyscanner); + int tok = yylex(&yylval, &yylloc, yyscanner); int tokloc = yylloc; if (tok == K_EXECUTE) @@ -1365,7 +1364,7 @@ for_control : for_variable K_IN expr = read_sql_expression2(K_LOOP, K_USING, "LOOP or USING", - &term, yyscanner); + &term, &yylval, &yylloc, yyscanner); new = palloc0(sizeof(PLpgSQL_stmt_dynfors)); new->cmd_type = PLPGSQL_STMT_DYNFORS; @@ -1398,7 +1397,7 @@ for_control : for_variable K_IN { expr = read_sql_expression2(',', K_LOOP, ", or LOOP", - &term, yyscanner); + &term, &yylval, &yylloc, yyscanner); new->params = lappend(new->params, expr); } while (term == ','); } @@ -1433,7 +1432,7 @@ for_control : for_variable K_IN parser_errposition(tokloc))); /* collect cursor's parameters if any */ - new->argquery = read_cursor_args(cursor, K_LOOP, yyscanner); + new->argquery = read_cursor_args(cursor, K_LOOP, &yylval, &yylloc, yyscanner); /* create loop's private RECORD variable */ new->var = (PLpgSQL_variable *) @@ -1467,7 +1466,7 @@ for_control : for_variable K_IN K_REVERSE, "reverse")) reverse = true; else - plpgsql_push_back_token(tok); + plpgsql_push_back_token(tok, &yylval, &yylloc); /* * Read tokens until we see either a ".." @@ -1485,7 +1484,7 @@ for_control : for_variable K_IN false, &expr1loc, &tok, - yyscanner); + &yylval, &yylloc, yyscanner); if (tok == DOT_DOT) { @@ -1506,12 +1505,12 @@ for_control : for_variable K_IN /* Read and check the second one */ expr2 = read_sql_expression2(K_LOOP, K_BY, "LOOP", - &tok, yyscanner); + &tok, &yylval, &yylloc, yyscanner); /* Get the BY clause if any */ if (tok == K_BY) expr_by = read_sql_expression(K_LOOP, - "LOOP", yyscanner); + "LOOP", &yylval, &yylloc, yyscanner); else expr_by = NULL; @@ -1626,13 +1625,14 @@ for_variable : T_DATUM $$.scalar = $1.datum; $$.row = NULL; /* check for comma-separated list */ - tok = yylex(yyscanner); - plpgsql_push_back_token(tok); + tok = yylex(&yylval, &yylloc, yyscanner); + plpgsql_push_back_token(tok, &yylval, &yylloc); if (tok == ',') $$.row = (PLpgSQL_datum *) read_into_scalar_list($$.name, $$.scalar, @1, + &yylval, &yylloc, yyscanner); } } @@ -1645,8 +1645,8 @@ for_variable : T_DATUM $$.scalar = NULL; $$.row = NULL; /* check for comma-separated list */ - tok = yylex(yyscanner); - plpgsql_push_back_token(tok); + tok = yylex(&yylval, &yylloc, yyscanner); + plpgsql_push_back_token(tok, &yylval, &yylloc); if (tok == ',') word_is_not_variable(&($1), @1); } @@ -1772,24 +1772,24 @@ stmt_return : K_RETURN { int tok; - tok = yylex(yyscanner); + tok = yylex(&yylval, &yylloc, yyscanner); if (tok == 0) - yyerror(yyscanner, "unexpected end of function definition"); + yyerror(&yylloc, yyscanner, "unexpected end of function definition"); if (tok_is_keyword(tok, &yylval, K_NEXT, "next")) { - $$ = make_return_next_stmt(@1, yyscanner); + $$ = make_return_next_stmt(@1, &yylval, &yylloc, yyscanner); } else if (tok_is_keyword(tok, &yylval, K_QUERY, "query")) { - $$ = make_return_query_stmt(@1, yyscanner); + $$ = make_return_query_stmt(@1, &yylval, &yylloc, yyscanner); } else { - plpgsql_push_back_token(tok); - $$ = make_return_stmt(@1, yyscanner); + plpgsql_push_back_token(tok, &yylval, &yylloc); + $$ = make_return_stmt(@1, &yylval, &yylloc, yyscanner); } } ; @@ -1810,9 +1810,9 @@ stmt_raise : K_RAISE new->params = NIL; new->options = NIL; - tok = yylex(yyscanner); + tok = yylex(&yylval, &yylloc, yyscanner); if (tok == 0) - yyerror(yyscanner, "unexpected end of function definition"); + yyerror(&yylloc, yyscanner, "unexpected end of function definition"); /* * We could have just RAISE, meaning to re-throw @@ -1827,40 +1827,40 @@ stmt_raise : K_RAISE K_EXCEPTION, "exception")) { new->elog_level = ERROR; - tok = yylex(yyscanner); + tok = yylex(&yylval, &yylloc, yyscanner); } else if (tok_is_keyword(tok, &yylval, K_WARNING, "warning")) { new->elog_level = WARNING; - tok = yylex(yyscanner); + tok = yylex(&yylval, &yylloc, yyscanner); } else if (tok_is_keyword(tok, &yylval, K_NOTICE, "notice")) { new->elog_level = NOTICE; - tok = yylex(yyscanner); + tok = yylex(&yylval, &yylloc, yyscanner); } else if (tok_is_keyword(tok, &yylval, K_INFO, "info")) { new->elog_level = INFO; - tok = yylex(yyscanner); + tok = yylex(&yylval, &yylloc, yyscanner); } else if (tok_is_keyword(tok, &yylval, K_LOG, "log")) { new->elog_level = LOG; - tok = yylex(yyscanner); + tok = yylex(&yylval, &yylloc, yyscanner); } else if (tok_is_keyword(tok, &yylval, K_DEBUG, "debug")) { new->elog_level = DEBUG1; - tok = yylex(yyscanner); + tok = yylex(&yylval, &yylloc, yyscanner); } if (tok == 0) - yyerror(yyscanner, "unexpected end of function definition"); + yyerror(&yylloc, yyscanner, "unexpected end of function definition"); /* * Next we can have a condition name, or @@ -1878,9 +1878,9 @@ stmt_raise : K_RAISE * begins the list of parameter expressions, * or USING to begin the options list. */ - tok = yylex(yyscanner); + tok = yylex(&yylval, &yylloc, yyscanner); if (tok != ',' && tok != ';' && tok != K_USING) - yyerror(yyscanner, "syntax error"); + yyerror(&yylloc, yyscanner, "syntax error"); while (tok == ',') { @@ -1891,7 +1891,7 @@ stmt_raise : K_RAISE RAW_PARSE_PLPGSQL_EXPR, true, true, NULL, &tok, - yyscanner); + &yylval, &yylloc, yyscanner); new->params = lappend(new->params, expr); } } @@ -1904,14 +1904,14 @@ stmt_raise : K_RAISE /* next token should be a string literal */ char *sqlstatestr; - if (yylex(yyscanner) != SCONST) - yyerror(yyscanner, "syntax error"); + if (yylex(&yylval, &yylloc, yyscanner) != SCONST) + yyerror(&yylloc, yyscanner, "syntax error"); sqlstatestr = yylval.str; if (strlen(sqlstatestr) != 5) - yyerror(yyscanner, "invalid SQLSTATE code"); + yyerror(&yylloc, yyscanner, "invalid SQLSTATE code"); if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5) - yyerror(yyscanner, "invalid SQLSTATE code"); + yyerror(&yylloc, yyscanner, "invalid SQLSTATE code"); new->condname = sqlstatestr; } else @@ -1921,17 +1921,17 @@ stmt_raise : K_RAISE else if (plpgsql_token_is_unreserved_keyword(tok)) new->condname = pstrdup(yylval.keyword); else - yyerror(yyscanner, "syntax error"); + yyerror(&yylloc, yyscanner, "syntax error"); plpgsql_recognize_err_condition(new->condname, false); } - tok = yylex(yyscanner); + tok = yylex(&yylval, &yylloc, yyscanner); if (tok != ';' && tok != K_USING) - yyerror(yyscanner, "syntax error"); + yyerror(&yylloc, yyscanner, "syntax error"); } if (tok == K_USING) - new->options = read_raise_options(yyscanner); + new->options = read_raise_options(&yylval, &yylloc, yyscanner); } check_raise_parameters(new); @@ -1953,10 +1953,10 @@ stmt_assert : K_ASSERT new->cond = read_sql_expression2(',', ';', ", or ;", - &tok, yyscanner); + &tok, &yylval, &yylloc, yyscanner); if (tok == ',') - new->message = read_sql_expression(';', ";", yyscanner); + new->message = read_sql_expression(';', ";", &yylval, &yylloc, yyscanner); else new->message = NULL; @@ -1984,37 +1984,37 @@ loop_body : proc_sect K_END K_LOOP opt_label ';' */ stmt_execsql : K_IMPORT { - $$ = make_execsql_stmt(K_IMPORT, @1, NULL, yyscanner); + $$ = make_execsql_stmt(K_IMPORT, @1, NULL, &yylval, &yylloc, yyscanner); } | K_INSERT { - $$ = make_execsql_stmt(K_INSERT, @1, NULL, yyscanner); + $$ = make_execsql_stmt(K_INSERT, @1, NULL, &yylval, &yylloc, yyscanner); } | K_MERGE { - $$ = make_execsql_stmt(K_MERGE, @1, NULL, yyscanner); + $$ = make_execsql_stmt(K_MERGE, @1, NULL, &yylval, &yylloc, yyscanner); } | T_WORD { int tok; - tok = yylex(yyscanner); - plpgsql_push_back_token(tok); + tok = yylex(&yylval, &yylloc, yyscanner); + plpgsql_push_back_token(tok, &yylval, &yylloc); if (tok == '=' || tok == COLON_EQUALS || tok == '[' || tok == '.') word_is_not_variable(&($1), @1); - $$ = make_execsql_stmt(T_WORD, @1, &($1), yyscanner); + $$ = make_execsql_stmt(T_WORD, @1, &($1), &yylval, &yylloc, yyscanner); } | T_CWORD { int tok; - tok = yylex(yyscanner); - plpgsql_push_back_token(tok); + tok = yylex(&yylval, &yylloc, yyscanner); + plpgsql_push_back_token(tok, &yylval, &yylloc); if (tok == '=' || tok == COLON_EQUALS || tok == '[' || tok == '.') cword_is_not_variable(&($1), @1); - $$ = make_execsql_stmt(T_CWORD, @1, NULL, yyscanner); + $$ = make_execsql_stmt(T_CWORD, @1, NULL, &yylval, &yylloc, yyscanner); } ; @@ -2029,7 +2029,7 @@ stmt_dynexecute : K_EXECUTE RAW_PARSE_PLPGSQL_EXPR, true, true, NULL, &endtoken, - yyscanner); + &yylval, &yylloc, yyscanner); new = palloc(sizeof(PLpgSQL_stmt_dynexecute)); new->cmd_type = PLPGSQL_STMT_DYNEXECUTE; @@ -2053,15 +2053,15 @@ stmt_dynexecute : K_EXECUTE if (endtoken == K_INTO) { if (new->into) /* multiple INTO */ - yyerror(yyscanner, "syntax error"); + yyerror(&yylloc, yyscanner, "syntax error"); new->into = true; - read_into_target(&new->target, &new->strict, yyscanner); - endtoken = yylex(yyscanner); + read_into_target(&new->target, &new->strict, &yylval, &yylloc, yyscanner); + endtoken = yylex(&yylval, &yylloc, yyscanner); } else if (endtoken == K_USING) { if (new->params) /* multiple USING */ - yyerror(yyscanner, "syntax error"); + yyerror(&yylloc, yyscanner, "syntax error"); do { expr = read_sql_construct(',', ';', K_INTO, @@ -2069,14 +2069,14 @@ stmt_dynexecute : K_EXECUTE RAW_PARSE_PLPGSQL_EXPR, true, true, NULL, &endtoken, - yyscanner); + &yylval, &yylloc, yyscanner); new->params = lappend(new->params, expr); } while (endtoken == ','); } else if (endtoken == ';') break; else - yyerror(yyscanner, "syntax error"); + yyerror(&yylloc, yyscanner, "syntax error"); } $$ = (PLpgSQL_stmt *) new; @@ -2099,29 +2099,29 @@ stmt_open : K_OPEN cursor_variable if ($2->cursor_explicit_expr == NULL) { /* be nice if we could use opt_scrollable here */ - tok = yylex(yyscanner); + tok = yylex(&yylval, &yylloc, yyscanner); if (tok_is_keyword(tok, &yylval, K_NO, "no")) { - tok = yylex(yyscanner); + tok = yylex(&yylval, &yylloc, yyscanner); if (tok_is_keyword(tok, &yylval, K_SCROLL, "scroll")) { new->cursor_options |= CURSOR_OPT_NO_SCROLL; - tok = yylex(yyscanner); + tok = yylex(&yylval, &yylloc, yyscanner); } } else if (tok_is_keyword(tok, &yylval, K_SCROLL, "scroll")) { new->cursor_options |= CURSOR_OPT_SCROLL; - tok = yylex(yyscanner); + tok = yylex(&yylval, &yylloc, yyscanner); } if (tok != K_FOR) - yyerror(yyscanner, "syntax error, expected \"FOR\""); + yyerror(&yylloc, yyscanner, "syntax error, expected \"FOR\""); - tok = yylex(yyscanner); + tok = yylex(&yylval, &yylloc, yyscanner); if (tok == K_EXECUTE) { int endtoken; @@ -2129,7 +2129,7 @@ stmt_open : K_OPEN cursor_variable new->dynquery = read_sql_expression2(K_USING, ';', "USING or ;", - &endtoken, yyscanner); + &endtoken, &yylval, &yylloc, yyscanner); /* If we found "USING", collect argument(s) */ if (endtoken == K_USING) @@ -2140,7 +2140,7 @@ stmt_open : K_OPEN cursor_variable { expr = read_sql_expression2(',', ';', ", or ;", - &endtoken, yyscanner); + &endtoken, &yylval, &yylloc, yyscanner); new->params = lappend(new->params, expr); } while (endtoken == ','); @@ -2148,14 +2148,14 @@ stmt_open : K_OPEN cursor_variable } else { - plpgsql_push_back_token(tok); - new->query = read_sql_stmt(yyscanner); + plpgsql_push_back_token(tok, &yylval, &yylloc); + new->query = read_sql_stmt(&yylval, &yylloc, yyscanner); } } else { /* predefined cursor query, so read args */ - new->argquery = read_cursor_args($2, ';', yyscanner); + new->argquery = read_cursor_args($2, ';', &yylval, &yylloc, yyscanner); } $$ = (PLpgSQL_stmt *) new; @@ -2168,10 +2168,10 @@ stmt_fetch : K_FETCH opt_fetch_direction cursor_variable K_INTO PLpgSQL_variable *target; /* We have already parsed everything through the INTO keyword */ - read_into_target(&target, NULL, yyscanner); + read_into_target(&target, NULL, &yylval, &yylloc, yyscanner); - if (yylex(yyscanner) != ';') - yyerror(yyscanner, "syntax error"); + if (yylex(&yylval, &yylloc, yyscanner) != ';') + yyerror(&yylloc, yyscanner, "syntax error"); /* * We don't allow multiple rows in PL/pgSQL's FETCH @@ -2206,7 +2206,7 @@ stmt_move : K_MOVE opt_fetch_direction cursor_variable ';' opt_fetch_direction : { - $$ = read_fetch_direction(yyscanner); + $$ = read_fetch_direction(&yylval, &yylloc, yyscanner); } ; @@ -2394,14 +2394,14 @@ proc_condition : any_identifier char *sqlstatestr; /* next token should be a string literal */ - if (yylex(yyscanner) != SCONST) - yyerror(yyscanner, "syntax error"); + if (yylex(&yylval, &yylloc, yyscanner) != SCONST) + yyerror(&yylloc, yyscanner, "syntax error"); sqlstatestr = yylval.str; if (strlen(sqlstatestr) != 5) - yyerror(yyscanner, "invalid SQLSTATE code"); + yyerror(&yylloc, yyscanner, "invalid SQLSTATE code"); if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5) - yyerror(yyscanner, "invalid SQLSTATE code"); + yyerror(&yylloc, yyscanner, "invalid SQLSTATE code"); new = palloc(sizeof(PLpgSQL_condition)); new->sqlerrstate = @@ -2419,15 +2419,15 @@ proc_condition : any_identifier ; expr_until_semi : - { $$ = read_sql_expression(';', ";", yyscanner); } + { $$ = read_sql_expression(';', ";", &yylval, &yylloc, yyscanner); } ; expr_until_then : - { $$ = read_sql_expression(K_THEN, "THEN", yyscanner); } + { $$ = read_sql_expression(K_THEN, "THEN", &yylval, &yylloc, yyscanner); } ; expr_until_loop : - { $$ = read_sql_expression(K_LOOP, "LOOP", yyscanner); } + { $$ = read_sql_expression(K_LOOP, "LOOP", &yylval, &yylloc, yyscanner); } ; opt_block_label : @@ -2485,7 +2485,7 @@ any_identifier : T_WORD | T_DATUM { if ($1.ident == NULL) /* composite name not OK */ - yyerror(yyscanner, "syntax error"); + yyerror(&yylloc, yyscanner, "syntax error"); $$ = $1.ident; } ; @@ -2637,45 +2637,45 @@ cword_is_not_variable(PLcword *cword, int location) * look at yylval and yylloc. */ static void -current_token_is_not_variable(int tok, yyscan_t yyscanner) +current_token_is_not_variable(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { if (tok == T_WORD) - word_is_not_variable(&(yylval.word), yylloc); + word_is_not_variable(&(yylvalp->word), *yyllocp); else if (tok == T_CWORD) - cword_is_not_variable(&(yylval.cword), yylloc); + cword_is_not_variable(&(yylvalp->cword), *yyllocp); else - yyerror(yyscanner, "syntax error"); + yyerror(yyllocp, yyscanner, "syntax error"); } /* Convenience routine to read an expression with one possible terminator */ static PLpgSQL_expr * -read_sql_expression(int until, const char *expected, yyscan_t yyscanner) +read_sql_expression(int until, const char *expected, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { return read_sql_construct(until, 0, 0, expected, RAW_PARSE_PLPGSQL_EXPR, true, true, NULL, NULL, - yyscanner); + yylvalp, yyllocp, yyscanner); } /* Convenience routine to read an expression with two possible terminators */ static PLpgSQL_expr * read_sql_expression2(int until, int until2, const char *expected, - int *endtoken, yyscan_t yyscanner) + int *endtoken, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { return read_sql_construct(until, until2, 0, expected, RAW_PARSE_PLPGSQL_EXPR, true, true, NULL, endtoken, - yyscanner); + yylvalp, yyllocp, yyscanner); } /* Convenience routine to read a SQL statement that must end with ';' */ static PLpgSQL_expr * -read_sql_stmt(yyscan_t yyscanner) +read_sql_stmt(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { return read_sql_construct(';', 0, 0, ";", RAW_PARSE_DEFAULT, false, true, NULL, NULL, - yyscanner); + yylvalp, yyllocp, yyscanner); } /* @@ -2702,6 +2702,7 @@ read_sql_construct(int until, bool valid_sql, int *startloc, int *endtoken, + YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { int tok; @@ -2720,9 +2721,9 @@ read_sql_construct(int until, for (;;) { - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); if (startlocation < 0) /* remember loc of first token */ - startlocation = yylloc; + startlocation = *yyllocp; if (tok == until && parenlevel == 0) break; if (tok == until2 && parenlevel == 0) @@ -2735,7 +2736,7 @@ read_sql_construct(int until, { parenlevel--; if (parenlevel < 0) - yyerror(yyscanner, "mismatched parentheses"); + yyerror(yyllocp, yyscanner, "mismatched parentheses"); } /* @@ -2746,22 +2747,22 @@ read_sql_construct(int until, if (tok == 0 || tok == ';') { if (parenlevel != 0) - yyerror(yyscanner, "mismatched parentheses"); + yyerror(yyllocp, yyscanner, "mismatched parentheses"); if (isexpression) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("missing \"%s\" at end of SQL expression", expected), - parser_errposition(yylloc))); + parser_errposition(*yyllocp))); else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("missing \"%s\" at end of SQL statement", expected), - parser_errposition(yylloc))); + parser_errposition(*yyllocp))); } /* Remember end+1 location of last accepted token */ - endlocation = yylloc + plpgsql_token_length(); + endlocation = *yyllocp + plpgsql_token_length(); } plpgsql_IdentifierLookup = save_IdentifierLookup; @@ -2775,9 +2776,9 @@ read_sql_construct(int until, if (startlocation >= endlocation) { if (isexpression) - yyerror(yyscanner, "missing expression"); + yyerror(yyllocp, yyscanner, "missing expression"); else - yyerror(yyscanner, "missing SQL statement"); + yyerror(yyllocp, yyscanner, "missing SQL statement"); } /* @@ -2809,7 +2810,7 @@ read_sql_construct(int until, * Returns a PLpgSQL_type struct. */ static PLpgSQL_type * -read_datatype(int tok, yyscan_t yyscanner) +read_datatype(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { StringInfoData ds; char *type_name; @@ -2822,10 +2823,10 @@ read_datatype(int tok, yyscan_t yyscanner) /* Often there will be a lookahead token, but if not, get one */ if (tok == YYEMPTY) - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); /* The current token is the start of what we'll pass to parse_datatype */ - startlocation = yylloc; + startlocation = *yyllocp; /* * If we have a simple or composite identifier, check for %TYPE and @@ -2833,48 +2834,48 @@ read_datatype(int tok, yyscan_t yyscanner) */ if (tok == T_WORD) { - char *dtname = yylval.word.ident; + char *dtname = yylvalp->word.ident; - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); if (tok == '%') { - tok = yylex(yyscanner); - if (tok_is_keyword(tok, &yylval, + tok = yylex(yylvalp, yyllocp, yyscanner); + if (tok_is_keyword(tok, yylvalp, K_TYPE, "type")) result = plpgsql_parse_wordtype(dtname); - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_ROWTYPE, "rowtype")) result = plpgsql_parse_wordrowtype(dtname); } } else if (plpgsql_token_is_unreserved_keyword(tok)) { - char *dtname = pstrdup(yylval.keyword); + char *dtname = pstrdup(yylvalp->keyword); - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); if (tok == '%') { - tok = yylex(yyscanner); - if (tok_is_keyword(tok, &yylval, + tok = yylex(yylvalp, yyllocp, yyscanner); + if (tok_is_keyword(tok, yylvalp, K_TYPE, "type")) result = plpgsql_parse_wordtype(dtname); - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_ROWTYPE, "rowtype")) result = plpgsql_parse_wordrowtype(dtname); } } else if (tok == T_CWORD) { - List *dtnames = yylval.cword.idents; + List *dtnames = yylvalp->cword.idents; - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); if (tok == '%') { - tok = yylex(yyscanner); - if (tok_is_keyword(tok, &yylval, + tok = yylex(yylvalp, yyllocp, yyscanner); + if (tok_is_keyword(tok, yylvalp, K_TYPE, "type")) result = plpgsql_parse_cwordtype(dtnames); - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_ROWTYPE, "rowtype")) result = plpgsql_parse_cwordrowtype(dtnames); } @@ -2892,24 +2893,24 @@ read_datatype(int tok, yyscan_t yyscanner) { bool is_array = false; - tok = yylex(yyscanner); - if (tok_is_keyword(tok, &yylval, + tok = yylex(yylvalp, yyllocp, yyscanner); + if (tok_is_keyword(tok, yylvalp, K_ARRAY, "array")) { is_array = true; - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); } while (tok == '[') { is_array = true; - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); if (tok == ICONST) - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); if (tok != ']') - yyerror(yyscanner, "syntax error, expected \"]\""); - tok = yylex(yyscanner); + yyerror(yyllocp, yyscanner, "syntax error, expected \"]\""); + tok = yylex(yylvalp, yyllocp, yyscanner); } - plpgsql_push_back_token(tok); + plpgsql_push_back_token(tok, yylvalp, yyllocp); if (is_array) result = plpgsql_build_datatype_arrayof(result); @@ -2928,9 +2929,9 @@ read_datatype(int tok, yyscan_t yyscanner) if (tok == 0) { if (parenlevel != 0) - yyerror(yyscanner, "mismatched parentheses"); + yyerror(yyllocp, yyscanner, "mismatched parentheses"); else - yyerror(yyscanner, "incomplete data type declaration"); + yyerror(yyllocp, yyscanner, "incomplete data type declaration"); } /* Possible followers for datatype in a declaration */ if (tok == K_COLLATE || tok == K_NOT || @@ -2944,22 +2945,22 @@ read_datatype(int tok, yyscan_t yyscanner) else if (tok == ')') parenlevel--; - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); } /* set up ds to contain complete typename text */ initStringInfo(&ds); - plpgsql_append_source_text(&ds, startlocation, yylloc); + plpgsql_append_source_text(&ds, startlocation, *yyllocp); type_name = ds.data; if (type_name[0] == '\0') - yyerror(yyscanner, "missing data type declaration"); + yyerror(yyllocp, yyscanner, "missing data type declaration"); result = parse_datatype(type_name, startlocation); pfree(ds.data); - plpgsql_push_back_token(tok); + plpgsql_push_back_token(tok, yylvalp, yyllocp); return result; } @@ -2970,7 +2971,7 @@ read_datatype(int tok, yyscan_t yyscanner) * If firsttoken == T_WORD, pass its yylval value as "word", else pass NULL. */ static PLpgSQL_stmt * -make_execsql_stmt(int firsttoken, int location, PLword *word, yyscan_t yyscanner) +make_execsql_stmt(int firsttoken, int location, PLword *word, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { StringInfoData ds; IdentifierLookup save_IdentifierLookup; @@ -3039,22 +3040,22 @@ make_execsql_stmt(int firsttoken, int location, PLword *word, yyscan_t yyscanner for (;;) { prev_tok = tok; - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); if (have_into && into_end_loc < 0) - into_end_loc = yylloc; /* token after the INTO part */ + into_end_loc = *yyllocp; /* token after the INTO part */ /* Detect CREATE [OR REPLACE] {FUNCTION|PROCEDURE} */ if (tokens[0] == 'c' && token_count < sizeof(tokens)) { if (tok == K_OR) tokens[token_count] = 'o'; else if (tok == T_WORD && - strcmp(yylval.word.ident, "replace") == 0) + strcmp(yylvalp->word.ident, "replace") == 0) tokens[token_count] = 'r'; else if (tok == T_WORD && - strcmp(yylval.word.ident, "function") == 0) + strcmp(yylvalp->word.ident, "function") == 0) tokens[token_count] = 'f'; else if (tok == T_WORD && - strcmp(yylval.word.ident, "procedure") == 0) + strcmp(yylvalp->word.ident, "procedure") == 0) tokens[token_count] = 'f'; /* treat same as "function" */ if (tokens[1] == 'f' || (tokens[1] == 'o' && tokens[2] == 'r' && tokens[3] == 'f')) @@ -3078,7 +3079,7 @@ make_execsql_stmt(int firsttoken, int location, PLword *word, yyscan_t yyscanner if (tok == ';' && paren_depth == 0 && begin_depth == 0) break; if (tok == 0) - yyerror(yyscanner, "unexpected end of function definition"); + yyerror(yyllocp, yyscanner, "unexpected end of function definition"); if (tok == K_INTO) { if (prev_tok == K_INSERT) @@ -3088,11 +3089,11 @@ make_execsql_stmt(int firsttoken, int location, PLword *word, yyscan_t yyscanner if (firsttoken == K_IMPORT) continue; /* IMPORT ... INTO is not an INTO-target */ if (have_into) - yyerror(yyscanner, "INTO specified more than once"); + yyerror(yyllocp, yyscanner, "INTO specified more than once"); have_into = true; - into_start_loc = yylloc; + into_start_loc = *yyllocp; plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL; - read_into_target(&target, &have_strict, yyscanner); + read_into_target(&target, &have_strict, yylvalp, yyllocp, yyscanner); plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR; } } @@ -3108,10 +3109,10 @@ make_execsql_stmt(int firsttoken, int location, PLword *word, yyscan_t yyscanner */ plpgsql_append_source_text(&ds, location, into_start_loc); appendStringInfoSpaces(&ds, into_end_loc - into_start_loc); - plpgsql_append_source_text(&ds, into_end_loc, yylloc); + plpgsql_append_source_text(&ds, into_end_loc, *yyllocp); } else - plpgsql_append_source_text(&ds, location, yylloc); + plpgsql_append_source_text(&ds, location, *yyllocp); /* trim any trailing whitespace, for neatness */ while (ds.len > 0 && scanner_isspace(ds.data[ds.len - 1])) @@ -3145,7 +3146,7 @@ make_execsql_stmt(int firsttoken, int location, PLword *word, yyscan_t yyscanner * Read FETCH or MOVE direction clause (everything through FROM/IN). */ static PLpgSQL_stmt_fetch * -read_fetch_direction(yyscan_t yyscanner) +read_fetch_direction(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { PLpgSQL_stmt_fetch *fetch; int tok; @@ -3164,65 +3165,65 @@ read_fetch_direction(yyscan_t yyscanner) fetch->expr = NULL; fetch->returns_multiple_rows = false; - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); if (tok == 0) - yyerror(yyscanner, "unexpected end of function definition"); + yyerror(yyllocp, yyscanner, "unexpected end of function definition"); - if (tok_is_keyword(tok, &yylval, + if (tok_is_keyword(tok, yylvalp, K_NEXT, "next")) { /* use defaults */ } - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_PRIOR, "prior")) { fetch->direction = FETCH_BACKWARD; } - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_FIRST, "first")) { fetch->direction = FETCH_ABSOLUTE; } - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_LAST, "last")) { fetch->direction = FETCH_ABSOLUTE; fetch->how_many = -1; } - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_ABSOLUTE, "absolute")) { fetch->direction = FETCH_ABSOLUTE; fetch->expr = read_sql_expression2(K_FROM, K_IN, "FROM or IN", - NULL, yyscanner); + NULL, yylvalp, yyllocp, yyscanner); check_FROM = false; } - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_RELATIVE, "relative")) { fetch->direction = FETCH_RELATIVE; fetch->expr = read_sql_expression2(K_FROM, K_IN, "FROM or IN", - NULL, yyscanner); + NULL, yylvalp, yyllocp, yyscanner); check_FROM = false; } - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_ALL, "all")) { fetch->how_many = FETCH_ALL; fetch->returns_multiple_rows = true; } - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_FORWARD, "forward")) { - complete_direction(fetch, &check_FROM, yyscanner); + complete_direction(fetch, &check_FROM, yylvalp, yyllocp, yyscanner); } - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_BACKWARD, "backward")) { fetch->direction = FETCH_BACKWARD; - complete_direction(fetch, &check_FROM, yyscanner); + complete_direction(fetch, &check_FROM, yylvalp, yyllocp, yyscanner); } else if (tok == K_FROM || tok == K_IN) { @@ -3232,7 +3233,7 @@ read_fetch_direction(yyscan_t yyscanner) else if (tok == T_DATUM) { /* Assume there's no direction clause and tok is a cursor name */ - plpgsql_push_back_token(tok); + plpgsql_push_back_token(tok, yylvalp, yyllocp); check_FROM = false; } else @@ -3245,10 +3246,10 @@ read_fetch_direction(yyscan_t yyscanner) * will trigger. Perhaps this can be improved someday, but it hardly * seems worth a lot of work. */ - plpgsql_push_back_token(tok); + plpgsql_push_back_token(tok, yylvalp, yyllocp); fetch->expr = read_sql_expression2(K_FROM, K_IN, "FROM or IN", - NULL, yyscanner); + NULL, yylvalp, yyllocp, yyscanner); fetch->returns_multiple_rows = true; check_FROM = false; } @@ -3256,9 +3257,9 @@ read_fetch_direction(yyscan_t yyscanner) /* check FROM or IN keyword after direction's specification */ if (check_FROM) { - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); if (tok != K_FROM && tok != K_IN) - yyerror(yyscanner, "expected FROM or IN"); + yyerror(yyllocp, yyscanner, "expected FROM or IN"); } return fetch; @@ -3271,13 +3272,13 @@ read_fetch_direction(yyscan_t yyscanner) * BACKWARD expr, BACKWARD ALL, BACKWARD */ static void -complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM, yyscan_t yyscanner) +complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { int tok; - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); if (tok == 0) - yyerror(yyscanner, "unexpected end of function definition"); + yyerror(yyllocp, yyscanner, "unexpected end of function definition"); if (tok == K_FROM || tok == K_IN) { @@ -3293,17 +3294,17 @@ complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM, yyscan_t yyscann return; } - plpgsql_push_back_token(tok); + plpgsql_push_back_token(tok, yylvalp, yyllocp); fetch->expr = read_sql_expression2(K_FROM, K_IN, "FROM or IN", - NULL, yyscanner); + NULL, yylvalp, yyllocp, yyscanner); fetch->returns_multiple_rows = true; *check_FROM = false; } static PLpgSQL_stmt * -make_return_stmt(int location, yyscan_t yyscanner) +make_return_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { PLpgSQL_stmt_return *new; @@ -3316,36 +3317,36 @@ make_return_stmt(int location, yyscan_t yyscanner) if (plpgsql_curr_compile->fn_retset) { - if (yylex(yyscanner) != ';') + if (yylex(yylvalp, yyllocp, yyscanner) != ';') ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("RETURN cannot have a parameter in function returning set"), errhint("Use RETURN NEXT or RETURN QUERY."), - parser_errposition(yylloc))); + parser_errposition(*yyllocp))); } else if (plpgsql_curr_compile->fn_rettype == VOIDOID) { - if (yylex(yyscanner) != ';') + if (yylex(yylvalp, yyllocp, yyscanner) != ';') { if (plpgsql_curr_compile->fn_prokind == PROKIND_PROCEDURE) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("RETURN cannot have a parameter in a procedure"), - parser_errposition(yylloc))); + parser_errposition(*yyllocp))); else ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("RETURN cannot have a parameter in function returning void"), - parser_errposition(yylloc))); + parser_errposition(*yyllocp))); } } else if (plpgsql_curr_compile->out_param_varno >= 0) { - if (yylex(yyscanner) != ';') + if (yylex(yylvalp, yyllocp, yyscanner) != ';') ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("RETURN cannot have a parameter in function with OUT parameters"), - parser_errposition(yylloc))); + parser_errposition(*yyllocp))); new->retvarno = plpgsql_curr_compile->out_param_varno; } else @@ -3354,17 +3355,17 @@ make_return_stmt(int location, yyscan_t yyscanner) * We want to special-case simple variable references for efficiency. * So peek ahead to see if that's what we have. */ - int tok = yylex(yyscanner); + int tok = yylex(yylvalp, yyllocp, yyscanner); if (tok == T_DATUM && plpgsql_peek(yyscanner) == ';' && - (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_VAR || - yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_PROMISE || - yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW || - yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC)) + (yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_VAR || + yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_PROMISE || + yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_ROW || + yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_REC)) { - new->retvarno = yylval.wdatum.datum->dno; + new->retvarno = yylvalp->wdatum.datum->dno; /* eat the semicolon token that we only peeked at above */ - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); Assert(tok == ';'); } else @@ -3375,8 +3376,8 @@ make_return_stmt(int location, yyscan_t yyscanner) * Note that a well-formed expression is _required_ here; anything * else is a compile-time error. */ - plpgsql_push_back_token(tok); - new->expr = read_sql_expression(';', ";", yyscanner); + plpgsql_push_back_token(tok, yylvalp, yyllocp); + new->expr = read_sql_expression(';', ";", yylvalp, yyllocp, yyscanner); } } @@ -3385,7 +3386,7 @@ make_return_stmt(int location, yyscan_t yyscanner) static PLpgSQL_stmt * -make_return_next_stmt(int location, yyscan_t yyscanner) +make_return_next_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { PLpgSQL_stmt_return_next *new; @@ -3404,11 +3405,11 @@ make_return_next_stmt(int location, yyscan_t yyscanner) if (plpgsql_curr_compile->out_param_varno >= 0) { - if (yylex(yyscanner) != ';') + if (yylex(yylvalp, yyllocp, yyscanner) != ';') ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("RETURN NEXT cannot have a parameter in function with OUT parameters"), - parser_errposition(yylloc))); + parser_errposition(*yyllocp))); new->retvarno = plpgsql_curr_compile->out_param_varno; } else @@ -3417,17 +3418,17 @@ make_return_next_stmt(int location, yyscan_t yyscanner) * We want to special-case simple variable references for efficiency. * So peek ahead to see if that's what we have. */ - int tok = yylex(yyscanner); + int tok = yylex(yylvalp, yyllocp, yyscanner); if (tok == T_DATUM && plpgsql_peek(yyscanner) == ';' && - (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_VAR || - yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_PROMISE || - yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW || - yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC)) + (yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_VAR || + yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_PROMISE || + yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_ROW || + yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_REC)) { - new->retvarno = yylval.wdatum.datum->dno; + new->retvarno = yylvalp->wdatum.datum->dno; /* eat the semicolon token that we only peeked at above */ - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); Assert(tok == ';'); } else @@ -3438,8 +3439,8 @@ make_return_next_stmt(int location, yyscan_t yyscanner) * Note that a well-formed expression is _required_ here; anything * else is a compile-time error. */ - plpgsql_push_back_token(tok); - new->expr = read_sql_expression(';', ";", yyscanner); + plpgsql_push_back_token(tok, yylvalp, yyllocp); + new->expr = read_sql_expression(';', ";", yylvalp, yyllocp, yyscanner); } } @@ -3448,7 +3449,7 @@ make_return_next_stmt(int location, yyscan_t yyscanner) static PLpgSQL_stmt * -make_return_query_stmt(int location, yyscan_t yyscanner) +make_return_query_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { PLpgSQL_stmt_return_query *new; int tok; @@ -3465,11 +3466,11 @@ make_return_query_stmt(int location, yyscan_t yyscanner) new->stmtid = ++plpgsql_curr_compile->nstatements; /* check for RETURN QUERY EXECUTE */ - if ((tok = yylex(yyscanner)) != K_EXECUTE) + if ((tok = yylex(yylvalp, yyllocp, yyscanner)) != K_EXECUTE) { /* ordinary static query */ - plpgsql_push_back_token(tok); - new->query = read_sql_stmt(yyscanner); + plpgsql_push_back_token(tok, yylvalp, yyllocp); + new->query = read_sql_stmt(yylvalp, yyllocp, yyscanner); } else { @@ -3477,14 +3478,14 @@ make_return_query_stmt(int location, yyscan_t yyscanner) int term; new->dynquery = read_sql_expression2(';', K_USING, "; or USING", - &term, yyscanner); + &term, yylvalp, yyllocp, yyscanner); if (term == K_USING) { do { PLpgSQL_expr *expr; - expr = read_sql_expression2(',', ';', ", or ;", &term, yyscanner); + expr = read_sql_expression2(',', ';', ", or ;", &term, yylvalp, yyllocp, yyscanner); new->params = lappend(new->params, expr); } while (term == ','); } @@ -3538,7 +3539,7 @@ check_assignable(PLpgSQL_datum *datum, int location) * INTO keyword. */ static void -read_into_target(PLpgSQL_variable **target, bool *strict, yyscan_t yyscanner) +read_into_target(PLpgSQL_variable **target, bool *strict, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { int tok; @@ -3547,11 +3548,11 @@ read_into_target(PLpgSQL_variable **target, bool *strict, yyscan_t yyscanner) if (strict) *strict = false; - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); if (strict && tok == K_STRICT) { *strict = true; - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); } /* @@ -3564,30 +3565,30 @@ read_into_target(PLpgSQL_variable **target, bool *strict, yyscan_t yyscanner) switch (tok) { case T_DATUM: - if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW || - yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC) + if (yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_ROW || + yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_REC) { - check_assignable(yylval.wdatum.datum, yylloc); - *target = (PLpgSQL_variable *) yylval.wdatum.datum; + check_assignable(yylvalp->wdatum.datum, *yyllocp); + *target = (PLpgSQL_variable *) yylvalp->wdatum.datum; - if ((tok = yylex(yyscanner)) == ',') + if ((tok = yylex(yylvalp, yyllocp, yyscanner)) == ',') ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("record variable cannot be part of multiple-item INTO list"), - parser_errposition(yylloc))); - plpgsql_push_back_token(tok); + parser_errposition(*yyllocp))); + plpgsql_push_back_token(tok, yylvalp, yyllocp); } else { *target = (PLpgSQL_variable *) - read_into_scalar_list(NameOfDatum(&(yylval.wdatum)), - yylval.wdatum.datum, yylloc, yyscanner); + read_into_scalar_list(NameOfDatum(&(yylvalp->wdatum)), + yylvalp->wdatum.datum, *yyllocp, yylvalp, yyllocp, yyscanner); } break; default: /* just to give a better message than "syntax error" */ - current_token_is_not_variable(tok, yyscanner); + current_token_is_not_variable(tok, yylvalp, yyllocp, yyscanner); } } @@ -3601,6 +3602,7 @@ static PLpgSQL_row * read_into_scalar_list(char *initial_name, PLpgSQL_datum *initial_datum, int initial_location, + YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { int nfields; @@ -3614,34 +3616,34 @@ read_into_scalar_list(char *initial_name, varnos[0] = initial_datum->dno; nfields = 1; - while ((tok = yylex(yyscanner)) == ',') + while ((tok = yylex(yylvalp, yyllocp, yyscanner)) == ',') { /* Check for array overflow */ if (nfields >= 1024) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("too many INTO variables specified"), - parser_errposition(yylloc))); + parser_errposition(*yyllocp))); - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); switch (tok) { case T_DATUM: - check_assignable(yylval.wdatum.datum, yylloc); - if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW || - yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC) + check_assignable(yylvalp->wdatum.datum, *yyllocp); + if (yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_ROW || + yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_REC) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("\"%s\" is not a scalar variable", - NameOfDatum(&(yylval.wdatum))), - parser_errposition(yylloc))); - fieldnames[nfields] = NameOfDatum(&(yylval.wdatum)); - varnos[nfields++] = yylval.wdatum.datum->dno; + NameOfDatum(&(yylvalp->wdatum))), + parser_errposition(*yyllocp))); + fieldnames[nfields] = NameOfDatum(&(yylvalp->wdatum)); + varnos[nfields++] = yylvalp->wdatum.datum->dno; break; default: /* just to give a better message than "syntax error" */ - current_token_is_not_variable(tok, yyscanner); + current_token_is_not_variable(tok, yylvalp, yyllocp, yyscanner); } } @@ -3649,7 +3651,7 @@ read_into_scalar_list(char *initial_name, * We read an extra, non-comma token from yylex(), so push it back onto * the input stream */ - plpgsql_push_back_token(tok); + plpgsql_push_back_token(tok, yylvalp, yyllocp); row = palloc0(sizeof(PLpgSQL_row)); row->dtype = PLPGSQL_DTYPE_ROW; @@ -3852,7 +3854,7 @@ check_labels(const char *start_label, const char *end_label, int end_location) * parens). */ static PLpgSQL_expr * -read_cursor_args(PLpgSQL_var *cursor, int until, yyscan_t yyscanner) +read_cursor_args(PLpgSQL_var *cursor, int until, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { PLpgSQL_expr *expr; PLpgSQL_row *row; @@ -3862,7 +3864,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until, yyscan_t yyscanner) StringInfoData ds; bool any_named = false; - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); if (cursor->cursor_explicit_argrow < 0) { /* No arguments expected */ @@ -3871,10 +3873,10 @@ read_cursor_args(PLpgSQL_var *cursor, int until, yyscan_t yyscanner) (errcode(ERRCODE_SYNTAX_ERROR), errmsg("cursor \"%s\" has no arguments", cursor->refname), - parser_errposition(yylloc))); + parser_errposition(*yyllocp))); if (tok != until) - yyerror(yyscanner, "syntax error"); + yyerror(yyllocp, yyscanner, "syntax error"); return NULL; } @@ -3885,7 +3887,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until, yyscan_t yyscanner) (errcode(ERRCODE_SYNTAX_ERROR), errmsg("cursor \"%s\" has arguments", cursor->refname), - parser_errposition(yylloc))); + parser_errposition(*yyllocp))); /* * Read the arguments, one by one. @@ -3912,8 +3914,8 @@ read_cursor_args(PLpgSQL_var *cursor, int until, yyscan_t yyscanner) /* Read the argument name, ignoring any matching variable */ save_IdentifierLookup = plpgsql_IdentifierLookup; plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_DECLARE; - yylex(yyscanner); - argname = yylval.str; + yylex(yylvalp, yyllocp, yyscanner); + argname = yylvalp->str; plpgsql_IdentifierLookup = save_IdentifierLookup; /* Match argument name to cursor arguments */ @@ -3927,15 +3929,15 @@ read_cursor_args(PLpgSQL_var *cursor, int until, yyscan_t yyscanner) (errcode(ERRCODE_SYNTAX_ERROR), errmsg("cursor \"%s\" has no argument named \"%s\"", cursor->refname, argname), - parser_errposition(yylloc))); + parser_errposition(*yyllocp))); /* * Eat the ":=". We already peeked, so the error should never * happen. */ - tok2 = yylex(yyscanner); + tok2 = yylex(yylvalp, yyllocp, yyscanner); if (tok2 != COLON_EQUALS) - yyerror(yyscanner, "syntax error"); + yyerror(yyllocp, yyscanner, "syntax error"); any_named = true; } @@ -3960,7 +3962,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until, yyscan_t yyscanner) RAW_PARSE_PLPGSQL_EXPR, true, true, NULL, &endtoken, - yyscanner); + yylvalp, yyllocp, yyscanner); argv[argpos] = item->query; @@ -3969,14 +3971,14 @@ read_cursor_args(PLpgSQL_var *cursor, int until, yyscan_t yyscanner) (errcode(ERRCODE_SYNTAX_ERROR), errmsg("not enough arguments for cursor \"%s\"", cursor->refname), - parser_errposition(yylloc))); + parser_errposition(*yyllocp))); if (endtoken == ',' && (argc == row->nfields - 1)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("too many arguments for cursor \"%s\"", cursor->refname), - parser_errposition(yylloc))); + parser_errposition(*yyllocp))); } /* Make positional argument list */ @@ -4007,9 +4009,9 @@ read_cursor_args(PLpgSQL_var *cursor, int until, yyscan_t yyscanner) pfree(ds.data); /* Next we'd better find the until token */ - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); if (tok != until) - yyerror(yyscanner, "syntax error"); + yyerror(yyllocp, yyscanner, "syntax error"); return expr; } @@ -4018,7 +4020,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until, yyscan_t yyscanner) * Parse RAISE ... USING options */ static List * -read_raise_options(yyscan_t yyscanner) +read_raise_options(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { List *result = NIL; @@ -4027,46 +4029,46 @@ read_raise_options(yyscan_t yyscanner) PLpgSQL_raise_option *opt; int tok; - if ((tok = yylex(yyscanner)) == 0) - yyerror(yyscanner, "unexpected end of function definition"); + if ((tok = yylex(yylvalp, yyllocp, yyscanner)) == 0) + yyerror(yyllocp, yyscanner, "unexpected end of function definition"); opt = (PLpgSQL_raise_option *) palloc(sizeof(PLpgSQL_raise_option)); - if (tok_is_keyword(tok, &yylval, + if (tok_is_keyword(tok, yylvalp, K_ERRCODE, "errcode")) opt->opt_type = PLPGSQL_RAISEOPTION_ERRCODE; - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_MESSAGE, "message")) opt->opt_type = PLPGSQL_RAISEOPTION_MESSAGE; - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_DETAIL, "detail")) opt->opt_type = PLPGSQL_RAISEOPTION_DETAIL; - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_HINT, "hint")) opt->opt_type = PLPGSQL_RAISEOPTION_HINT; - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_COLUMN, "column")) opt->opt_type = PLPGSQL_RAISEOPTION_COLUMN; - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_CONSTRAINT, "constraint")) opt->opt_type = PLPGSQL_RAISEOPTION_CONSTRAINT; - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_DATATYPE, "datatype")) opt->opt_type = PLPGSQL_RAISEOPTION_DATATYPE; - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_TABLE, "table")) opt->opt_type = PLPGSQL_RAISEOPTION_TABLE; - else if (tok_is_keyword(tok, &yylval, + else if (tok_is_keyword(tok, yylvalp, K_SCHEMA, "schema")) opt->opt_type = PLPGSQL_RAISEOPTION_SCHEMA; else - yyerror(yyscanner, "unrecognized RAISE statement option"); + yyerror(yyllocp, yyscanner, "unrecognized RAISE statement option"); - tok = yylex(yyscanner); + tok = yylex(yylvalp, yyllocp, yyscanner); if (tok != '=' && tok != COLON_EQUALS) - yyerror(yyscanner, "syntax error, expected \"=\""); + yyerror(yyllocp, yyscanner, "syntax error, expected \"=\""); - opt->expr = read_sql_expression2(',', ';', ", or ;", &tok, yyscanner); + opt->expr = read_sql_expression2(',', ';', ", or ;", &tok, yylvalp, yyllocp, yyscanner); result = lappend(result, opt); diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c index eeb40c301db..abf2d40c07a 100644 --- a/src/pl/plpgsql/src/pl_scanner.c +++ b/src/pl/plpgsql/src/pl_scanner.c @@ -142,7 +142,7 @@ static void location_lineno_init(void); * matches one of those. */ int -plpgsql_yylex(yyscan_t yyscanner) +plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { int tok1; TokenAuxData aux1; @@ -296,8 +296,8 @@ plpgsql_yylex(yyscan_t yyscanner) */ } - plpgsql_yylval = aux1.lval; - plpgsql_yylloc = aux1.lloc; + *yylvalp = aux1.lval; + *yyllocp = aux1.lloc; plpgsql_yyleng = aux1.leng; plpgsql_yytoken = tok1; return tok1; @@ -383,12 +383,12 @@ push_back_token(int token, TokenAuxData *auxdata) * is not a good idea to push back a token code other than what you read. */ void -plpgsql_push_back_token(int token) +plpgsql_push_back_token(int token, YYSTYPE *yylvalp, YYLTYPE *yyllocp) { TokenAuxData auxdata; - auxdata.lval = plpgsql_yylval; - auxdata.lloc = plpgsql_yylloc; + auxdata.lval = *yylvalp; + auxdata.lloc = *yyllocp; auxdata.leng = plpgsql_yyleng; push_back_token(token, &auxdata); } @@ -512,9 +512,9 @@ plpgsql_scanner_errposition(int location) * be misleading! */ void -plpgsql_yyerror(yyscan_t yyscanner, const char *message) +plpgsql_yyerror(YYLTYPE *yyllocp, yyscan_t yyscanner, const char *message) { - char *yytext = core_yy_extra.scanbuf + plpgsql_yylloc; + char *yytext = core_yy_extra.scanbuf + *yyllocp; if (*yytext == '\0') { @@ -522,7 +522,7 @@ plpgsql_yyerror(yyscan_t yyscanner, const char *message) (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))); + plpgsql_scanner_errposition(*yyllocp))); } else { @@ -538,7 +538,7 @@ plpgsql_yyerror(yyscan_t yyscanner, const char *message) (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))); + plpgsql_scanner_errposition(*yyllocp))); } } diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index 07dcfa84f88..151ae7943df 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -1315,13 +1315,15 @@ extern void plpgsql_dumptree(PLpgSQL_function *func); /* * Scanner functions in pl_scanner.c */ +union YYSTYPE; +#define YYLTYPE int #ifndef YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T typedef void *yyscan_t; #endif -extern int plpgsql_yylex(yyscan_t yyscanner); +extern int plpgsql_yylex(union YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); extern int plpgsql_token_length(void); -extern void plpgsql_push_back_token(int token); +extern void plpgsql_push_back_token(int token, union YYSTYPE *yylvalp, YYLTYPE *yyllocp); extern bool plpgsql_token_is_unreserved_keyword(int token); extern void plpgsql_append_source_text(StringInfo buf, int startlocation, int endlocation); @@ -1329,7 +1331,7 @@ extern int plpgsql_peek(yyscan_t yyscanner); extern void plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc, yyscan_t yyscanner); extern int plpgsql_scanner_errposition(int location); -extern void plpgsql_yyerror(yyscan_t yyscanner, const char *message) pg_attribute_noreturn(); +extern void plpgsql_yyerror(YYLTYPE *yyllocp, yyscan_t yyscanner, const char *message) pg_attribute_noreturn(); extern int plpgsql_location_to_lineno(int location); extern int plpgsql_latest_lineno(void); extern yyscan_t plpgsql_scanner_init(const char *str); -- 2.47.1