From 0728266e298c78e9943cf6f7ac81cd187c236f90 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Sat, 7 Dec 2024 00:09:08 +0100 Subject: [PATCH v2 11/11] plpgsql: reentrant scanner --- src/pl/plpgsql/src/pl_comp.c | 18 +- src/pl/plpgsql/src/pl_gram.y | 420 +++++++++++++++++--------------- src/pl/plpgsql/src/pl_scanner.c | 38 +-- src/pl/plpgsql/src/plpgsql.h | 16 +- 4 files changed, 256 insertions(+), 236 deletions(-) diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 6255a86d75b..917daebef06 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -269,6 +269,7 @@ do_compile(FunctionCallInfo fcinfo, Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup); bool is_dml_trigger = CALLED_AS_TRIGGER(fcinfo); bool is_event_trigger = CALLED_AS_EVENT_TRIGGER(fcinfo); + yyscan_t scanner; Datum prosrcdatum; char *proc_source; HeapTuple typeTup; @@ -292,11 +293,11 @@ do_compile(FunctionCallInfo fcinfo, /* * Setup the scanner input and error info. We assume that this function * cannot be invoked recursively, so there's no need to save and restore - * the static variables used here. + * the static variables used here. XXX */ prosrcdatum = SysCacheGetAttrNotNull(PROCOID, procTup, Anum_pg_proc_prosrc); proc_source = TextDatumGetCString(prosrcdatum); - plpgsql_scanner_init(proc_source); + scanner = plpgsql_scanner_init(proc_source); plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname)); @@ -779,12 +780,12 @@ do_compile(FunctionCallInfo fcinfo, /* * Now parse the function's text */ - parse_rc = plpgsql_yyparse(); + parse_rc = plpgsql_yyparse(scanner); if (parse_rc != 0) elog(ERROR, "plpgsql parser returned %d", parse_rc); function->action = plpgsql_parse_result; - plpgsql_scanner_finish(); + plpgsql_scanner_finish(scanner); pfree(proc_source); /* @@ -841,6 +842,7 @@ do_compile(FunctionCallInfo fcinfo, PLpgSQL_function * plpgsql_compile_inline(char *proc_source) { + yyscan_t scanner; char *func_name = "inline_code_block"; PLpgSQL_function *function; ErrorContextCallback plerrcontext; @@ -851,9 +853,9 @@ plpgsql_compile_inline(char *proc_source) /* * Setup the scanner input and error info. We assume that this function * cannot be invoked recursively, so there's no need to save and restore - * the static variables used here. + * the static variables used here. XXX */ - plpgsql_scanner_init(proc_source); + scanner = plpgsql_scanner_init(proc_source); plpgsql_error_funcname = func_name; @@ -935,12 +937,12 @@ plpgsql_compile_inline(char *proc_source) /* * Now parse the function's text */ - parse_rc = plpgsql_yyparse(); + parse_rc = plpgsql_yyparse(scanner); if (parse_rc != 0) elog(ERROR, "plpgsql parser returned %d", parse_rc); function->action = plpgsql_parse_result; - plpgsql_scanner_finish(); + plpgsql_scanner_finish(scanner); /* * If it returns VOID (always true at the moment), we allow control to diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index 8182ce28aa1..4d09fa89d99 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -63,7 +63,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); +static void current_token_is_not_variable(int tok, yyscan_t yyscanner); static PLpgSQL_expr *read_sql_construct(int until, int until2, int until3, @@ -72,31 +72,33 @@ static PLpgSQL_expr *read_sql_construct(int until, bool isexpression, bool valid_sql, int *startloc, - int *endtoken); + int *endtoken, + yyscan_t yyscanner); static PLpgSQL_expr *read_sql_expression(int until, - const char *expected); + const char *expected, yyscan_t yyscanner); static PLpgSQL_expr *read_sql_expression2(int until, int until2, const char *expected, - int *endtoken); -static PLpgSQL_expr *read_sql_stmt(void); -static PLpgSQL_type *read_datatype(int tok); + int *endtoken, yyscan_t yyscanner); +static PLpgSQL_expr *read_sql_stmt(yyscan_t yyscanner); +static PLpgSQL_type *read_datatype(int tok, yyscan_t yyscanner); static PLpgSQL_stmt *make_execsql_stmt(int firsttoken, int location, - PLword *word); -static PLpgSQL_stmt_fetch *read_fetch_direction(void); + PLword *word, yyscan_t yyscanner); +static PLpgSQL_stmt_fetch *read_fetch_direction(yyscan_t yyscanner); static void complete_direction(PLpgSQL_stmt_fetch *fetch, - bool *check_FROM); -static PLpgSQL_stmt *make_return_stmt(int location); -static PLpgSQL_stmt *make_return_next_stmt(int location); -static PLpgSQL_stmt *make_return_query_stmt(int location); + 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); 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); + bool *strict, yyscan_t yyscanner); static PLpgSQL_row *read_into_scalar_list(char *initial_name, PLpgSQL_datum *initial_datum, - int initial_location); + int initial_location, + yyscan_t yyscanner); static PLpgSQL_row *make_scalar_list1(char *initial_name, PLpgSQL_datum *initial_datum, int lineno, int location); @@ -108,12 +110,14 @@ 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); -static List *read_raise_options(void); + int until, yyscan_t yyscanner); +static List *read_raise_options(yyscan_t yyscanner); static void check_raise_parameters(PLpgSQL_stmt_raise *stmt); %} +%parse-param {yyscan_t yyscanner} +%lex-param {yyscan_t yyscanner} %expect 0 %name-prefix="plpgsql_yy" %locations @@ -577,7 +581,7 @@ opt_scrollable : decl_cursor_query : { - $$ = read_sql_stmt(); + $$ = read_sql_stmt(yyscanner); } ; @@ -706,7 +710,7 @@ decl_varname : T_WORD if (plpgsql_ns_lookup(plpgsql_ns_top(), true, $1.ident, NULL, NULL, NULL) != NULL) - yyerror("duplicate declaration"); + yyerror(yyscanner, "duplicate declaration"); if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR || plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_SHADOWVAR) @@ -734,7 +738,7 @@ decl_varname : T_WORD if (plpgsql_ns_lookup(plpgsql_ns_top(), true, $1, NULL, NULL, NULL) != NULL) - yyerror("duplicate declaration"); + yyerror(yyscanner, "duplicate declaration"); if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR || plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_SHADOWVAR) @@ -766,7 +770,7 @@ decl_datatype : * consume it, and then we must tell bison to forget * it. */ - $$ = read_datatype(yychar); + $$ = read_datatype(yychar, yyscanner); yyclearin; } ; @@ -799,7 +803,7 @@ decl_defval : ';' { $$ = NULL; } | decl_defkey { - $$ = read_sql_expression(';', ";"); + $$ = read_sql_expression(';', ";", yyscanner); } ; @@ -900,7 +904,8 @@ stmt_perform : K_PERFORM new->expr = read_sql_construct(';', 0, 0, ";", RAW_PARSE_DEFAULT, false, false, - &startloc, NULL); + &startloc, NULL, + yyscanner); /* overwrite "perform" ... */ memcpy(new->expr->query, " SELECT", 7); /* left-justify to get rid of the leading space */ @@ -923,7 +928,7 @@ stmt_call : K_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(); + new->expr = read_sql_stmt(yyscanner); new->is_call = true; /* Remember we may need a procedure resource owner */ @@ -942,7 +947,7 @@ stmt_call : K_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(); + new->expr = read_sql_stmt(yyscanner); new->is_call = false; /* Remember we may need a procedure resource owner */ @@ -986,7 +991,8 @@ stmt_assign : T_DATUM new->expr = read_sql_construct(';', 0, 0, ";", pmode, false, true, - NULL, NULL); + NULL, NULL, + yyscanner); $$ = (PLpgSQL_stmt *) new; } @@ -1093,7 +1099,7 @@ getdiag_list_item : getdiag_target assign_operator getdiag_item getdiag_item : { - int tok = yylex(); + int tok = yylex(yyscanner); if (tok_is_keyword(tok, &yylval, K_ROW_COUNT, "row_count")) @@ -1135,7 +1141,7 @@ getdiag_item : K_RETURNED_SQLSTATE, "returned_sqlstate")) $$ = PLPGSQL_GETDIAG_RETURNED_SQLSTATE; else - yyerror("unrecognized GET DIAGNOSTICS item"); + yyerror(yyscanner, "unrecognized GET DIAGNOSTICS item"); } ; @@ -1148,7 +1154,7 @@ getdiag_target : T_DATUM */ if ($1.datum->dtype == PLPGSQL_DTYPE_ROW || $1.datum->dtype == PLPGSQL_DTYPE_REC || - plpgsql_peek() == '[') + plpgsql_peek(yyscanner) == '[') ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("\"%s\" is not a scalar variable", @@ -1222,12 +1228,12 @@ 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(); + int tok = yylex(yyscanner); if (tok != K_WHEN) { plpgsql_push_back_token(tok); - expr = read_sql_expression(K_WHEN, "WHEN"); + expr = read_sql_expression(K_WHEN, "WHEN", yyscanner); } plpgsql_push_back_token(K_WHEN); $$ = expr; @@ -1347,7 +1353,7 @@ stmt_for : opt_loop_label K_FOR for_control loop_body for_control : for_variable K_IN { - int tok = yylex(); + int tok = yylex(yyscanner); int tokloc = yylloc; if (tok == K_EXECUTE) @@ -1359,7 +1365,7 @@ for_control : for_variable K_IN expr = read_sql_expression2(K_LOOP, K_USING, "LOOP or USING", - &term); + &term, yyscanner); new = palloc0(sizeof(PLpgSQL_stmt_dynfors)); new->cmd_type = PLPGSQL_STMT_DYNFORS; @@ -1392,7 +1398,7 @@ for_control : for_variable K_IN { expr = read_sql_expression2(',', K_LOOP, ", or LOOP", - &term); + &term, yyscanner); new->params = lappend(new->params, expr); } while (term == ','); } @@ -1427,8 +1433,7 @@ for_control : for_variable K_IN parser_errposition(tokloc))); /* collect cursor's parameters if any */ - new->argquery = read_cursor_args(cursor, - K_LOOP); + new->argquery = read_cursor_args(cursor, K_LOOP, yyscanner); /* create loop's private RECORD variable */ new->var = (PLpgSQL_variable *) @@ -1479,7 +1484,8 @@ for_control : for_variable K_IN true, false, &expr1loc, - &tok); + &tok, + yyscanner); if (tok == DOT_DOT) { @@ -1500,12 +1506,12 @@ for_control : for_variable K_IN /* Read and check the second one */ expr2 = read_sql_expression2(K_LOOP, K_BY, "LOOP", - &tok); + &tok, yyscanner); /* Get the BY clause if any */ if (tok == K_BY) expr_by = read_sql_expression(K_LOOP, - "LOOP"); + "LOOP", yyscanner); else expr_by = NULL; @@ -1620,13 +1626,14 @@ for_variable : T_DATUM $$.scalar = $1.datum; $$.row = NULL; /* check for comma-separated list */ - tok = yylex(); + tok = yylex(yyscanner); plpgsql_push_back_token(tok); if (tok == ',') $$.row = (PLpgSQL_datum *) read_into_scalar_list($$.name, $$.scalar, - @1); + @1, + yyscanner); } } | T_WORD @@ -1638,7 +1645,7 @@ for_variable : T_DATUM $$.scalar = NULL; $$.row = NULL; /* check for comma-separated list */ - tok = yylex(); + tok = yylex(yyscanner); plpgsql_push_back_token(tok); if (tok == ',') word_is_not_variable(&($1), @1); @@ -1765,24 +1772,24 @@ stmt_return : K_RETURN { int tok; - tok = yylex(); + tok = yylex(yyscanner); if (tok == 0) - yyerror("unexpected end of function definition"); + yyerror(yyscanner, "unexpected end of function definition"); if (tok_is_keyword(tok, &yylval, K_NEXT, "next")) { - $$ = make_return_next_stmt(@1); + $$ = make_return_next_stmt(@1, yyscanner); } else if (tok_is_keyword(tok, &yylval, K_QUERY, "query")) { - $$ = make_return_query_stmt(@1); + $$ = make_return_query_stmt(@1, yyscanner); } else { plpgsql_push_back_token(tok); - $$ = make_return_stmt(@1); + $$ = make_return_stmt(@1, yyscanner); } } ; @@ -1803,9 +1810,9 @@ stmt_raise : K_RAISE new->params = NIL; new->options = NIL; - tok = yylex(); + tok = yylex(yyscanner); if (tok == 0) - yyerror("unexpected end of function definition"); + yyerror(yyscanner, "unexpected end of function definition"); /* * We could have just RAISE, meaning to re-throw @@ -1820,40 +1827,40 @@ stmt_raise : K_RAISE K_EXCEPTION, "exception")) { new->elog_level = ERROR; - tok = yylex(); + tok = yylex(yyscanner); } else if (tok_is_keyword(tok, &yylval, K_WARNING, "warning")) { new->elog_level = WARNING; - tok = yylex(); + tok = yylex(yyscanner); } else if (tok_is_keyword(tok, &yylval, K_NOTICE, "notice")) { new->elog_level = NOTICE; - tok = yylex(); + tok = yylex(yyscanner); } else if (tok_is_keyword(tok, &yylval, K_INFO, "info")) { new->elog_level = INFO; - tok = yylex(); + tok = yylex(yyscanner); } else if (tok_is_keyword(tok, &yylval, K_LOG, "log")) { new->elog_level = LOG; - tok = yylex(); + tok = yylex(yyscanner); } else if (tok_is_keyword(tok, &yylval, K_DEBUG, "debug")) { new->elog_level = DEBUG1; - tok = yylex(); + tok = yylex(yyscanner); } if (tok == 0) - yyerror("unexpected end of function definition"); + yyerror(yyscanner, "unexpected end of function definition"); /* * Next we can have a condition name, or @@ -1871,9 +1878,9 @@ stmt_raise : K_RAISE * begins the list of parameter expressions, * or USING to begin the options list. */ - tok = yylex(); + tok = yylex(yyscanner); if (tok != ',' && tok != ';' && tok != K_USING) - yyerror("syntax error"); + yyerror(yyscanner, "syntax error"); while (tok == ',') { @@ -1883,7 +1890,8 @@ stmt_raise : K_RAISE ", or ; or USING", RAW_PARSE_PLPGSQL_EXPR, true, true, - NULL, &tok); + NULL, &tok, + yyscanner); new->params = lappend(new->params, expr); } } @@ -1896,14 +1904,14 @@ stmt_raise : K_RAISE /* next token should be a string literal */ char *sqlstatestr; - if (yylex() != SCONST) - yyerror("syntax error"); + if (yylex(yyscanner) != SCONST) + yyerror(yyscanner, "syntax error"); sqlstatestr = yylval.str; if (strlen(sqlstatestr) != 5) - yyerror("invalid SQLSTATE code"); + yyerror(yyscanner, "invalid SQLSTATE code"); if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5) - yyerror("invalid SQLSTATE code"); + yyerror(yyscanner, "invalid SQLSTATE code"); new->condname = sqlstatestr; } else @@ -1913,17 +1921,17 @@ stmt_raise : K_RAISE else if (plpgsql_token_is_unreserved_keyword(tok)) new->condname = pstrdup(yylval.keyword); else - yyerror("syntax error"); + yyerror(yyscanner, "syntax error"); plpgsql_recognize_err_condition(new->condname, false); } - tok = yylex(); + tok = yylex(yyscanner); if (tok != ';' && tok != K_USING) - yyerror("syntax error"); + yyerror(yyscanner, "syntax error"); } if (tok == K_USING) - new->options = read_raise_options(); + new->options = read_raise_options(yyscanner); } check_raise_parameters(new); @@ -1945,10 +1953,10 @@ stmt_assert : K_ASSERT new->cond = read_sql_expression2(',', ';', ", or ;", - &tok); + &tok, yyscanner); if (tok == ',') - new->message = read_sql_expression(';', ";"); + new->message = read_sql_expression(';', ";", yyscanner); else new->message = NULL; @@ -1976,37 +1984,37 @@ loop_body : proc_sect K_END K_LOOP opt_label ';' */ stmt_execsql : K_IMPORT { - $$ = make_execsql_stmt(K_IMPORT, @1, NULL); + $$ = make_execsql_stmt(K_IMPORT, @1, NULL, yyscanner); } | K_INSERT { - $$ = make_execsql_stmt(K_INSERT, @1, NULL); + $$ = make_execsql_stmt(K_INSERT, @1, NULL, yyscanner); } | K_MERGE { - $$ = make_execsql_stmt(K_MERGE, @1, NULL); + $$ = make_execsql_stmt(K_MERGE, @1, NULL, yyscanner); } | T_WORD { int tok; - tok = yylex(); + tok = yylex(yyscanner); plpgsql_push_back_token(tok); if (tok == '=' || tok == COLON_EQUALS || tok == '[' || tok == '.') word_is_not_variable(&($1), @1); - $$ = make_execsql_stmt(T_WORD, @1, &($1)); + $$ = make_execsql_stmt(T_WORD, @1, &($1), yyscanner); } | T_CWORD { int tok; - tok = yylex(); + tok = yylex(yyscanner); plpgsql_push_back_token(tok); if (tok == '=' || tok == COLON_EQUALS || tok == '[' || tok == '.') cword_is_not_variable(&($1), @1); - $$ = make_execsql_stmt(T_CWORD, @1, NULL); + $$ = make_execsql_stmt(T_CWORD, @1, NULL, yyscanner); } ; @@ -2020,7 +2028,8 @@ stmt_dynexecute : K_EXECUTE "INTO or USING or ;", RAW_PARSE_PLPGSQL_EXPR, true, true, - NULL, &endtoken); + NULL, &endtoken, + yyscanner); new = palloc(sizeof(PLpgSQL_stmt_dynexecute)); new->cmd_type = PLPGSQL_STMT_DYNEXECUTE; @@ -2044,29 +2053,30 @@ stmt_dynexecute : K_EXECUTE if (endtoken == K_INTO) { if (new->into) /* multiple INTO */ - yyerror("syntax error"); + yyerror(yyscanner, "syntax error"); new->into = true; - read_into_target(&new->target, &new->strict); - endtoken = yylex(); + read_into_target(&new->target, &new->strict, yyscanner); + endtoken = yylex(yyscanner); } else if (endtoken == K_USING) { if (new->params) /* multiple USING */ - yyerror("syntax error"); + yyerror(yyscanner, "syntax error"); do { expr = read_sql_construct(',', ';', K_INTO, ", or ; or INTO", RAW_PARSE_PLPGSQL_EXPR, true, true, - NULL, &endtoken); + NULL, &endtoken, + yyscanner); new->params = lappend(new->params, expr); } while (endtoken == ','); } else if (endtoken == ';') break; else - yyerror("syntax error"); + yyerror(yyscanner, "syntax error"); } $$ = (PLpgSQL_stmt *) new; @@ -2089,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(); + tok = yylex(yyscanner); if (tok_is_keyword(tok, &yylval, K_NO, "no")) { - tok = yylex(); + tok = yylex(yyscanner); if (tok_is_keyword(tok, &yylval, K_SCROLL, "scroll")) { new->cursor_options |= CURSOR_OPT_NO_SCROLL; - tok = yylex(); + tok = yylex(yyscanner); } } else if (tok_is_keyword(tok, &yylval, K_SCROLL, "scroll")) { new->cursor_options |= CURSOR_OPT_SCROLL; - tok = yylex(); + tok = yylex(yyscanner); } if (tok != K_FOR) - yyerror("syntax error, expected \"FOR\""); + yyerror(yyscanner, "syntax error, expected \"FOR\""); - tok = yylex(); + tok = yylex(yyscanner); if (tok == K_EXECUTE) { int endtoken; @@ -2119,7 +2129,7 @@ stmt_open : K_OPEN cursor_variable new->dynquery = read_sql_expression2(K_USING, ';', "USING or ;", - &endtoken); + &endtoken, yyscanner); /* If we found "USING", collect argument(s) */ if (endtoken == K_USING) @@ -2130,7 +2140,7 @@ stmt_open : K_OPEN cursor_variable { expr = read_sql_expression2(',', ';', ", or ;", - &endtoken); + &endtoken, yyscanner); new->params = lappend(new->params, expr); } while (endtoken == ','); @@ -2139,13 +2149,13 @@ stmt_open : K_OPEN cursor_variable else { plpgsql_push_back_token(tok); - new->query = read_sql_stmt(); + new->query = read_sql_stmt(yyscanner); } } else { /* predefined cursor query, so read args */ - new->argquery = read_cursor_args($2, ';'); + new->argquery = read_cursor_args($2, ';', yyscanner); } $$ = (PLpgSQL_stmt *) new; @@ -2158,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); + read_into_target(&target, NULL, yyscanner); - if (yylex() != ';') - yyerror("syntax error"); + if (yylex(yyscanner) != ';') + yyerror(yyscanner, "syntax error"); /* * We don't allow multiple rows in PL/pgSQL's FETCH @@ -2196,7 +2206,7 @@ stmt_move : K_MOVE opt_fetch_direction cursor_variable ';' opt_fetch_direction : { - $$ = read_fetch_direction(); + $$ = read_fetch_direction(yyscanner); } ; @@ -2264,7 +2274,7 @@ cursor_variable : T_DATUM * just throw an error if next token is '['. */ if ($1.datum->dtype != PLPGSQL_DTYPE_VAR || - plpgsql_peek() == '[') + plpgsql_peek(yyscanner) == '[') ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("cursor variable must be a simple variable"), @@ -2384,14 +2394,14 @@ proc_condition : any_identifier char *sqlstatestr; /* next token should be a string literal */ - if (yylex() != SCONST) - yyerror("syntax error"); + if (yylex(yyscanner) != SCONST) + yyerror(yyscanner, "syntax error"); sqlstatestr = yylval.str; if (strlen(sqlstatestr) != 5) - yyerror("invalid SQLSTATE code"); + yyerror(yyscanner, "invalid SQLSTATE code"); if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5) - yyerror("invalid SQLSTATE code"); + yyerror(yyscanner, "invalid SQLSTATE code"); new = palloc(sizeof(PLpgSQL_condition)); new->sqlerrstate = @@ -2409,15 +2419,15 @@ proc_condition : any_identifier ; expr_until_semi : - { $$ = read_sql_expression(';', ";"); } + { $$ = read_sql_expression(';', ";", yyscanner); } ; expr_until_then : - { $$ = read_sql_expression(K_THEN, "THEN"); } + { $$ = read_sql_expression(K_THEN, "THEN", yyscanner); } ; expr_until_loop : - { $$ = read_sql_expression(K_LOOP, "LOOP"); } + { $$ = read_sql_expression(K_LOOP, "LOOP", yyscanner); } ; opt_block_label : @@ -2475,7 +2485,7 @@ any_identifier : T_WORD | T_DATUM { if ($1.ident == NULL) /* composite name not OK */ - yyerror("syntax error"); + yyerror(yyscanner, "syntax error"); $$ = $1.ident; } ; @@ -2627,42 +2637,45 @@ cword_is_not_variable(PLcword *cword, int location) * look at yylval and yylloc. */ static void -current_token_is_not_variable(int tok) +current_token_is_not_variable(int tok, yyscan_t yyscanner) { if (tok == T_WORD) word_is_not_variable(&(yylval.word), yylloc); else if (tok == T_CWORD) cword_is_not_variable(&(yylval.cword), yylloc); else - yyerror("syntax error"); + yyerror(yyscanner, "syntax error"); } /* Convenience routine to read an expression with one possible terminator */ static PLpgSQL_expr * -read_sql_expression(int until, const char *expected) +read_sql_expression(int until, const char *expected, yyscan_t yyscanner) { return read_sql_construct(until, 0, 0, expected, RAW_PARSE_PLPGSQL_EXPR, - true, true, NULL, NULL); + true, true, NULL, NULL, + 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) + int *endtoken, yyscan_t yyscanner) { return read_sql_construct(until, until2, 0, expected, RAW_PARSE_PLPGSQL_EXPR, - true, true, NULL, endtoken); + true, true, NULL, endtoken, + yyscanner); } /* Convenience routine to read a SQL statement that must end with ';' */ static PLpgSQL_expr * -read_sql_stmt(void) +read_sql_stmt(yyscan_t yyscanner) { return read_sql_construct(';', 0, 0, ";", RAW_PARSE_DEFAULT, - false, true, NULL, NULL); + false, true, NULL, NULL, + yyscanner); } /* @@ -2688,7 +2701,8 @@ read_sql_construct(int until, bool isexpression, bool valid_sql, int *startloc, - int *endtoken) + int *endtoken, + yyscan_t yyscanner) { int tok; StringInfoData ds; @@ -2706,7 +2720,7 @@ read_sql_construct(int until, for (;;) { - tok = yylex(); + tok = yylex(yyscanner); if (startlocation < 0) /* remember loc of first token */ startlocation = yylloc; if (tok == until && parenlevel == 0) @@ -2721,7 +2735,7 @@ read_sql_construct(int until, { parenlevel--; if (parenlevel < 0) - yyerror("mismatched parentheses"); + yyerror(yyscanner, "mismatched parentheses"); } /* * End of function definition is an error, and we don't expect to @@ -2731,7 +2745,7 @@ read_sql_construct(int until, if (tok == 0 || tok == ';') { if (parenlevel != 0) - yyerror("mismatched parentheses"); + yyerror(yyscanner, "mismatched parentheses"); if (isexpression) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -2760,9 +2774,9 @@ read_sql_construct(int until, if (startlocation >= endlocation) { if (isexpression) - yyerror("missing expression"); + yyerror(yyscanner, "missing expression"); else - yyerror("missing SQL statement"); + yyerror(yyscanner, "missing SQL statement"); } /* @@ -2794,7 +2808,7 @@ read_sql_construct(int until, * Returns a PLpgSQL_type struct. */ static PLpgSQL_type * -read_datatype(int tok) +read_datatype(int tok, yyscan_t yyscanner) { StringInfoData ds; char *type_name; @@ -2807,7 +2821,7 @@ read_datatype(int tok) /* Often there will be a lookahead token, but if not, get one */ if (tok == YYEMPTY) - tok = yylex(); + tok = yylex(yyscanner); /* The current token is the start of what we'll pass to parse_datatype */ startlocation = yylloc; @@ -2820,10 +2834,10 @@ read_datatype(int tok) { char *dtname = yylval.word.ident; - tok = yylex(); + tok = yylex(yyscanner); if (tok == '%') { - tok = yylex(); + tok = yylex(yyscanner); if (tok_is_keyword(tok, &yylval, K_TYPE, "type")) result = plpgsql_parse_wordtype(dtname); @@ -2836,10 +2850,10 @@ read_datatype(int tok) { char *dtname = pstrdup(yylval.keyword); - tok = yylex(); + tok = yylex(yyscanner); if (tok == '%') { - tok = yylex(); + tok = yylex(yyscanner); if (tok_is_keyword(tok, &yylval, K_TYPE, "type")) result = plpgsql_parse_wordtype(dtname); @@ -2852,10 +2866,10 @@ read_datatype(int tok) { List *dtnames = yylval.cword.idents; - tok = yylex(); + tok = yylex(yyscanner); if (tok == '%') { - tok = yylex(); + tok = yylex(yyscanner); if (tok_is_keyword(tok, &yylval, K_TYPE, "type")) result = plpgsql_parse_cwordtype(dtnames); @@ -2877,22 +2891,22 @@ read_datatype(int tok) { bool is_array = false; - tok = yylex(); + tok = yylex(yyscanner); if (tok_is_keyword(tok, &yylval, K_ARRAY, "array")) { is_array = true; - tok = yylex(); + tok = yylex(yyscanner); } while (tok == '[') { is_array = true; - tok = yylex(); + tok = yylex(yyscanner); if (tok == ICONST) - tok = yylex(); + tok = yylex(yyscanner); if (tok != ']') - yyerror("syntax error, expected \"]\""); - tok = yylex(); + yyerror(yyscanner, "syntax error, expected \"]\""); + tok = yylex(yyscanner); } plpgsql_push_back_token(tok); @@ -2913,9 +2927,9 @@ read_datatype(int tok) if (tok == 0) { if (parenlevel != 0) - yyerror("mismatched parentheses"); + yyerror(yyscanner, "mismatched parentheses"); else - yyerror("incomplete data type declaration"); + yyerror(yyscanner, "incomplete data type declaration"); } /* Possible followers for datatype in a declaration */ if (tok == K_COLLATE || tok == K_NOT || @@ -2929,7 +2943,7 @@ read_datatype(int tok) else if (tok == ')') parenlevel--; - tok = yylex(); + tok = yylex(yyscanner); } /* set up ds to contain complete typename text */ @@ -2938,7 +2952,7 @@ read_datatype(int tok) type_name = ds.data; if (type_name[0] == '\0') - yyerror("missing data type declaration"); + yyerror(yyscanner, "missing data type declaration"); result = parse_datatype(type_name, startlocation); @@ -2955,7 +2969,7 @@ read_datatype(int tok) * 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) +make_execsql_stmt(int firsttoken, int location, PLword *word, yyscan_t yyscanner) { StringInfoData ds; IdentifierLookup save_IdentifierLookup; @@ -3024,7 +3038,7 @@ make_execsql_stmt(int firsttoken, int location, PLword *word) for (;;) { prev_tok = tok; - tok = yylex(); + tok = yylex(yyscanner); if (have_into && into_end_loc < 0) into_end_loc = yylloc; /* token after the INTO part */ /* Detect CREATE [OR REPLACE] {FUNCTION|PROCEDURE} */ @@ -3063,7 +3077,7 @@ make_execsql_stmt(int firsttoken, int location, PLword *word) if (tok == ';' && paren_depth == 0 && begin_depth == 0) break; if (tok == 0) - yyerror("unexpected end of function definition"); + yyerror(yyscanner, "unexpected end of function definition"); if (tok == K_INTO) { if (prev_tok == K_INSERT) @@ -3073,11 +3087,11 @@ make_execsql_stmt(int firsttoken, int location, PLword *word) if (firsttoken == K_IMPORT) continue; /* IMPORT ... INTO is not an INTO-target */ if (have_into) - yyerror("INTO specified more than once"); + yyerror(yyscanner, "INTO specified more than once"); have_into = true; into_start_loc = yylloc; plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL; - read_into_target(&target, &have_strict); + read_into_target(&target, &have_strict, yyscanner); plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR; } } @@ -3130,7 +3144,7 @@ make_execsql_stmt(int firsttoken, int location, PLword *word) * Read FETCH or MOVE direction clause (everything through FROM/IN). */ static PLpgSQL_stmt_fetch * -read_fetch_direction(void) +read_fetch_direction(yyscan_t yyscanner) { PLpgSQL_stmt_fetch *fetch; int tok; @@ -3149,9 +3163,9 @@ read_fetch_direction(void) fetch->expr = NULL; fetch->returns_multiple_rows = false; - tok = yylex(); + tok = yylex(yyscanner); if (tok == 0) - yyerror("unexpected end of function definition"); + yyerror(yyscanner, "unexpected end of function definition"); if (tok_is_keyword(tok, &yylval, K_NEXT, "next")) @@ -3180,7 +3194,7 @@ read_fetch_direction(void) fetch->direction = FETCH_ABSOLUTE; fetch->expr = read_sql_expression2(K_FROM, K_IN, "FROM or IN", - NULL); + NULL, yyscanner); check_FROM = false; } else if (tok_is_keyword(tok, &yylval, @@ -3189,7 +3203,7 @@ read_fetch_direction(void) fetch->direction = FETCH_RELATIVE; fetch->expr = read_sql_expression2(K_FROM, K_IN, "FROM or IN", - NULL); + NULL, yyscanner); check_FROM = false; } else if (tok_is_keyword(tok, &yylval, @@ -3201,13 +3215,13 @@ read_fetch_direction(void) else if (tok_is_keyword(tok, &yylval, K_FORWARD, "forward")) { - complete_direction(fetch, &check_FROM); + complete_direction(fetch, &check_FROM, yyscanner); } else if (tok_is_keyword(tok, &yylval, K_BACKWARD, "backward")) { fetch->direction = FETCH_BACKWARD; - complete_direction(fetch, &check_FROM); + complete_direction(fetch, &check_FROM, yyscanner); } else if (tok == K_FROM || tok == K_IN) { @@ -3233,7 +3247,7 @@ read_fetch_direction(void) plpgsql_push_back_token(tok); fetch->expr = read_sql_expression2(K_FROM, K_IN, "FROM or IN", - NULL); + NULL, yyscanner); fetch->returns_multiple_rows = true; check_FROM = false; } @@ -3241,9 +3255,9 @@ read_fetch_direction(void) /* check FROM or IN keyword after direction's specification */ if (check_FROM) { - tok = yylex(); + tok = yylex(yyscanner); if (tok != K_FROM && tok != K_IN) - yyerror("expected FROM or IN"); + yyerror(yyscanner, "expected FROM or IN"); } return fetch; @@ -3256,13 +3270,13 @@ read_fetch_direction(void) * BACKWARD expr, BACKWARD ALL, BACKWARD */ static void -complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM) +complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM, yyscan_t yyscanner) { int tok; - tok = yylex(); + tok = yylex(yyscanner); if (tok == 0) - yyerror("unexpected end of function definition"); + yyerror(yyscanner, "unexpected end of function definition"); if (tok == K_FROM || tok == K_IN) { @@ -3281,14 +3295,14 @@ complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM) plpgsql_push_back_token(tok); fetch->expr = read_sql_expression2(K_FROM, K_IN, "FROM or IN", - NULL); + NULL, yyscanner); fetch->returns_multiple_rows = true; *check_FROM = false; } static PLpgSQL_stmt * -make_return_stmt(int location) +make_return_stmt(int location, yyscan_t yyscanner) { PLpgSQL_stmt_return *new; @@ -3301,7 +3315,7 @@ make_return_stmt(int location) if (plpgsql_curr_compile->fn_retset) { - if (yylex() != ';') + if (yylex(yyscanner) != ';') ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("RETURN cannot have a parameter in function returning set"), @@ -3310,7 +3324,7 @@ make_return_stmt(int location) } else if (plpgsql_curr_compile->fn_rettype == VOIDOID) { - if (yylex() != ';') + if (yylex(yyscanner) != ';') { if (plpgsql_curr_compile->fn_prokind == PROKIND_PROCEDURE) ereport(ERROR, @@ -3326,7 +3340,7 @@ make_return_stmt(int location) } else if (plpgsql_curr_compile->out_param_varno >= 0) { - if (yylex() != ';') + if (yylex(yyscanner) != ';') ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("RETURN cannot have a parameter in function with OUT parameters"), @@ -3339,9 +3353,9 @@ make_return_stmt(int location) * We want to special-case simple variable references for efficiency. * So peek ahead to see if that's what we have. */ - int tok = yylex(); + int tok = yylex(yyscanner); - if (tok == T_DATUM && plpgsql_peek() == ';' && + 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 || @@ -3349,7 +3363,7 @@ make_return_stmt(int location) { new->retvarno = yylval.wdatum.datum->dno; /* eat the semicolon token that we only peeked at above */ - tok = yylex(); + tok = yylex(yyscanner); Assert(tok == ';'); } else @@ -3361,7 +3375,7 @@ make_return_stmt(int location) * anything else is a compile-time error. */ plpgsql_push_back_token(tok); - new->expr = read_sql_expression(';', ";"); + new->expr = read_sql_expression(';', ";", yyscanner); } } @@ -3370,7 +3384,7 @@ make_return_stmt(int location) static PLpgSQL_stmt * -make_return_next_stmt(int location) +make_return_next_stmt(int location, yyscan_t yyscanner) { PLpgSQL_stmt_return_next *new; @@ -3389,7 +3403,7 @@ make_return_next_stmt(int location) if (plpgsql_curr_compile->out_param_varno >= 0) { - if (yylex() != ';') + if (yylex(yyscanner) != ';') ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("RETURN NEXT cannot have a parameter in function with OUT parameters"), @@ -3402,9 +3416,9 @@ make_return_next_stmt(int location) * We want to special-case simple variable references for efficiency. * So peek ahead to see if that's what we have. */ - int tok = yylex(); + int tok = yylex(yyscanner); - if (tok == T_DATUM && plpgsql_peek() == ';' && + 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 || @@ -3412,7 +3426,7 @@ make_return_next_stmt(int location) { new->retvarno = yylval.wdatum.datum->dno; /* eat the semicolon token that we only peeked at above */ - tok = yylex(); + tok = yylex(yyscanner); Assert(tok == ';'); } else @@ -3424,7 +3438,7 @@ make_return_next_stmt(int location) * anything else is a compile-time error. */ plpgsql_push_back_token(tok); - new->expr = read_sql_expression(';', ";"); + new->expr = read_sql_expression(';', ";", yyscanner); } } @@ -3433,7 +3447,7 @@ make_return_next_stmt(int location) static PLpgSQL_stmt * -make_return_query_stmt(int location) +make_return_query_stmt(int location, yyscan_t yyscanner) { PLpgSQL_stmt_return_query *new; int tok; @@ -3450,11 +3464,11 @@ make_return_query_stmt(int location) new->stmtid = ++plpgsql_curr_compile->nstatements; /* check for RETURN QUERY EXECUTE */ - if ((tok = yylex()) != K_EXECUTE) + if ((tok = yylex(yyscanner)) != K_EXECUTE) { /* ordinary static query */ plpgsql_push_back_token(tok); - new->query = read_sql_stmt(); + new->query = read_sql_stmt(yyscanner); } else { @@ -3462,14 +3476,14 @@ make_return_query_stmt(int location) int term; new->dynquery = read_sql_expression2(';', K_USING, "; or USING", - &term); + &term, yyscanner); if (term == K_USING) { do { PLpgSQL_expr *expr; - expr = read_sql_expression2(',', ';', ", or ;", &term); + expr = read_sql_expression2(',', ';', ", or ;", &term, yyscanner); new->params = lappend(new->params, expr); } while (term == ','); } @@ -3523,7 +3537,7 @@ check_assignable(PLpgSQL_datum *datum, int location) * INTO keyword. */ static void -read_into_target(PLpgSQL_variable **target, bool *strict) +read_into_target(PLpgSQL_variable **target, bool *strict, yyscan_t yyscanner) { int tok; @@ -3532,11 +3546,11 @@ read_into_target(PLpgSQL_variable **target, bool *strict) if (strict) *strict = false; - tok = yylex(); + tok = yylex(yyscanner); if (strict && tok == K_STRICT) { *strict = true; - tok = yylex(); + tok = yylex(yyscanner); } /* @@ -3555,7 +3569,7 @@ read_into_target(PLpgSQL_variable **target, bool *strict) check_assignable(yylval.wdatum.datum, yylloc); *target = (PLpgSQL_variable *) yylval.wdatum.datum; - if ((tok = yylex()) == ',') + if ((tok = yylex(yyscanner)) == ',') ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("record variable cannot be part of multiple-item INTO list"), @@ -3566,13 +3580,13 @@ read_into_target(PLpgSQL_variable **target, bool *strict) { *target = (PLpgSQL_variable *) read_into_scalar_list(NameOfDatum(&(yylval.wdatum)), - yylval.wdatum.datum, yylloc); + yylval.wdatum.datum, yylloc, yyscanner); } break; default: /* just to give a better message than "syntax error" */ - current_token_is_not_variable(tok); + current_token_is_not_variable(tok, yyscanner); } } @@ -3585,7 +3599,8 @@ read_into_target(PLpgSQL_variable **target, bool *strict) static PLpgSQL_row * read_into_scalar_list(char *initial_name, PLpgSQL_datum *initial_datum, - int initial_location) + int initial_location, + yyscan_t yyscanner) { int nfields; char *fieldnames[1024]; @@ -3598,7 +3613,7 @@ read_into_scalar_list(char *initial_name, varnos[0] = initial_datum->dno; nfields = 1; - while ((tok = yylex()) == ',') + while ((tok = yylex(yyscanner)) == ',') { /* Check for array overflow */ if (nfields >= 1024) @@ -3607,7 +3622,7 @@ read_into_scalar_list(char *initial_name, errmsg("too many INTO variables specified"), parser_errposition(yylloc))); - tok = yylex(); + tok = yylex(yyscanner); switch (tok) { case T_DATUM: @@ -3625,7 +3640,7 @@ read_into_scalar_list(char *initial_name, default: /* just to give a better message than "syntax error" */ - current_token_is_not_variable(tok); + current_token_is_not_variable(tok, yyscanner); } } @@ -3836,7 +3851,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) +read_cursor_args(PLpgSQL_var *cursor, int until, yyscan_t yyscanner) { PLpgSQL_expr *expr; PLpgSQL_row *row; @@ -3846,7 +3861,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until) StringInfoData ds; bool any_named = false; - tok = yylex(); + tok = yylex(yyscanner); if (cursor->cursor_explicit_argrow < 0) { /* No arguments expected */ @@ -3858,7 +3873,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until) parser_errposition(yylloc))); if (tok != until) - yyerror("syntax error"); + yyerror(yyscanner, "syntax error"); return NULL; } @@ -3887,7 +3902,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until) int arglocation; /* Check if it's a named parameter: "param := value" */ - plpgsql_peek2(&tok1, &tok2, &arglocation, NULL); + plpgsql_peek2(&tok1, &tok2, &arglocation, NULL, yyscanner); if (tok1 == IDENT && tok2 == COLON_EQUALS) { char *argname; @@ -3896,7 +3911,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until) /* Read the argument name, ignoring any matching variable */ save_IdentifierLookup = plpgsql_IdentifierLookup; plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_DECLARE; - yylex(); + yylex(yyscanner); argname = yylval.str; plpgsql_IdentifierLookup = save_IdentifierLookup; @@ -3917,9 +3932,9 @@ read_cursor_args(PLpgSQL_var *cursor, int until) * Eat the ":=". We already peeked, so the error should never * happen. */ - tok2 = yylex(); + tok2 = yylex(yyscanner); if (tok2 != COLON_EQUALS) - yyerror("syntax error"); + yyerror(yyscanner, "syntax error"); any_named = true; } @@ -3943,7 +3958,8 @@ read_cursor_args(PLpgSQL_var *cursor, int until) ",\" or \")", RAW_PARSE_PLPGSQL_EXPR, true, true, - NULL, &endtoken); + NULL, &endtoken, + yyscanner); argv[argpos] = item->query; @@ -3990,9 +4006,9 @@ read_cursor_args(PLpgSQL_var *cursor, int until) pfree(ds.data); /* Next we'd better find the until token */ - tok = yylex(); + tok = yylex(yyscanner); if (tok != until) - yyerror("syntax error"); + yyerror(yyscanner, "syntax error"); return expr; } @@ -4001,7 +4017,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until) * Parse RAISE ... USING options */ static List * -read_raise_options(void) +read_raise_options(yyscan_t yyscanner) { List *result = NIL; @@ -4010,8 +4026,8 @@ read_raise_options(void) PLpgSQL_raise_option *opt; int tok; - if ((tok = yylex()) == 0) - yyerror("unexpected end of function definition"); + if ((tok = yylex(yyscanner)) == 0) + yyerror(yyscanner, "unexpected end of function definition"); opt = (PLpgSQL_raise_option *) palloc(sizeof(PLpgSQL_raise_option)); @@ -4043,13 +4059,13 @@ read_raise_options(void) K_SCHEMA, "schema")) opt->opt_type = PLPGSQL_RAISEOPTION_SCHEMA; else - yyerror("unrecognized RAISE statement option"); + yyerror(yyscanner, "unrecognized RAISE statement option"); - tok = yylex(); + tok = yylex(yyscanner); if (tok != '=' && tok != COLON_EQUALS) - yyerror("syntax error, expected \"=\""); + yyerror(yyscanner, "syntax error, expected \"=\""); - opt->expr = read_sql_expression2(',', ';', ", or ;", &tok); + opt->expr = read_sql_expression2(',', ';', ", or ;", &tok, yyscanner); result = lappend(result, opt); diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c index 9407da51efa..e24b107909b 100644 --- a/src/pl/plpgsql/src/pl_scanner.c +++ b/src/pl/plpgsql/src/pl_scanner.c @@ -103,7 +103,6 @@ typedef struct */ /* The stuff the core lexer needs */ -static core_yyscan_t yyscanner = NULL; static core_yy_extra_type core_yy; /* The original input string */ @@ -128,7 +127,7 @@ static const char *cur_line_end; static int cur_line_num; /* Internal functions */ -static int internal_yylex(TokenAuxData *auxdata); +static int internal_yylex(TokenAuxData *auxdata, yyscan_t yyscanner); static void push_back_token(int token, TokenAuxData *auxdata); static void location_lineno_init(void); @@ -143,37 +142,37 @@ static void location_lineno_init(void); * matches one of those. */ int -plpgsql_yylex(void) +plpgsql_yylex(yyscan_t yyscanner) { int tok1; TokenAuxData aux1; int kwnum; - tok1 = internal_yylex(&aux1); + tok1 = internal_yylex(&aux1, yyscanner); if (tok1 == IDENT || tok1 == PARAM) { int tok2; TokenAuxData aux2; - tok2 = internal_yylex(&aux2); + tok2 = internal_yylex(&aux2, yyscanner); if (tok2 == '.') { int tok3; TokenAuxData aux3; - tok3 = internal_yylex(&aux3); + tok3 = internal_yylex(&aux3, yyscanner); if (tok3 == IDENT) { int tok4; TokenAuxData aux4; - tok4 = internal_yylex(&aux4); + tok4 = internal_yylex(&aux4, yyscanner); if (tok4 == '.') { int tok5; TokenAuxData aux5; - tok5 = internal_yylex(&aux5); + tok5 = internal_yylex(&aux5, yyscanner); if (tok5 == IDENT) { if (plpgsql_parse_tripword(aux1.lval.str, @@ -322,7 +321,7 @@ plpgsql_token_length(void) * interfacing from the core_YYSTYPE to YYSTYPE union. */ static int -internal_yylex(TokenAuxData *auxdata) +internal_yylex(TokenAuxData *auxdata, yyscan_t yyscanner) { int token; const char *yytext; @@ -434,12 +433,12 @@ plpgsql_append_source_text(StringInfo buf, * be returned as IDENT. Reserved keywords are resolved as usual. */ int -plpgsql_peek(void) +plpgsql_peek(yyscan_t yyscanner) { int tok1; TokenAuxData aux1; - tok1 = internal_yylex(&aux1); + tok1 = internal_yylex(&aux1, yyscanner); push_back_token(tok1, &aux1); return tok1; } @@ -453,15 +452,15 @@ plpgsql_peek(void) * be returned as IDENT. Reserved keywords are resolved as usual. */ void -plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc) +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); - tok2 = internal_yylex(&aux2); + tok1 = internal_yylex(&aux1, yyscanner); + tok2 = internal_yylex(&aux2, yyscanner); *tok1_p = tok1; if (tok1_loc) @@ -513,7 +512,7 @@ plpgsql_scanner_errposition(int location) * be misleading! */ void -plpgsql_yyerror(const char *message) +plpgsql_yyerror(yyscan_t yyscanner, const char *message) { char *yytext = core_yy.scanbuf + plpgsql_yylloc; @@ -599,9 +598,11 @@ plpgsql_latest_lineno(void) * Although it is not fed directly to flex, we need the original string * to cite in error messages. */ -void +yyscan_t plpgsql_scanner_init(const char *str) { + yyscan_t yyscanner; + /* Start up the core scanner */ yyscanner = scanner_init(str, &core_yy, &ReservedPLKeywords, ReservedPLKeywordTokens); @@ -621,17 +622,18 @@ plpgsql_scanner_init(const char *str) num_pushbacks = 0; location_lineno_init(); + + return yyscanner; } /* * Called after parsing is done to clean up after plpgsql_scanner_init() */ void -plpgsql_scanner_finish(void) +plpgsql_scanner_finish(yyscan_t yyscanner) { /* release storage */ scanner_finish(yyscanner); /* avoid leaving any dangling pointers */ - yyscanner = NULL; scanorig = NULL; } diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index 50c3b28472b..dab4e16c72e 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -1315,26 +1315,26 @@ extern void plpgsql_dumptree(PLpgSQL_function *func); /* * Scanner functions in pl_scanner.c */ -extern int plpgsql_base_yylex(void); -extern int plpgsql_yylex(void); +typedef void *yyscan_t; +extern int plpgsql_yylex(yyscan_t yyscanner); extern int plpgsql_token_length(void); extern void plpgsql_push_back_token(int token); extern bool plpgsql_token_is_unreserved_keyword(int token); extern void plpgsql_append_source_text(StringInfo buf, int startlocation, int endlocation); -extern int plpgsql_peek(void); +extern int plpgsql_peek(yyscan_t yyscanner); extern void plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, - int *tok2_loc); + int *tok2_loc, yyscan_t yyscanner); extern int plpgsql_scanner_errposition(int location); -extern void plpgsql_yyerror(const char *message) pg_attribute_noreturn(); +extern void plpgsql_yyerror(yyscan_t yyscanner, const char *message) pg_attribute_noreturn(); extern int plpgsql_location_to_lineno(int location); extern int plpgsql_latest_lineno(void); -extern void plpgsql_scanner_init(const char *str); -extern void plpgsql_scanner_finish(void); +extern yyscan_t plpgsql_scanner_init(const char *str); +extern void plpgsql_scanner_finish(yyscan_t yyscanner); /* * Externs in gram.y */ -extern int plpgsql_yyparse(void); +extern int plpgsql_yyparse(yyscan_t yyscanner); #endif /* PLPGSQL_H */ -- 2.47.1