From 4c3e4f0da9a2fa1f646da9362b39974e7e44117e Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Thu, 26 Dec 2024 17:01:39 +0100 Subject: [PATCH v3 4/4] plpgsql: yyextra --- src/pl/plpgsql/src/pl_comp.c | 33 +++-- src/pl/plpgsql/src/pl_gram.y | 234 ++++++++++++++++---------------- src/pl/plpgsql/src/pl_scanner.c | 189 ++++++++++++++------------ src/pl/plpgsql/src/plpgsql.h | 13 +- 4 files changed, 250 insertions(+), 219 deletions(-) diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 57685c4e948..f443423b98c 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -237,6 +237,12 @@ plpgsql_compile(FunctionCallInfo fcinfo, bool forValidator) return function; } +struct compile_error_callback_arg +{ + const char *proc_source; + yyscan_t yyscanner; +}; + /* * This is the slow part of plpgsql_compile(). * @@ -277,6 +283,7 @@ do_compile(FunctionCallInfo fcinfo, PLpgSQL_variable *var; PLpgSQL_rec *rec; int i; + struct compile_error_callback_arg cbarg; ErrorContextCallback plerrcontext; int parse_rc; Oid rettypeid; @@ -291,9 +298,7 @@ do_compile(FunctionCallInfo fcinfo, MemoryContext func_cxt; /* - * 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. + * Setup the scanner input and error info. */ prosrcdatum = SysCacheGetAttrNotNull(PROCOID, procTup, Anum_pg_proc_prosrc); proc_source = TextDatumGetCString(prosrcdatum); @@ -304,8 +309,10 @@ do_compile(FunctionCallInfo fcinfo, /* * Setup error traceback support for ereport() */ + cbarg.proc_source = forValidator ? proc_source : NULL; + cbarg.yyscanner = scanner; plerrcontext.callback = plpgsql_compile_error_callback; - plerrcontext.arg = forValidator ? proc_source : NULL; + plerrcontext.arg = &cbarg; plerrcontext.previous = error_context_stack; error_context_stack = &plerrcontext; @@ -845,15 +852,14 @@ plpgsql_compile_inline(char *proc_source) yyscan_t scanner; char *func_name = "inline_code_block"; PLpgSQL_function *function; + struct compile_error_callback_arg cbarg; ErrorContextCallback plerrcontext; PLpgSQL_variable *var; int parse_rc; MemoryContext func_cxt; /* - * 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. + * Setup the scanner input and error info. */ scanner = plpgsql_scanner_init(proc_source); @@ -862,8 +868,10 @@ plpgsql_compile_inline(char *proc_source) /* * Setup error traceback support for ereport() */ + cbarg.proc_source = proc_source; + cbarg.yyscanner = scanner; plerrcontext.callback = plpgsql_compile_error_callback; - plerrcontext.arg = proc_source; + plerrcontext.arg = &cbarg; plerrcontext.previous = error_context_stack; error_context_stack = &plerrcontext; @@ -980,13 +988,16 @@ plpgsql_compile_inline(char *proc_source) static void plpgsql_compile_error_callback(void *arg) { - if (arg) + struct compile_error_callback_arg *cbarg = (struct compile_error_callback_arg *) arg; + yyscan_t yyscanner = cbarg->yyscanner; + + if (cbarg->proc_source) { /* * Try to convert syntax error position to reference text of original * CREATE FUNCTION or DO command. */ - if (function_parse_error_transpose((const char *) arg)) + if (function_parse_error_transpose(cbarg->proc_source)) return; /* @@ -997,7 +1008,7 @@ plpgsql_compile_error_callback(void *arg) if (plpgsql_error_funcname) errcontext("compilation of PL/pgSQL function \"%s\" near line %d", - plpgsql_error_funcname, plpgsql_latest_lineno()); + plpgsql_error_funcname, plpgsql_latest_lineno(yyscanner)); } diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index cb5c2dca186..5f712198e5c 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -49,16 +49,17 @@ typedef struct { int location; + yyscan_t yyscanner; } sql_error_callback_arg; -#define parser_errposition(pos) plpgsql_scanner_errposition(pos) +#define parser_errposition(pos) plpgsql_scanner_errposition(pos, yyscanner) union YYSTYPE; /* need forward reference for tok_is_keyword */ 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 word_is_not_variable(PLword *word, int location, yyscan_t yyscanner); +static void cword_is_not_variable(PLcword *cword, int location, 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, @@ -87,9 +88,9 @@ static PLpgSQL_stmt *make_return_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *y 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); + List *case_when_list, List *else_stmts, yyscan_t yyscanner); static char *NameOfDatum(PLwdatum *wdatum); -static void check_assignable(PLpgSQL_datum *datum, int location); +static void check_assignable(PLpgSQL_datum *datum, int location, 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, @@ -99,14 +100,15 @@ static PLpgSQL_row *read_into_scalar_list(char *initial_name, yyscan_t yyscanner); static PLpgSQL_row *make_scalar_list1(char *initial_name, PLpgSQL_datum *initial_datum, - int lineno, int location); + int lineno, int location, yyscan_t yyscanner); static void check_sql_expr(const char *stmt, - RawParseMode parseMode, int location); + RawParseMode parseMode, int location, yyscan_t yyscanner); static void plpgsql_sql_error_callback(void *arg); 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); + int end_location, + 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); @@ -421,7 +423,7 @@ pl_block : decl_sect K_BEGIN proc_sect exception_sect K_END opt_label new = palloc0(sizeof(PLpgSQL_stmt_block)); new->cmd_type = PLPGSQL_STMT_BLOCK; - new->lineno = plpgsql_location_to_lineno(@2); + new->lineno = plpgsql_location_to_lineno(@2, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; new->label = $1.label; new->n_initvars = $1.n_initvars; @@ -429,7 +431,7 @@ pl_block : decl_sect K_BEGIN proc_sect exception_sect K_END opt_label new->body = $3; new->exceptions = $4; - check_labels($1.label, $6, @6); + check_labels($1.label, $6, @6, yyscanner); plpgsql_ns_pop(); $$ = (PLpgSQL_stmt *) new; @@ -597,7 +599,7 @@ decl_cursor_args : new = palloc0(sizeof(PLpgSQL_row)); new->dtype = PLPGSQL_DTYPE_ROW; new->refname = "(unnamed row)"; - new->lineno = plpgsql_location_to_lineno(@1); + new->lineno = plpgsql_location_to_lineno(@1, yyscanner); new->rowtupdesc = NULL; new->nfields = list_length($2); new->fieldnames = palloc(new->nfields * sizeof(char *)); @@ -701,7 +703,7 @@ decl_aliasitem : T_WORD decl_varname : T_WORD { $$.name = $1.ident; - $$.lineno = plpgsql_location_to_lineno(@1); + $$.lineno = plpgsql_location_to_lineno(@1, yyscanner); /* * Check to make sure name isn't already declared * in the current block. @@ -729,7 +731,7 @@ decl_varname : T_WORD | unreserved_keyword { $$.name = pstrdup($1); - $$.lineno = plpgsql_location_to_lineno(@1); + $$.lineno = plpgsql_location_to_lineno(@1, yyscanner); /* * Check to make sure name isn't already declared * in the current block. @@ -888,9 +890,9 @@ stmt_perform : K_PERFORM new = palloc0(sizeof(PLpgSQL_stmt_perform)); new->cmd_type = PLPGSQL_STMT_PERFORM; - new->lineno = plpgsql_location_to_lineno(@1); + new->lineno = plpgsql_location_to_lineno(@1, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; - plpgsql_push_back_token(K_PERFORM, &yylval, &yylloc); + plpgsql_push_back_token(K_PERFORM, &yylval, &yylloc, yyscanner); /* * Since PERFORM isn't legal SQL, we have to cheat to @@ -912,7 +914,7 @@ stmt_perform : K_PERFORM strlen(new->expr->query)); /* offset syntax error position to account for that */ check_sql_expr(new->expr->query, new->expr->parseMode, - startloc + 1); + startloc + 1, yyscanner); $$ = (PLpgSQL_stmt *) new; } @@ -924,9 +926,9 @@ stmt_call : K_CALL new = palloc0(sizeof(PLpgSQL_stmt_call)); new->cmd_type = PLPGSQL_STMT_CALL; - new->lineno = plpgsql_location_to_lineno(@1); + new->lineno = plpgsql_location_to_lineno(@1, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; - plpgsql_push_back_token(K_CALL, &yylval, &yylloc); + plpgsql_push_back_token(K_CALL, &yylval, &yylloc, yyscanner); new->expr = read_sql_stmt(&yylval, &yylloc, yyscanner); new->is_call = true; @@ -943,9 +945,9 @@ stmt_call : K_CALL new = palloc0(sizeof(PLpgSQL_stmt_call)); new->cmd_type = PLPGSQL_STMT_CALL; - new->lineno = plpgsql_location_to_lineno(@1); + new->lineno = plpgsql_location_to_lineno(@1, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; - plpgsql_push_back_token(K_DO, &yylval, &yylloc); + plpgsql_push_back_token(K_DO, &yylval, &yylloc, yyscanner); new->expr = read_sql_stmt(&yylval, &yylloc, yyscanner); new->is_call = false; @@ -979,14 +981,14 @@ stmt_assign : T_DATUM pmode = 0; /* keep compiler quiet */ } - check_assignable($1.datum, @1); + check_assignable($1.datum, @1, yyscanner); new = palloc0(sizeof(PLpgSQL_stmt_assign)); new->cmd_type = PLPGSQL_STMT_ASSIGN; - new->lineno = plpgsql_location_to_lineno(@1); + new->lineno = plpgsql_location_to_lineno(@1, yyscanner); 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, &yylval, &yylloc); + plpgsql_push_back_token(T_DATUM, &yylval, &yylloc, yyscanner); new->expr = read_sql_construct(';', 0, 0, ";", pmode, false, true, @@ -1004,7 +1006,7 @@ stmt_getdiag : K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';' new = palloc0(sizeof(PLpgSQL_stmt_getdiag)); new->cmd_type = PLPGSQL_STMT_GETDIAG; - new->lineno = plpgsql_location_to_lineno(@1); + new->lineno = plpgsql_location_to_lineno(@1, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; new->is_stacked = $2; new->diag_items = $4; @@ -1159,18 +1161,18 @@ getdiag_target : T_DATUM errmsg("\"%s\" is not a scalar variable", NameOfDatum(&($1))), parser_errposition(@1))); - check_assignable($1.datum, @1); + check_assignable($1.datum, @1, yyscanner); $$ = $1.datum; } | T_WORD { /* just to give a better message than "syntax error" */ - word_is_not_variable(&($1), @1); + word_is_not_variable(&($1), @1, yyscanner); } | T_CWORD { /* just to give a better message than "syntax error" */ - cword_is_not_variable(&($1), @1); + cword_is_not_variable(&($1), @1, yyscanner); } ; @@ -1180,7 +1182,7 @@ stmt_if : K_IF expr_until_then proc_sect stmt_elsifs stmt_else K_END K_IF ';' new = palloc0(sizeof(PLpgSQL_stmt_if)); new->cmd_type = PLPGSQL_STMT_IF; - new->lineno = plpgsql_location_to_lineno(@1); + new->lineno = plpgsql_location_to_lineno(@1, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; new->cond = $2; new->then_body = $3; @@ -1200,7 +1202,7 @@ stmt_elsifs : PLpgSQL_if_elsif *new; new = palloc0(sizeof(PLpgSQL_if_elsif)); - new->lineno = plpgsql_location_to_lineno(@2); + new->lineno = plpgsql_location_to_lineno(@2, yyscanner); new->cond = $3; new->stmts = $4; @@ -1220,7 +1222,7 @@ stmt_else : stmt_case : K_CASE opt_expr_until_when case_when_list opt_case_else K_END K_CASE ';' { - $$ = make_case(@1, $2, $3, $4); + $$ = make_case(@1, $2, $3, $4, yyscanner); } ; @@ -1231,10 +1233,10 @@ opt_expr_until_when : if (tok != K_WHEN) { - plpgsql_push_back_token(tok, &yylval, &yylloc); + plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner); expr = read_sql_expression(K_WHEN, "WHEN", &yylval, &yylloc, yyscanner); } - plpgsql_push_back_token(K_WHEN, &yylval, &yylloc); + plpgsql_push_back_token(K_WHEN, &yylval, &yylloc, yyscanner); $$ = expr; } ; @@ -1253,7 +1255,7 @@ case_when : K_WHEN expr_until_then proc_sect { PLpgSQL_case_when *new = palloc(sizeof(PLpgSQL_case_when)); - new->lineno = plpgsql_location_to_lineno(@1); + new->lineno = plpgsql_location_to_lineno(@1, yyscanner); new->expr = $2; new->stmts = $3; $$ = new; @@ -1285,12 +1287,12 @@ stmt_loop : opt_loop_label K_LOOP loop_body new = palloc0(sizeof(PLpgSQL_stmt_loop)); new->cmd_type = PLPGSQL_STMT_LOOP; - new->lineno = plpgsql_location_to_lineno(@2); + new->lineno = plpgsql_location_to_lineno(@2, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; new->label = $1; new->body = $3.stmts; - check_labels($1, $3.end_label, $3.end_label_location); + check_labels($1, $3.end_label, $3.end_label_location, yyscanner); plpgsql_ns_pop(); $$ = (PLpgSQL_stmt *) new; @@ -1303,13 +1305,13 @@ stmt_while : opt_loop_label K_WHILE expr_until_loop loop_body new = palloc0(sizeof(PLpgSQL_stmt_while)); new->cmd_type = PLPGSQL_STMT_WHILE; - new->lineno = plpgsql_location_to_lineno(@2); + new->lineno = plpgsql_location_to_lineno(@2, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; new->label = $1; new->cond = $3; new->body = $4.stmts; - check_labels($1, $4.end_label, $4.end_label_location); + check_labels($1, $4.end_label, $4.end_label_location, yyscanner); plpgsql_ns_pop(); $$ = (PLpgSQL_stmt *) new; @@ -1324,7 +1326,7 @@ stmt_for : opt_loop_label K_FOR for_control loop_body PLpgSQL_stmt_fori *new; new = (PLpgSQL_stmt_fori *) $3; - new->lineno = plpgsql_location_to_lineno(@2); + new->lineno = plpgsql_location_to_lineno(@2, yyscanner); new->label = $1; new->body = $4.stmts; $$ = (PLpgSQL_stmt *) new; @@ -1338,13 +1340,13 @@ stmt_for : opt_loop_label K_FOR for_control loop_body $3->cmd_type == PLPGSQL_STMT_DYNFORS); /* forq is the common supertype of all three */ new = (PLpgSQL_stmt_forq *) $3; - new->lineno = plpgsql_location_to_lineno(@2); + new->lineno = plpgsql_location_to_lineno(@2, yyscanner); new->label = $1; new->body = $4.stmts; $$ = (PLpgSQL_stmt *) new; } - check_labels($1, $4.end_label, $4.end_label_location); + check_labels($1, $4.end_label, $4.end_label_location, yyscanner); /* close namespace started in opt_loop_label */ plpgsql_ns_pop(); } @@ -1372,14 +1374,14 @@ for_control : for_variable K_IN if ($1.row) { new->var = (PLpgSQL_variable *) $1.row; - check_assignable($1.row, @1); + check_assignable($1.row, @1, yyscanner); } else if ($1.scalar) { /* convert single scalar to list */ new->var = (PLpgSQL_variable *) make_scalar_list1($1.name, $1.scalar, - $1.lineno, @1); + $1.lineno, @1, yyscanner); /* make_scalar_list1 did check_assignable */ } else @@ -1466,7 +1468,7 @@ for_control : for_variable K_IN K_REVERSE, "reverse")) reverse = true; else - plpgsql_push_back_token(tok, &yylval, &yylloc); + plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner); /* * Read tokens until we see either a ".." @@ -1500,7 +1502,7 @@ for_control : for_variable K_IN */ expr1->parseMode = RAW_PARSE_PLPGSQL_EXPR; check_sql_expr(expr1->query, expr1->parseMode, - expr1loc); + expr1loc, yyscanner); /* Read and check the second one */ expr2 = read_sql_expression2(K_LOOP, K_BY, @@ -1557,7 +1559,7 @@ for_control : for_variable K_IN /* Check syntax as a regular query */ check_sql_expr(expr1->query, expr1->parseMode, - expr1loc); + expr1loc, yyscanner); new = palloc0(sizeof(PLpgSQL_stmt_fors)); new->cmd_type = PLPGSQL_STMT_FORS; @@ -1565,14 +1567,14 @@ for_control : for_variable K_IN if ($1.row) { new->var = (PLpgSQL_variable *) $1.row; - check_assignable($1.row, @1); + check_assignable($1.row, @1, yyscanner); } else if ($1.scalar) { /* convert single scalar to list */ new->var = (PLpgSQL_variable *) make_scalar_list1($1.name, $1.scalar, - $1.lineno, @1); + $1.lineno, @1, yyscanner); /* make_scalar_list1 did check_assignable */ } else @@ -1611,7 +1613,7 @@ for_control : for_variable K_IN for_variable : T_DATUM { $$.name = NameOfDatum(&($1)); - $$.lineno = plpgsql_location_to_lineno(@1); + $$.lineno = plpgsql_location_to_lineno(@1, yyscanner); if ($1.datum->dtype == PLPGSQL_DTYPE_ROW || $1.datum->dtype == PLPGSQL_DTYPE_REC) { @@ -1626,7 +1628,7 @@ for_variable : T_DATUM $$.row = NULL; /* check for comma-separated list */ tok = yylex(&yylval, &yylloc, yyscanner); - plpgsql_push_back_token(tok, &yylval, &yylloc); + plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner); if (tok == ',') $$.row = (PLpgSQL_datum *) read_into_scalar_list($$.name, @@ -1641,19 +1643,19 @@ for_variable : T_DATUM int tok; $$.name = $1.ident; - $$.lineno = plpgsql_location_to_lineno(@1); + $$.lineno = plpgsql_location_to_lineno(@1, yyscanner); $$.scalar = NULL; $$.row = NULL; /* check for comma-separated list */ tok = yylex(&yylval, &yylloc, yyscanner); - plpgsql_push_back_token(tok, &yylval, &yylloc); + plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner); if (tok == ',') - word_is_not_variable(&($1), @1); + word_is_not_variable(&($1), @1, yyscanner); } | T_CWORD { /* just to give a better message than "syntax error" */ - cword_is_not_variable(&($1), @1); + cword_is_not_variable(&($1), @1, yyscanner); } ; @@ -1663,7 +1665,7 @@ stmt_foreach_a : opt_loop_label K_FOREACH for_variable foreach_slice K_IN K_ARRA new = palloc0(sizeof(PLpgSQL_stmt_foreach_a)); new->cmd_type = PLPGSQL_STMT_FOREACH_A; - new->lineno = plpgsql_location_to_lineno(@2); + new->lineno = plpgsql_location_to_lineno(@2, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; new->label = $1; new->slice = $4; @@ -1673,12 +1675,12 @@ stmt_foreach_a : opt_loop_label K_FOREACH for_variable foreach_slice K_IN K_ARRA if ($3.row) { new->varno = $3.row->dno; - check_assignable($3.row, @3); + check_assignable($3.row, @3, yyscanner); } else if ($3.scalar) { new->varno = $3.scalar->dno; - check_assignable($3.scalar, @3); + check_assignable($3.scalar, @3, yyscanner); } else { @@ -1688,7 +1690,7 @@ stmt_foreach_a : opt_loop_label K_FOREACH for_variable foreach_slice K_IN K_ARRA parser_errposition(@3))); } - check_labels($1, $8.end_label, $8.end_label_location); + check_labels($1, $8.end_label, $8.end_label_location, yyscanner); plpgsql_ns_pop(); $$ = (PLpgSQL_stmt *) new; @@ -1713,7 +1715,7 @@ stmt_exit : exit_type opt_label opt_exitcond new->cmd_type = PLPGSQL_STMT_EXIT; new->stmtid = ++plpgsql_curr_compile->nstatements; new->is_exit = $1; - new->lineno = plpgsql_location_to_lineno(@1); + new->lineno = plpgsql_location_to_lineno(@1, yyscanner); new->label = $2; new->cond = $3; @@ -1788,7 +1790,7 @@ stmt_return : K_RETURN } else { - plpgsql_push_back_token(tok, &yylval, &yylloc); + plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner); $$ = make_return_stmt(@1, &yylval, &yylloc, yyscanner); } } @@ -1802,7 +1804,7 @@ stmt_raise : K_RAISE new = palloc(sizeof(PLpgSQL_stmt_raise)); new->cmd_type = PLPGSQL_STMT_RAISE; - new->lineno = plpgsql_location_to_lineno(@1); + new->lineno = plpgsql_location_to_lineno(@1, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; new->elog_level = ERROR; /* default */ new->condname = NULL; @@ -1948,7 +1950,7 @@ stmt_assert : K_ASSERT new = palloc(sizeof(PLpgSQL_stmt_assert)); new->cmd_type = PLPGSQL_STMT_ASSERT; - new->lineno = plpgsql_location_to_lineno(@1); + new->lineno = plpgsql_location_to_lineno(@1, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; new->cond = read_sql_expression2(',', ';', @@ -1999,10 +2001,10 @@ stmt_execsql : K_IMPORT int tok; tok = yylex(&yylval, &yylloc, yyscanner); - plpgsql_push_back_token(tok, &yylval, &yylloc); + plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner); if (tok == '=' || tok == COLON_EQUALS || tok == '[' || tok == '.') - word_is_not_variable(&($1), @1); + word_is_not_variable(&($1), @1, yyscanner); $$ = make_execsql_stmt(T_WORD, @1, &($1), &yylval, &yylloc, yyscanner); } | T_CWORD @@ -2010,10 +2012,10 @@ stmt_execsql : K_IMPORT int tok; tok = yylex(&yylval, &yylloc, yyscanner); - plpgsql_push_back_token(tok, &yylval, &yylloc); + plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner); if (tok == '=' || tok == COLON_EQUALS || tok == '[' || tok == '.') - cword_is_not_variable(&($1), @1); + cword_is_not_variable(&($1), @1, yyscanner); $$ = make_execsql_stmt(T_CWORD, @1, NULL, &yylval, &yylloc, yyscanner); } ; @@ -2033,7 +2035,7 @@ stmt_dynexecute : K_EXECUTE new = palloc(sizeof(PLpgSQL_stmt_dynexecute)); new->cmd_type = PLPGSQL_STMT_DYNEXECUTE; - new->lineno = plpgsql_location_to_lineno(@1); + new->lineno = plpgsql_location_to_lineno(@1, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; new->query = expr; new->into = false; @@ -2091,7 +2093,7 @@ stmt_open : K_OPEN cursor_variable new = palloc0(sizeof(PLpgSQL_stmt_open)); new->cmd_type = PLPGSQL_STMT_OPEN; - new->lineno = plpgsql_location_to_lineno(@1); + new->lineno = plpgsql_location_to_lineno(@1, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; new->curvar = $2->dno; new->cursor_options = CURSOR_OPT_FAST_PLAN; @@ -2148,7 +2150,7 @@ stmt_open : K_OPEN cursor_variable } else { - plpgsql_push_back_token(tok, &yylval, &yylloc); + plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner); new->query = read_sql_stmt(&yylval, &yylloc, yyscanner); } } @@ -2183,7 +2185,7 @@ stmt_fetch : K_FETCH opt_fetch_direction cursor_variable K_INTO errmsg("FETCH statement cannot return multiple rows"), parser_errposition(@1))); - fetch->lineno = plpgsql_location_to_lineno(@1); + fetch->lineno = plpgsql_location_to_lineno(@1, yyscanner); fetch->target = target; fetch->curvar = $3->dno; fetch->is_move = false; @@ -2196,7 +2198,7 @@ stmt_move : K_MOVE opt_fetch_direction cursor_variable ';' { PLpgSQL_stmt_fetch *fetch = $2; - fetch->lineno = plpgsql_location_to_lineno(@1); + fetch->lineno = plpgsql_location_to_lineno(@1, yyscanner); fetch->curvar = $3->dno; fetch->is_move = true; @@ -2216,7 +2218,7 @@ stmt_close : K_CLOSE cursor_variable ';' new = palloc(sizeof(PLpgSQL_stmt_close)); new->cmd_type = PLPGSQL_STMT_CLOSE; - new->lineno = plpgsql_location_to_lineno(@1); + new->lineno = plpgsql_location_to_lineno(@1, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; new->curvar = $2->dno; @@ -2237,7 +2239,7 @@ stmt_commit : K_COMMIT opt_transaction_chain ';' new = palloc(sizeof(PLpgSQL_stmt_commit)); new->cmd_type = PLPGSQL_STMT_COMMIT; - new->lineno = plpgsql_location_to_lineno(@1); + new->lineno = plpgsql_location_to_lineno(@1, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; new->chain = $2; @@ -2251,7 +2253,7 @@ stmt_rollback : K_ROLLBACK opt_transaction_chain ';' new = palloc(sizeof(PLpgSQL_stmt_rollback)); new->cmd_type = PLPGSQL_STMT_ROLLBACK; - new->lineno = plpgsql_location_to_lineno(@1); + new->lineno = plpgsql_location_to_lineno(@1, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; new->chain = $2; @@ -2291,12 +2293,12 @@ cursor_variable : T_DATUM | T_WORD { /* just to give a better message than "syntax error" */ - word_is_not_variable(&($1), @1); + word_is_not_variable(&($1), @1, yyscanner); } | T_CWORD { /* just to give a better message than "syntax error" */ - cword_is_not_variable(&($1), @1); + cword_is_not_variable(&($1), @1, yyscanner); } ; @@ -2311,7 +2313,7 @@ exception_sect : * scope of the names extends to the end of the * current block. */ - int lineno = plpgsql_location_to_lineno(@1); + int lineno = plpgsql_location_to_lineno(@1, yyscanner); PLpgSQL_exception_block *new = palloc(sizeof(PLpgSQL_exception_block)); PLpgSQL_variable *var; @@ -2359,7 +2361,7 @@ proc_exception : K_WHEN proc_conditions K_THEN proc_sect PLpgSQL_exception *new; new = palloc0(sizeof(PLpgSQL_exception)); - new->lineno = plpgsql_location_to_lineno(@1); + new->lineno = plpgsql_location_to_lineno(@1, yyscanner); new->conditions = $2; new->action = $4; @@ -2611,7 +2613,7 @@ tok_is_keyword(int token, union YYSTYPE *lval, * ie, unrecognized variable. */ static void -word_is_not_variable(PLword *word, int location) +word_is_not_variable(PLword *word, int location, yyscan_t yyscanner) { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -2622,7 +2624,7 @@ word_is_not_variable(PLword *word, int location) /* Same, for a CWORD */ static void -cword_is_not_variable(PLcword *cword, int location) +cword_is_not_variable(PLcword *cword, int location, yyscan_t yyscanner) { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -2640,9 +2642,9 @@ static void current_token_is_not_variable(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { if (tok == T_WORD) - word_is_not_variable(&(yylvalp->word), *yyllocp); + word_is_not_variable(&(yylvalp->word), *yyllocp, yyscanner); else if (tok == T_CWORD) - cword_is_not_variable(&(yylvalp->cword), *yyllocp); + cword_is_not_variable(&(yylvalp->cword), *yyllocp, yyscanner); else yyerror(yyllocp, yyscanner, "syntax error"); } @@ -2762,7 +2764,7 @@ read_sql_construct(int until, parser_errposition(*yyllocp))); } /* Remember end+1 location of last accepted token */ - endlocation = *yyllocp + plpgsql_token_length(); + endlocation = *yyllocp + plpgsql_token_length(yyscanner); } plpgsql_IdentifierLookup = save_IdentifierLookup; @@ -2788,7 +2790,7 @@ read_sql_construct(int until, * whitespace by hand, but that causes problems if there's a "-- comment" * in front of said whitespace.) */ - plpgsql_append_source_text(&ds, startlocation, endlocation); + plpgsql_append_source_text(&ds, startlocation, endlocation, yyscanner); expr = palloc0(sizeof(PLpgSQL_expr)); expr->query = pstrdup(ds.data); @@ -2800,7 +2802,7 @@ read_sql_construct(int until, pfree(ds.data); if (valid_sql) - check_sql_expr(expr->query, expr->parseMode, startlocation); + check_sql_expr(expr->query, expr->parseMode, startlocation, yyscanner); return expr; } @@ -2910,7 +2912,7 @@ read_datatype(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) yyerror(yyllocp, yyscanner, "syntax error, expected \"]\""); tok = yylex(yylvalp, yyllocp, yyscanner); } - plpgsql_push_back_token(tok, yylvalp, yyllocp); + plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner); if (is_array) result = plpgsql_build_datatype_arrayof(result); @@ -2950,7 +2952,7 @@ read_datatype(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) /* set up ds to contain complete typename text */ initStringInfo(&ds); - plpgsql_append_source_text(&ds, startlocation, *yyllocp); + plpgsql_append_source_text(&ds, startlocation, *yyllocp, yyscanner); type_name = ds.data; if (type_name[0] == '\0') @@ -2960,7 +2962,7 @@ read_datatype(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) pfree(ds.data); - plpgsql_push_back_token(tok, yylvalp, yyllocp); + plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner); return result; } @@ -3107,12 +3109,12 @@ make_execsql_stmt(int firsttoken, int location, PLword *word, YYSTYPE *yylvalp, * text, so that locations within the redacted SQL statement still * line up with those in the original source text. */ - plpgsql_append_source_text(&ds, location, into_start_loc); + plpgsql_append_source_text(&ds, location, into_start_loc, yyscanner); appendStringInfoSpaces(&ds, into_end_loc - into_start_loc); - plpgsql_append_source_text(&ds, into_end_loc, *yyllocp); + plpgsql_append_source_text(&ds, into_end_loc, *yyllocp, yyscanner); } else - plpgsql_append_source_text(&ds, location, *yyllocp); + plpgsql_append_source_text(&ds, location, *yyllocp, yyscanner); /* trim any trailing whitespace, for neatness */ while (ds.len > 0 && scanner_isspace(ds.data[ds.len - 1])) @@ -3127,11 +3129,11 @@ make_execsql_stmt(int firsttoken, int location, PLword *word, YYSTYPE *yylvalp, expr->ns = plpgsql_ns_top(); pfree(ds.data); - check_sql_expr(expr->query, expr->parseMode, location); + check_sql_expr(expr->query, expr->parseMode, location, yyscanner); execsql = palloc0(sizeof(PLpgSQL_stmt_execsql)); execsql->cmd_type = PLPGSQL_STMT_EXECSQL; - execsql->lineno = plpgsql_location_to_lineno(location); + execsql->lineno = plpgsql_location_to_lineno(location, yyscanner); execsql->stmtid = ++plpgsql_curr_compile->nstatements; execsql->sqlstmt = expr; execsql->into = have_into; @@ -3233,7 +3235,7 @@ read_fetch_direction(YYSTYPE *yylvalp, YYLTYPE *yyllocp, 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, yylvalp, yyllocp); + plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner); check_FROM = false; } else @@ -3246,7 +3248,7 @@ read_fetch_direction(YYSTYPE *yylvalp, YYLTYPE *yyllocp, 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, yylvalp, yyllocp); + plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner); fetch->expr = read_sql_expression2(K_FROM, K_IN, "FROM or IN", NULL, yylvalp, yyllocp, yyscanner); @@ -3294,7 +3296,7 @@ complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM, YYSTYPE *yylvalp return; } - plpgsql_push_back_token(tok, yylvalp, yyllocp); + plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner); fetch->expr = read_sql_expression2(K_FROM, K_IN, "FROM or IN", NULL, yylvalp, yyllocp, yyscanner); @@ -3310,7 +3312,7 @@ make_return_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yysc new = palloc0(sizeof(PLpgSQL_stmt_return)); new->cmd_type = PLPGSQL_STMT_RETURN; - new->lineno = plpgsql_location_to_lineno(location); + new->lineno = plpgsql_location_to_lineno(location, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; new->expr = NULL; new->retvarno = -1; @@ -3376,7 +3378,7 @@ make_return_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yysc * Note that a well-formed expression is _required_ here; anything * else is a compile-time error. */ - plpgsql_push_back_token(tok, yylvalp, yyllocp); + plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner); new->expr = read_sql_expression(';', ";", yylvalp, yyllocp, yyscanner); } } @@ -3398,7 +3400,7 @@ make_return_next_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t new = palloc0(sizeof(PLpgSQL_stmt_return_next)); new->cmd_type = PLPGSQL_STMT_RETURN_NEXT; - new->lineno = plpgsql_location_to_lineno(location); + new->lineno = plpgsql_location_to_lineno(location, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; new->expr = NULL; new->retvarno = -1; @@ -3439,7 +3441,7 @@ make_return_next_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t * Note that a well-formed expression is _required_ here; anything * else is a compile-time error. */ - plpgsql_push_back_token(tok, yylvalp, yyllocp); + plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner); new->expr = read_sql_expression(';', ";", yylvalp, yyllocp, yyscanner); } } @@ -3462,14 +3464,14 @@ make_return_query_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_ new = palloc0(sizeof(PLpgSQL_stmt_return_query)); new->cmd_type = PLPGSQL_STMT_RETURN_QUERY; - new->lineno = plpgsql_location_to_lineno(location); + new->lineno = plpgsql_location_to_lineno(location, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; /* check for RETURN QUERY EXECUTE */ if ((tok = yylex(yylvalp, yyllocp, yyscanner)) != K_EXECUTE) { /* ordinary static query */ - plpgsql_push_back_token(tok, yylvalp, yyllocp); + plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner); new->query = read_sql_stmt(yylvalp, yyllocp, yyscanner); } else @@ -3506,7 +3508,7 @@ NameOfDatum(PLwdatum *wdatum) } static void -check_assignable(PLpgSQL_datum *datum, int location) +check_assignable(PLpgSQL_datum *datum, int location, yyscan_t yyscanner) { switch (datum->dtype) { @@ -3526,7 +3528,7 @@ check_assignable(PLpgSQL_datum *datum, int location) case PLPGSQL_DTYPE_RECFIELD: /* assignable if parent record is */ check_assignable(plpgsql_Datums[((PLpgSQL_recfield *) datum)->recparentno], - location); + location, yyscanner); break; default: elog(ERROR, "unrecognized dtype: %d", datum->dtype); @@ -3568,7 +3570,7 @@ read_into_target(PLpgSQL_variable **target, bool *strict, YYSTYPE *yylvalp, YYLT if (yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_ROW || yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_REC) { - check_assignable(yylvalp->wdatum.datum, *yyllocp); + check_assignable(yylvalp->wdatum.datum, *yyllocp, yyscanner); *target = (PLpgSQL_variable *) yylvalp->wdatum.datum; if ((tok = yylex(yylvalp, yyllocp, yyscanner)) == ',') @@ -3576,7 +3578,7 @@ read_into_target(PLpgSQL_variable **target, bool *strict, YYSTYPE *yylvalp, YYLT (errcode(ERRCODE_SYNTAX_ERROR), errmsg("record variable cannot be part of multiple-item INTO list"), parser_errposition(*yyllocp))); - plpgsql_push_back_token(tok, yylvalp, yyllocp); + plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner); } else { @@ -3611,7 +3613,7 @@ read_into_scalar_list(char *initial_name, PLpgSQL_row *row; int tok; - check_assignable(initial_datum, initial_location); + check_assignable(initial_datum, initial_location, yyscanner); fieldnames[0] = initial_name; varnos[0] = initial_datum->dno; nfields = 1; @@ -3629,7 +3631,7 @@ read_into_scalar_list(char *initial_name, switch (tok) { case T_DATUM: - check_assignable(yylvalp->wdatum.datum, *yyllocp); + check_assignable(yylvalp->wdatum.datum, *yyllocp, yyscanner); if (yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_ROW || yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_REC) ereport(ERROR, @@ -3651,12 +3653,12 @@ 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, yylvalp, yyllocp); + plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner); row = palloc0(sizeof(PLpgSQL_row)); row->dtype = PLPGSQL_DTYPE_ROW; row->refname = "(unnamed row)"; - row->lineno = plpgsql_location_to_lineno(initial_location); + row->lineno = plpgsql_location_to_lineno(initial_location, yyscanner); row->rowtupdesc = NULL; row->nfields = nfields; row->fieldnames = palloc(sizeof(char *) * nfields); @@ -3682,11 +3684,11 @@ read_into_scalar_list(char *initial_name, static PLpgSQL_row * make_scalar_list1(char *initial_name, PLpgSQL_datum *initial_datum, - int lineno, int location) + int lineno, int location, yyscan_t yyscanner) { PLpgSQL_row *row; - check_assignable(initial_datum, location); + check_assignable(initial_datum, location, yyscanner); row = palloc0(sizeof(PLpgSQL_row)); row->dtype = PLPGSQL_DTYPE_ROW; @@ -3727,7 +3729,7 @@ make_scalar_list1(char *initial_name, * If no error cursor is provided, we'll just point at "location". */ static void -check_sql_expr(const char *stmt, RawParseMode parseMode, int location) +check_sql_expr(const char *stmt, RawParseMode parseMode, int location, yyscan_t yyscanner) { sql_error_callback_arg cbarg; ErrorContextCallback syntax_errcontext; @@ -3737,6 +3739,7 @@ check_sql_expr(const char *stmt, RawParseMode parseMode, int location) return; cbarg.location = location; + cbarg.yyscanner = yyscanner; syntax_errcontext.callback = plpgsql_sql_error_callback; syntax_errcontext.arg = &cbarg; @@ -3755,6 +3758,7 @@ static void plpgsql_sql_error_callback(void *arg) { sql_error_callback_arg *cbarg = (sql_error_callback_arg *) arg; + yyscan_t yyscanner = cbarg->yyscanner; int errpos; /* @@ -3823,7 +3827,7 @@ parse_datatype(const char *string, int location) * Check block starting and ending labels match. */ static void -check_labels(const char *start_label, const char *end_label, int end_location) +check_labels(const char *start_label, const char *end_label, int end_location, yyscan_t yyscanner) { if (end_label) { @@ -4119,13 +4123,13 @@ check_raise_parameters(PLpgSQL_stmt_raise *stmt) */ static PLpgSQL_stmt * make_case(int location, PLpgSQL_expr *t_expr, - List *case_when_list, List *else_stmts) + List *case_when_list, List *else_stmts, yyscan_t yyscanner) { PLpgSQL_stmt_case *new; new = palloc(sizeof(PLpgSQL_stmt_case)); new->cmd_type = PLPGSQL_STMT_CASE; - new->lineno = plpgsql_location_to_lineno(location); + new->lineno = plpgsql_location_to_lineno(location, yyscanner); new->stmtid = ++plpgsql_curr_compile->nstatements; new->t_expr = t_expr; new->t_varno = 0; diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c index abf2d40c07a..e3cff48b322 100644 --- a/src/pl/plpgsql/src/pl_scanner.c +++ b/src/pl/plpgsql/src/pl_scanner.c @@ -95,41 +95,56 @@ typedef struct int leng; /* length in bytes */ } TokenAuxData; +#define MAX_PUSHBACKS 4 + /* - * Scanner working state. At some point we might wish to fold all this - * into a YY_EXTRA struct. For the moment, there is no need for plpgsql's - * lexer to be re-entrant, and the notational burden of passing a yyscanner - * pointer around is great enough to not want to do it without need. + * Scanner working state. */ +struct plpgsql_yy_extra_type +{ + /* The stuff the core lexer needs */ + core_yy_extra_type core_yy_extra; -/* The stuff the core lexer needs */ -static core_yy_extra_type core_yy_extra; - -/* The original input string */ -static const char *scanorig; - -/* Current token's length (corresponds to plpgsql_yylval and plpgsql_yylloc) */ -static int plpgsql_yyleng; + /* The original input string */ + const char *scanorig; -/* Current token's code (corresponds to plpgsql_yylval and plpgsql_yylloc) */ -static int plpgsql_yytoken; + /* + * Current token's length (corresponds to plpgsql_yylval and + * plpgsql_yylloc) + */ + int plpgsql_yyleng; -/* Token pushback stack */ -#define MAX_PUSHBACKS 4 + /* Current token's code (corresponds to plpgsql_yylval and plpgsql_yylloc) */ + int plpgsql_yytoken; -static int num_pushbacks; -static int pushback_token[MAX_PUSHBACKS]; -static TokenAuxData pushback_auxdata[MAX_PUSHBACKS]; + /* Token pushback stack */ + int num_pushbacks; + int pushback_token[MAX_PUSHBACKS]; + TokenAuxData pushback_auxdata[MAX_PUSHBACKS]; -/* State for plpgsql_location_to_lineno() */ -static const char *cur_line_start; -static const char *cur_line_end; -static int cur_line_num; + /* State for plpgsql_location_to_lineno() */ + const char *cur_line_start; + const char *cur_line_end; + int cur_line_num; +}; /* Internal functions */ static int internal_yylex(TokenAuxData *auxdata, yyscan_t yyscanner); -static void push_back_token(int token, TokenAuxData *auxdata); -static void location_lineno_init(void); +static void push_back_token(int token, TokenAuxData *auxdata, yyscan_t yyscanner); +static void location_lineno_init(yyscan_t yyscanner); + +/* + * This is normally provided by the generated flex code, but we don't have + * that here, so we make a minimal version ourselves. + */ +struct yyguts_t +{ + struct plpgsql_yy_extra_type *yyextra_r; +}; + +/* see scan.l */ +#undef yyextra +#define yyextra (((struct yyguts_t *) yyscanner)->yyextra_r) /* @@ -189,8 +204,8 @@ plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) else { /* not A.B.C, so just process A.B */ - push_back_token(tok5, &aux5); - push_back_token(tok4, &aux4); + push_back_token(tok5, &aux5, yyscanner); + push_back_token(tok4, &aux4, yyscanner); if (plpgsql_parse_dblword(aux1.lval.str, aux3.lval.str, &aux1.lval.wdatum, @@ -205,7 +220,7 @@ plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) else { /* not A.B.C, so just process A.B */ - push_back_token(tok4, &aux4); + push_back_token(tok4, &aux4, yyscanner); if (plpgsql_parse_dblword(aux1.lval.str, aux3.lval.str, &aux1.lval.wdatum, @@ -220,10 +235,10 @@ plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) else { /* not A.B, so just process A */ - push_back_token(tok3, &aux3); - push_back_token(tok2, &aux2); + push_back_token(tok3, &aux3, yyscanner); + push_back_token(tok2, &aux2, yyscanner); if (plpgsql_parse_word(aux1.lval.str, - core_yy_extra.scanbuf + aux1.lloc, + yyextra->core_yy_extra.scanbuf + aux1.lloc, true, &aux1.lval.wdatum, &aux1.lval.word)) @@ -243,7 +258,7 @@ plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) else { /* not A.B, so just process A */ - push_back_token(tok2, &aux2); + push_back_token(tok2, &aux2, yyscanner); /* * See if it matches a variable name, except in the context where @@ -263,8 +278,8 @@ plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) * non-variable cases. */ if (plpgsql_parse_word(aux1.lval.str, - core_yy_extra.scanbuf + aux1.lloc, - (!AT_STMT_START(plpgsql_yytoken) || + yyextra->core_yy_extra.scanbuf + aux1.lloc, + (!AT_STMT_START(yyextra->plpgsql_yytoken) || (tok2 == '=' || tok2 == COLON_EQUALS || tok2 == '[')), &aux1.lval.wdatum, @@ -298,8 +313,8 @@ plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) *yylvalp = aux1.lval; *yyllocp = aux1.lloc; - plpgsql_yyleng = aux1.leng; - plpgsql_yytoken = tok1; + yyextra->plpgsql_yyleng = aux1.leng; + yyextra->plpgsql_yytoken = tok1; return tok1; } @@ -309,9 +324,9 @@ plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) * In the case of compound tokens, the length includes all the parts. */ int -plpgsql_token_length(void) +plpgsql_token_length(yyscan_t yyscanner) { - return plpgsql_yyleng; + return yyextra->plpgsql_yyleng; } /* @@ -326,11 +341,11 @@ internal_yylex(TokenAuxData *auxdata, yyscan_t yyscanner) int token; const char *yytext; - if (num_pushbacks > 0) + if (yyextra->num_pushbacks > 0) { - num_pushbacks--; - token = pushback_token[num_pushbacks]; - *auxdata = pushback_auxdata[num_pushbacks]; + yyextra->num_pushbacks--; + token = yyextra->pushback_token[yyextra->num_pushbacks]; + *auxdata = yyextra->pushback_auxdata[yyextra->num_pushbacks]; } else { @@ -339,7 +354,7 @@ internal_yylex(TokenAuxData *auxdata, yyscan_t yyscanner) yyscanner); /* remember the length of yytext before it gets changed */ - yytext = core_yy_extra.scanbuf + auxdata->lloc; + yytext = yyextra->core_yy_extra.scanbuf + auxdata->lloc; auxdata->leng = strlen(yytext); /* Check for << >> and #, which the core considers operators */ @@ -367,13 +382,13 @@ internal_yylex(TokenAuxData *auxdata, yyscan_t yyscanner) * Push back a token to be re-read by next internal_yylex() call. */ static void -push_back_token(int token, TokenAuxData *auxdata) +push_back_token(int token, TokenAuxData *auxdata, yyscan_t yyscanner) { - if (num_pushbacks >= MAX_PUSHBACKS) + if (yyextra->num_pushbacks >= MAX_PUSHBACKS) elog(ERROR, "too many tokens pushed back"); - pushback_token[num_pushbacks] = token; - pushback_auxdata[num_pushbacks] = *auxdata; - num_pushbacks++; + yyextra->pushback_token[yyextra->num_pushbacks] = token; + yyextra->pushback_auxdata[yyextra->num_pushbacks] = *auxdata; + yyextra->num_pushbacks++; } /* @@ -383,14 +398,14 @@ 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, YYSTYPE *yylvalp, YYLTYPE *yyllocp) +plpgsql_push_back_token(int token, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { TokenAuxData auxdata; auxdata.lval = *yylvalp; auxdata.lloc = *yyllocp; - auxdata.leng = plpgsql_yyleng; - push_back_token(token, &auxdata); + auxdata.leng = yyextra->plpgsql_yyleng; + push_back_token(token, &auxdata, yyscanner); } /* @@ -418,10 +433,11 @@ plpgsql_token_is_unreserved_keyword(int token) */ void plpgsql_append_source_text(StringInfo buf, - int startlocation, int endlocation) + int startlocation, int endlocation, + yyscan_t yyscanner) { Assert(startlocation <= endlocation); - appendBinaryStringInfo(buf, scanorig + startlocation, + appendBinaryStringInfo(buf, yyextra->scanorig + startlocation, endlocation - startlocation); } @@ -439,7 +455,7 @@ plpgsql_peek(yyscan_t yyscanner) TokenAuxData aux1; tok1 = internal_yylex(&aux1, yyscanner); - push_back_token(tok1, &aux1); + push_back_token(tok1, &aux1, yyscanner); return tok1; } @@ -469,8 +485,8 @@ plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc, yyscan_t y if (tok2_loc) *tok2_loc = aux2.lloc; - push_back_token(tok2, &aux2); - push_back_token(tok1, &aux1); + push_back_token(tok2, &aux2, yyscanner); + push_back_token(tok1, &aux1, yyscanner); } /* @@ -485,19 +501,19 @@ plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc, yyscan_t y * to still be available. */ int -plpgsql_scanner_errposition(int location) +plpgsql_scanner_errposition(int location, yyscan_t yyscanner) { int pos; - if (location < 0 || scanorig == NULL) + if (location < 0 || yyextra->scanorig == NULL) return 0; /* no-op if location is unknown */ /* Convert byte offset to character number */ - pos = pg_mbstrlen_with_len(scanorig, location) + 1; + pos = pg_mbstrlen_with_len(yyextra->scanorig, location) + 1; /* And pass it to the ereport mechanism */ (void) internalerrposition(pos); /* Also pass the function body string */ - return internalerrquery(scanorig); + return internalerrquery(yyextra->scanorig); } /* @@ -514,7 +530,7 @@ plpgsql_scanner_errposition(int location) void plpgsql_yyerror(YYLTYPE *yyllocp, yyscan_t yyscanner, const char *message) { - char *yytext = core_yy_extra.scanbuf + *yyllocp; + char *yytext = yyextra->core_yy_extra.scanbuf + *yyllocp; if (*yytext == '\0') { @@ -522,7 +538,7 @@ plpgsql_yyerror(YYLTYPE *yyllocp, 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(*yyllocp))); + plpgsql_scanner_errposition(*yyllocp, yyscanner))); } else { @@ -532,13 +548,13 @@ plpgsql_yyerror(YYLTYPE *yyllocp, yyscan_t yyscanner, const char *message) * only the single token here. This modifies scanbuf but we no longer * care about that. */ - yytext[plpgsql_yyleng] = '\0'; + yytext[yyextra->plpgsql_yyleng] = '\0'; ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), /* translator: first %s is typically the translation of "syntax error" */ errmsg("%s at or near \"%s\"", _(message), yytext), - plpgsql_scanner_errposition(*yyllocp))); + plpgsql_scanner_errposition(*yyllocp, yyscanner))); } } @@ -551,43 +567,43 @@ plpgsql_yyerror(YYLTYPE *yyllocp, yyscan_t yyscanner, const char *message) * of the "current" line. */ int -plpgsql_location_to_lineno(int location) +plpgsql_location_to_lineno(int location, yyscan_t yyscanner) { const char *loc; - if (location < 0 || scanorig == NULL) + if (location < 0 || yyextra->scanorig == NULL) return 0; /* garbage in, garbage out */ - loc = scanorig + location; + loc = yyextra->scanorig + location; /* be correct, but not fast, if input location goes backwards */ - if (loc < cur_line_start) - location_lineno_init(); + if (loc < yyextra->cur_line_start) + location_lineno_init(yyscanner); - while (cur_line_end != NULL && loc > cur_line_end) + while (yyextra->cur_line_end != NULL && loc > yyextra->cur_line_end) { - cur_line_start = cur_line_end + 1; - cur_line_num++; - cur_line_end = strchr(cur_line_start, '\n'); + yyextra->cur_line_start = yyextra->cur_line_end + 1; + yyextra->cur_line_num++; + yyextra->cur_line_end = strchr(yyextra->cur_line_start, '\n'); } - return cur_line_num; + return yyextra->cur_line_num; } /* initialize or reset the state for plpgsql_location_to_lineno */ static void -location_lineno_init(void) +location_lineno_init(yyscan_t yyscanner) { - cur_line_start = scanorig; - cur_line_num = 1; + yyextra->cur_line_start = yyextra->scanorig; + yyextra->cur_line_num = 1; - cur_line_end = strchr(cur_line_start, '\n'); + yyextra->cur_line_end = strchr(yyextra->cur_line_start, '\n'); } /* return the most recently computed lineno */ int -plpgsql_latest_lineno(void) +plpgsql_latest_lineno(yyscan_t yyscanner) { - return cur_line_num; + return yyextra->cur_line_num; } @@ -602,9 +618,10 @@ yyscan_t plpgsql_scanner_init(const char *str) { yyscan_t yyscanner; + struct plpgsql_yy_extra_type *yyext = palloc0_object(struct plpgsql_yy_extra_type); /* Start up the core scanner */ - yyscanner = scanner_init(str, &core_yy_extra, + yyscanner = scanner_init(str, (core_yy_extra_type *) yyext, &ReservedPLKeywords, ReservedPLKeywordTokens); /* @@ -613,15 +630,15 @@ plpgsql_scanner_init(const char *str) * yytext points into scanbuf, we rely on being able to apply locations * (offsets from string start) to scanorig as well. */ - scanorig = str; + yyext->scanorig = str; /* Other setup */ plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL; - plpgsql_yytoken = 0; + yyext->plpgsql_yytoken = 0; - num_pushbacks = 0; + yyext->num_pushbacks = 0; - location_lineno_init(); + location_lineno_init(yyscanner); return yyscanner; } @@ -634,6 +651,4 @@ plpgsql_scanner_finish(yyscan_t yyscanner) { /* release storage */ scanner_finish(yyscanner); - /* avoid leaving any dangling pointers */ - scanorig = NULL; } diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index 151ae7943df..2562c816a1b 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -1322,18 +1322,19 @@ union YYSTYPE; typedef void *yyscan_t; #endif 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, union YYSTYPE *yylvalp, YYLTYPE *yyllocp); +extern int plpgsql_token_length(yyscan_t yyscanner); +extern void plpgsql_push_back_token(int token, union YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); extern bool plpgsql_token_is_unreserved_keyword(int token); extern void plpgsql_append_source_text(StringInfo buf, - int startlocation, int endlocation); + int startlocation, int endlocation, + yyscan_t yyscanner); 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 int plpgsql_scanner_errposition(int location, yyscan_t yyscanner); 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 int plpgsql_location_to_lineno(int location, yyscan_t yyscanner); +extern int plpgsql_latest_lineno(yyscan_t yyscanner); extern yyscan_t plpgsql_scanner_init(const char *str); extern void plpgsql_scanner_finish(yyscan_t yyscanner); -- 2.47.1