From: Peter Eisentraut Date: Fri, 24 Jan 2025 05:55:39 +0000 (+0100) Subject: Return yyparse() result not via global variable X-Git-Tag: REL_18_BETA1~1024 X-Git-Url: http://git.postgresql.org/gitweb/?a=commitdiff_plain;h=473a575e05979b4dbb28b3f2544f4ec8f184ce65;p=postgresql.git Return yyparse() result not via global variable Instead of passing the parse result from yyparse() via a global variable, pass it via a function output argument. This complements earlier work to make the parsers reentrant. Discussion: Discussion: https://www.postgresql.org/message-id/flat/eb6faeac-2a8a-4b69-9189-c33c520e5b7b@eisentraut.org --- diff --git a/src/backend/nls.mk b/src/backend/nls.mk index 5a5298b33f7..b7d5dd46e45 100644 --- a/src/backend/nls.mk +++ b/src/backend/nls.mk @@ -9,9 +9,9 @@ GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS) \ yyerror \ jsonpath_yyerror:4 \ parser_yyerror \ - replication_yyerror:2 \ + replication_yyerror:3 \ scanner_yyerror \ - syncrep_yyerror:2 \ + syncrep_yyerror:4 \ report_invalid_record:2 \ ereport_startup_progress \ json_token_error:2 \ diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y index 61e68d0727a..7440aae5a1a 100644 --- a/src/backend/replication/repl_gram.y +++ b/src/backend/replication/repl_gram.y @@ -25,10 +25,6 @@ #include "repl_gram.h" -/* Result of the parsing is returned here */ -Node *replication_parse_result; - - /* * Bison doesn't allocate anything that needs to live across parser calls, * so we can easily have it use palloc instead of malloc. This prevents @@ -39,6 +35,7 @@ Node *replication_parse_result; %} +%parse-param {Node **replication_parse_result_p} %parse-param {yyscan_t yyscanner} %lex-param {yyscan_t yyscanner} %pure-parser @@ -104,7 +101,7 @@ Node *replication_parse_result; firstcmd: command opt_semicolon { - replication_parse_result = $1; + *replication_parse_result_p = $1; (void) yynerrs; /* suppress compiler warning */ } diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l index de10cb5abd1..014ea8d25c6 100644 --- a/src/backend/replication/repl_scanner.l +++ b/src/backend/replication/repl_scanner.l @@ -156,7 +156,7 @@ UPLOAD_MANIFEST { return K_UPLOAD_MANIFEST; } uint32 hi, lo; if (sscanf(yytext, "%X/%X", &hi, &lo) != 2) - replication_yyerror(yyscanner, "invalid streaming start location"); + replication_yyerror(NULL, yyscanner, "invalid streaming start location"); yylval->recptr = ((uint64) hi) << 32 | lo; return RECPTR; } @@ -213,7 +213,7 @@ UPLOAD_MANIFEST { return K_UPLOAD_MANIFEST; } return yytext[0]; } -<> { replication_yyerror(yyscanner, "unterminated quoted string"); } +<> { replication_yyerror(NULL, yyscanner, "unterminated quoted string"); } <> { @@ -252,8 +252,12 @@ addlitchar(unsigned char ychar, yyscan_t yyscanner) appendStringInfoChar(&yyextra->litbuf, ychar); } +/* + * (The first argument is enforced by Bison to match the first argument of + * yyparse(), but it is not used here.) + */ void -replication_yyerror(yyscan_t yyscanner, const char *message) +replication_yyerror(Node **replication_parse_result_p, yyscan_t yyscanner, const char *message) { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c index 1ce8bc7533f..d75e3968035 100644 --- a/src/backend/replication/syncrep.c +++ b/src/backend/replication/syncrep.c @@ -996,13 +996,13 @@ check_synchronous_standby_names(char **newval, void **extra, GucSource source) int parse_rc; SyncRepConfigData *pconf; - /* Reset communication variables to ensure a fresh start */ - syncrep_parse_result = NULL; - syncrep_parse_error_msg = NULL; + /* Result of parsing is returned in one of these two variables */ + SyncRepConfigData *syncrep_parse_result = NULL; + char *syncrep_parse_error_msg = NULL; /* Parse the synchronous_standby_names string */ syncrep_scanner_init(*newval, &scanner); - parse_rc = syncrep_yyparse(scanner); + parse_rc = syncrep_yyparse(&syncrep_parse_result, &syncrep_parse_error_msg, scanner); syncrep_scanner_finish(scanner); if (parse_rc != 0 || syncrep_parse_result == NULL) diff --git a/src/backend/replication/syncrep_gram.y b/src/backend/replication/syncrep_gram.y index 1a3b89ca674..22297bb151a 100644 --- a/src/backend/replication/syncrep_gram.y +++ b/src/backend/replication/syncrep_gram.y @@ -19,10 +19,6 @@ #include "syncrep_gram.h" -/* Result of parsing is returned in one of these two variables */ -SyncRepConfigData *syncrep_parse_result; -char *syncrep_parse_error_msg; - static SyncRepConfigData *create_syncrep_config(const char *num_sync, List *members, uint8 syncrep_method); @@ -36,7 +32,10 @@ static SyncRepConfigData *create_syncrep_config(const char *num_sync, %} +%parse-param {SyncRepConfigData **syncrep_parse_result_p} +%parse-param {char **syncrep_parse_error_msg_p} %parse-param {yyscan_t yyscanner} +%lex-param {char **syncrep_parse_error_msg_p} %lex-param {yyscan_t yyscanner} %pure-parser %expect 0 @@ -60,7 +59,7 @@ static SyncRepConfigData *create_syncrep_config(const char *num_sync, %% result: standby_config { - syncrep_parse_result = $1; + *syncrep_parse_result_p = $1; (void) yynerrs; /* suppress compiler warning */ } ; diff --git a/src/backend/replication/syncrep_scanner.l b/src/backend/replication/syncrep_scanner.l index 05e5fdecf1b..7dec1f869c7 100644 --- a/src/backend/replication/syncrep_scanner.l +++ b/src/backend/replication/syncrep_scanner.l @@ -42,6 +42,13 @@ struct syncrep_yy_extra_type StringInfoData xdbuf; }; +/* + * Better keep this definition here than put it in replication/syncrep.h and + * save a bit of duplication. Putting it in replication/syncrep.h would leak + * the definition to other parts and possibly affect other scanners. +*/ +#define YY_DECL extern int syncrep_yylex(union YYSTYPE *yylval_param, char **syncrep_parse_error_msg_p, yyscan_t yyscanner) + /* LCOV_EXCL_START */ %} @@ -104,7 +111,7 @@ xdinside [^"]+ return NAME; } <> { - syncrep_yyerror(yyscanner, "unterminated quoted identifier"); + syncrep_yyerror(NULL, syncrep_parse_error_msg_p, yyscanner, "unterminated quoted identifier"); return JUNK; } @@ -136,12 +143,21 @@ xdinside [^"]+ #undef yyextra #define yyextra (((struct yyguts_t *) yyscanner)->yyextra_r) -/* Needs to be here for access to yytext */ +/* + * This yyerror() function does not raise an error (elog or similar), it just + * collects the error message in *syncrep_parse_error_msg_p and leaves it to + * the ultimate caller of the syncrep parser to raise the error. (The + * ultimate caller will do that with special GUC error functions.) + * + * (The first argument is enforced by Bison to match the first argument of + * yyparse(), but it is not used here.) + */ void -syncrep_yyerror(yyscan_t yyscanner, const char *message) +syncrep_yyerror(SyncRepConfigData **syncrep_parse_result_p, char **syncrep_parse_error_msg_p, yyscan_t yyscanner, const char *message) { struct yyguts_t *yyg = (struct yyguts_t *) yyscanner; /* needed for yytext * macro */ + char *syncrep_parse_error_msg = *syncrep_parse_error_msg_p; /* report only the first error in a parse operation */ if (syncrep_parse_error_msg) diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index a0782b1bbf6..bac504b554e 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -2017,7 +2017,7 @@ exec_replication_command(const char *cmd_string) /* * Looks like a WalSender command, so parse it. */ - parse_rc = replication_yyparse(scanner); + parse_rc = replication_yyparse(&cmd_node, scanner); if (parse_rc != 0) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -2025,8 +2025,6 @@ exec_replication_command(const char *cmd_string) parse_rc))); replication_scanner_finish(scanner); - cmd_node = replication_parse_result; - /* * Report query to various monitoring facilities. For this purpose, we * report replication commands just like SQL commands. diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y index 9b5ab8074eb..68a37e49e45 100644 --- a/src/bin/pgbench/exprparse.y +++ b/src/bin/pgbench/exprparse.y @@ -21,8 +21,6 @@ #define PGBENCH_NARGS_HASH (-3) #define PGBENCH_NARGS_PERMUTE (-4) -PgBenchExpr *expr_parse_result; - static PgBenchExprList *make_elist(PgBenchExpr *expr, PgBenchExprList *list); static PgBenchExpr *make_null_constant(void); static PgBenchExpr *make_boolean_constant(bool bval); @@ -42,6 +40,7 @@ static PgBenchExpr *make_case(yyscan_t yyscanner, PgBenchExprList *when_then_lis %expect 0 %name-prefix="expr_yy" +%parse-param {PgBenchExpr **expr_parse_result_p} %parse-param {yyscan_t yyscanner} %lex-param {yyscan_t yyscanner} @@ -81,7 +80,7 @@ static PgBenchExpr *make_case(yyscan_t yyscanner, PgBenchExprList *when_then_lis %% result: expr { - expr_parse_result = $1; + *expr_parse_result_p = $1; (void) yynerrs; /* suppress compiler warning */ } diff --git a/src/bin/pgbench/exprscan.l b/src/bin/pgbench/exprscan.l index 46f6ea05121..8943a52e9f0 100644 --- a/src/bin/pgbench/exprscan.l +++ b/src/bin/pgbench/exprscan.l @@ -296,8 +296,12 @@ expr_yyerror_more(yyscan_t yyscanner, const char *message, const char *more) message, more, error_detection_offset - expr_start_offset); } +/* + * (The first argument is enforced by Bison to match the first argument of + * yyparse(), but it is not used here.) + */ void -expr_yyerror(yyscan_t yyscanner, const char *message) +expr_yyerror(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner, const char *message) { expr_yyerror_more(yyscanner, message, NULL); } diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index c415e0f32c1..40592e62606 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -5706,14 +5706,12 @@ process_backslash_command(PsqlScanState sstate, const char *source) yyscanner = expr_scanner_init(sstate, source, lineno, start_offset, my_command->argv[0]); - if (expr_yyparse(yyscanner) != 0) + if (expr_yyparse(&my_command->expr, yyscanner) != 0) { /* dead code: exit done from syntax_error called by yyerror */ exit(1); } - my_command->expr = expr_parse_result; - /* Save line, trimming any trailing newline */ my_command->first_line = expr_scanner_get_substring(sstate, diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h index 4b607b7ee04..f6a883611c5 100644 --- a/src/bin/pgbench/pgbench.h +++ b/src/bin/pgbench/pgbench.h @@ -138,11 +138,9 @@ struct PgBenchExprList PgBenchExprLink *tail; }; -extern PgBenchExpr *expr_parse_result; - -extern int expr_yyparse(yyscan_t yyscanner); +extern int expr_yyparse(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner); extern int expr_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner); -extern void expr_yyerror(yyscan_t yyscanner, const char *message) pg_attribute_noreturn(); +extern void expr_yyerror(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner, const char *message) pg_attribute_noreturn(); extern void expr_yyerror_more(yyscan_t yyscanner, const char *message, const char *more) pg_attribute_noreturn(); extern bool expr_lex_one_word(PsqlScanState state, PQExpBuffer word_buf, diff --git a/src/include/replication/syncrep.h b/src/include/replication/syncrep.h index 33b9cdb18f7..675669a79f7 100644 --- a/src/include/replication/syncrep.h +++ b/src/include/replication/syncrep.h @@ -73,10 +73,6 @@ typedef struct SyncRepConfigData extern PGDLLIMPORT SyncRepConfigData *SyncRepConfig; -/* communication variables for parsing synchronous_standby_names GUC */ -extern PGDLLIMPORT SyncRepConfigData *syncrep_parse_result; -extern PGDLLIMPORT char *syncrep_parse_error_msg; - /* user-settable parameters for synchronous replication */ extern PGDLLIMPORT char *SyncRepStandbyNames; @@ -105,9 +101,9 @@ union YYSTYPE; #define YY_TYPEDEF_YY_SCANNER_T typedef void *yyscan_t; #endif -extern int syncrep_yyparse(yyscan_t yyscanner); -extern int syncrep_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner); -extern void syncrep_yyerror(yyscan_t yyscanner, const char *str); +extern int syncrep_yyparse(SyncRepConfigData **syncrep_parse_result_p, char **syncrep_parse_error_msg_p, yyscan_t yyscanner); +extern int syncrep_yylex(union YYSTYPE *yylval_param, char **syncrep_parse_error_msg_p, yyscan_t yyscanner); +extern void syncrep_yyerror(SyncRepConfigData **syncrep_parse_result_p, char **syncrep_parse_error_msg_p, yyscan_t yyscanner, const char *str); extern void syncrep_scanner_init(const char *str, yyscan_t *yyscannerp); extern void syncrep_scanner_finish(yyscan_t yyscanner); diff --git a/src/include/replication/walsender_private.h b/src/include/replication/walsender_private.h index 5ab96ed5f7d..814b812432a 100644 --- a/src/include/replication/walsender_private.h +++ b/src/include/replication/walsender_private.h @@ -130,13 +130,11 @@ union YYSTYPE; #define YY_TYPEDEF_YY_SCANNER_T typedef void *yyscan_t; #endif -extern int replication_yyparse(yyscan_t yyscanner); +extern int replication_yyparse(Node **replication_parse_result_p, yyscan_t yyscanner); extern int replication_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner); -extern void replication_yyerror(yyscan_t yyscanner, const char *message) pg_attribute_noreturn(); +extern void replication_yyerror(Node **replication_parse_result_p, yyscan_t yyscanner, const char *message) pg_attribute_noreturn(); extern void replication_scanner_init(const char *str, yyscan_t *yyscannerp); extern void replication_scanner_finish(yyscan_t yyscanner); extern bool replication_scanner_is_replication_command(yyscan_t yyscanner); -extern PGDLLIMPORT Node *replication_parse_result; - #endif /* _WALSENDER_PRIVATE_H */ diff --git a/src/pl/plpgsql/src/nls.mk b/src/pl/plpgsql/src/nls.mk index eb06336675c..dd1c1e1440f 100644 --- a/src/pl/plpgsql/src/nls.mk +++ b/src/pl/plpgsql/src/nls.mk @@ -6,5 +6,5 @@ GETTEXT_FILES = pl_comp.c \ pl_funcs.c \ pl_handler.c \ pl_scanner.c -GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS) yyerror:3 plpgsql_yyerror:3 +GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS) yyerror:4 plpgsql_yyerror:4 GETTEXT_FLAGS = $(BACKEND_COMMON_GETTEXT_FLAGS) diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 9dc8218292d..a2de0880fb7 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -38,8 +38,6 @@ * Our own local and global variables * ---------- */ -PLpgSQL_stmt_block *plpgsql_parse_result; - static int datums_alloc; int plpgsql_nDatums; PLpgSQL_datum **plpgsql_Datums; @@ -787,10 +785,9 @@ do_compile(FunctionCallInfo fcinfo, /* * Now parse the function's text */ - parse_rc = plpgsql_yyparse(scanner); + parse_rc = plpgsql_yyparse(&function->action, scanner); if (parse_rc != 0) elog(ERROR, "plpgsql parser returned %d", parse_rc); - function->action = plpgsql_parse_result; plpgsql_scanner_finish(scanner); pfree(proc_source); @@ -945,10 +942,9 @@ plpgsql_compile_inline(char *proc_source) /* * Now parse the function's text */ - parse_rc = plpgsql_yyparse(scanner); + parse_rc = plpgsql_yyparse(&function->action, scanner); if (parse_rc != 0) elog(ERROR, "plpgsql parser returned %d", parse_rc); - function->action = plpgsql_parse_result; plpgsql_scanner_finish(scanner); diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index 063ed81f053..64d2c362bf9 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -116,6 +116,7 @@ static void check_raise_parameters(PLpgSQL_stmt_raise *stmt); %} +%parse-param {PLpgSQL_stmt_block **plpgsql_parse_result_p} %parse-param {yyscan_t yyscanner} %lex-param {yyscan_t yyscanner} %pure-parser @@ -368,7 +369,7 @@ static void check_raise_parameters(PLpgSQL_stmt_raise *stmt); pl_function : comp_options pl_block opt_semi { - plpgsql_parse_result = (PLpgSQL_stmt_block *) $2; + *plpgsql_parse_result_p = (PLpgSQL_stmt_block *) $2; (void) yynerrs; /* suppress compiler warning */ } ; @@ -712,7 +713,7 @@ decl_varname : T_WORD if (plpgsql_ns_lookup(plpgsql_ns_top(), true, $1.ident, NULL, NULL, NULL) != NULL) - yyerror(&yylloc, yyscanner, "duplicate declaration"); + yyerror(&yylloc, NULL, yyscanner, "duplicate declaration"); if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR || plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_SHADOWVAR) @@ -740,7 +741,7 @@ decl_varname : T_WORD if (plpgsql_ns_lookup(plpgsql_ns_top(), true, $1, NULL, NULL, NULL) != NULL) - yyerror(&yylloc, yyscanner, "duplicate declaration"); + yyerror(&yylloc, NULL, yyscanner, "duplicate declaration"); if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR || plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_SHADOWVAR) @@ -1143,7 +1144,7 @@ getdiag_item : K_RETURNED_SQLSTATE, "returned_sqlstate")) $$ = PLPGSQL_GETDIAG_RETURNED_SQLSTATE; else - yyerror(&yylloc, yyscanner, "unrecognized GET DIAGNOSTICS item"); + yyerror(&yylloc, NULL, yyscanner, "unrecognized GET DIAGNOSTICS item"); } ; @@ -1777,7 +1778,7 @@ stmt_return : K_RETURN tok = yylex(&yylval, &yylloc, yyscanner); if (tok == 0) - yyerror(&yylloc, yyscanner, "unexpected end of function definition"); + yyerror(&yylloc, NULL, yyscanner, "unexpected end of function definition"); if (tok_is_keyword(tok, &yylval, K_NEXT, "next")) @@ -1815,7 +1816,7 @@ stmt_raise : K_RAISE tok = yylex(&yylval, &yylloc, yyscanner); if (tok == 0) - yyerror(&yylloc, yyscanner, "unexpected end of function definition"); + yyerror(&yylloc, NULL, yyscanner, "unexpected end of function definition"); /* * We could have just RAISE, meaning to re-throw @@ -1863,7 +1864,7 @@ stmt_raise : K_RAISE tok = yylex(&yylval, &yylloc, yyscanner); } if (tok == 0) - yyerror(&yylloc, yyscanner, "unexpected end of function definition"); + yyerror(&yylloc, NULL, yyscanner, "unexpected end of function definition"); /* * Next we can have a condition name, or @@ -1883,7 +1884,7 @@ stmt_raise : K_RAISE */ tok = yylex(&yylval, &yylloc, yyscanner); if (tok != ',' && tok != ';' && tok != K_USING) - yyerror(&yylloc, yyscanner, "syntax error"); + yyerror(&yylloc, NULL, yyscanner, "syntax error"); while (tok == ',') { @@ -1908,13 +1909,13 @@ stmt_raise : K_RAISE char *sqlstatestr; if (yylex(&yylval, &yylloc, yyscanner) != SCONST) - yyerror(&yylloc, yyscanner, "syntax error"); + yyerror(&yylloc, NULL, yyscanner, "syntax error"); sqlstatestr = yylval.str; if (strlen(sqlstatestr) != 5) - yyerror(&yylloc, yyscanner, "invalid SQLSTATE code"); + yyerror(&yylloc, NULL, yyscanner, "invalid SQLSTATE code"); if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5) - yyerror(&yylloc, yyscanner, "invalid SQLSTATE code"); + yyerror(&yylloc, NULL, yyscanner, "invalid SQLSTATE code"); new->condname = sqlstatestr; } else @@ -1924,13 +1925,13 @@ stmt_raise : K_RAISE else if (plpgsql_token_is_unreserved_keyword(tok)) new->condname = pstrdup(yylval.keyword); else - yyerror(&yylloc, yyscanner, "syntax error"); + yyerror(&yylloc, NULL, yyscanner, "syntax error"); plpgsql_recognize_err_condition(new->condname, false); } tok = yylex(&yylval, &yylloc, yyscanner); if (tok != ';' && tok != K_USING) - yyerror(&yylloc, yyscanner, "syntax error"); + yyerror(&yylloc, NULL, yyscanner, "syntax error"); } if (tok == K_USING) @@ -2056,7 +2057,7 @@ stmt_dynexecute : K_EXECUTE if (endtoken == K_INTO) { if (new->into) /* multiple INTO */ - yyerror(&yylloc, yyscanner, "syntax error"); + yyerror(&yylloc, NULL, yyscanner, "syntax error"); new->into = true; read_into_target(&new->target, &new->strict, &yylval, &yylloc, yyscanner); endtoken = yylex(&yylval, &yylloc, yyscanner); @@ -2064,7 +2065,7 @@ stmt_dynexecute : K_EXECUTE else if (endtoken == K_USING) { if (new->params) /* multiple USING */ - yyerror(&yylloc, yyscanner, "syntax error"); + yyerror(&yylloc, NULL, yyscanner, "syntax error"); do { expr = read_sql_construct(',', ';', K_INTO, @@ -2079,7 +2080,7 @@ stmt_dynexecute : K_EXECUTE else if (endtoken == ';') break; else - yyerror(&yylloc, yyscanner, "syntax error"); + yyerror(&yylloc, NULL, yyscanner, "syntax error"); } $$ = (PLpgSQL_stmt *) new; @@ -2122,7 +2123,7 @@ stmt_open : K_OPEN cursor_variable } if (tok != K_FOR) - yyerror(&yylloc, yyscanner, "syntax error, expected \"FOR\""); + yyerror(&yylloc, NULL, yyscanner, "syntax error, expected \"FOR\""); tok = yylex(&yylval, &yylloc, yyscanner); if (tok == K_EXECUTE) @@ -2174,7 +2175,7 @@ stmt_fetch : K_FETCH opt_fetch_direction cursor_variable K_INTO read_into_target(&target, NULL, &yylval, &yylloc, yyscanner); if (yylex(&yylval, &yylloc, yyscanner) != ';') - yyerror(&yylloc, yyscanner, "syntax error"); + yyerror(&yylloc, NULL, yyscanner, "syntax error"); /* * We don't allow multiple rows in PL/pgSQL's FETCH @@ -2398,13 +2399,13 @@ proc_condition : any_identifier /* next token should be a string literal */ if (yylex(&yylval, &yylloc, yyscanner) != SCONST) - yyerror(&yylloc, yyscanner, "syntax error"); + yyerror(&yylloc, NULL, yyscanner, "syntax error"); sqlstatestr = yylval.str; if (strlen(sqlstatestr) != 5) - yyerror(&yylloc, yyscanner, "invalid SQLSTATE code"); + yyerror(&yylloc, NULL, yyscanner, "invalid SQLSTATE code"); if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5) - yyerror(&yylloc, yyscanner, "invalid SQLSTATE code"); + yyerror(&yylloc, NULL, yyscanner, "invalid SQLSTATE code"); new = palloc(sizeof(PLpgSQL_condition)); new->sqlerrstate = @@ -2488,7 +2489,7 @@ any_identifier : T_WORD | T_DATUM { if ($1.ident == NULL) /* composite name not OK */ - yyerror(&yylloc, yyscanner, "syntax error"); + yyerror(&yylloc, NULL, yyscanner, "syntax error"); $$ = $1.ident; } ; @@ -2647,7 +2648,7 @@ current_token_is_not_variable(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yysca else if (tok == T_CWORD) cword_is_not_variable(&(yylvalp->cword), *yyllocp, yyscanner); else - yyerror(yyllocp, yyscanner, "syntax error"); + yyerror(yyllocp, NULL, yyscanner, "syntax error"); } /* Convenience routine to read an expression with one possible terminator */ @@ -2739,7 +2740,7 @@ read_sql_construct(int until, { parenlevel--; if (parenlevel < 0) - yyerror(yyllocp, yyscanner, "mismatched parentheses"); + yyerror(yyllocp, NULL, yyscanner, "mismatched parentheses"); } /* @@ -2750,7 +2751,7 @@ read_sql_construct(int until, if (tok == 0 || tok == ';') { if (parenlevel != 0) - yyerror(yyllocp, yyscanner, "mismatched parentheses"); + yyerror(yyllocp, NULL, yyscanner, "mismatched parentheses"); if (isexpression) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -2779,9 +2780,9 @@ read_sql_construct(int until, if (startlocation >= endlocation) { if (isexpression) - yyerror(yyllocp, yyscanner, "missing expression"); + yyerror(yyllocp, NULL, yyscanner, "missing expression"); else - yyerror(yyllocp, yyscanner, "missing SQL statement"); + yyerror(yyllocp, NULL, yyscanner, "missing SQL statement"); } /* @@ -2910,7 +2911,7 @@ read_datatype(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) if (tok == ICONST) tok = yylex(yylvalp, yyllocp, yyscanner); if (tok != ']') - yyerror(yyllocp, yyscanner, "syntax error, expected \"]\""); + yyerror(yyllocp, NULL, yyscanner, "syntax error, expected \"]\""); tok = yylex(yylvalp, yyllocp, yyscanner); } plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner); @@ -2932,9 +2933,9 @@ read_datatype(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) if (tok == 0) { if (parenlevel != 0) - yyerror(yyllocp, yyscanner, "mismatched parentheses"); + yyerror(yyllocp, NULL, yyscanner, "mismatched parentheses"); else - yyerror(yyllocp, yyscanner, "incomplete data type declaration"); + yyerror(yyllocp, NULL, yyscanner, "incomplete data type declaration"); } /* Possible followers for datatype in a declaration */ if (tok == K_COLLATE || tok == K_NOT || @@ -2957,7 +2958,7 @@ read_datatype(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) type_name = ds.data; if (type_name[0] == '\0') - yyerror(yyllocp, yyscanner, "missing data type declaration"); + yyerror(yyllocp, NULL, yyscanner, "missing data type declaration"); result = parse_datatype(type_name, startlocation, yyscanner); @@ -3082,7 +3083,7 @@ make_execsql_stmt(int firsttoken, int location, PLword *word, YYSTYPE *yylvalp, if (tok == ';' && paren_depth == 0 && begin_depth == 0) break; if (tok == 0) - yyerror(yyllocp, yyscanner, "unexpected end of function definition"); + yyerror(yyllocp, NULL, yyscanner, "unexpected end of function definition"); if (tok == K_INTO) { if (prev_tok == K_INSERT) @@ -3092,7 +3093,7 @@ make_execsql_stmt(int firsttoken, int location, PLword *word, YYSTYPE *yylvalp, if (firsttoken == K_IMPORT) continue; /* IMPORT ... INTO is not an INTO-target */ if (have_into) - yyerror(yyllocp, yyscanner, "INTO specified more than once"); + yyerror(yyllocp, NULL, yyscanner, "INTO specified more than once"); have_into = true; into_start_loc = *yyllocp; plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL; @@ -3170,7 +3171,7 @@ read_fetch_direction(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) tok = yylex(yylvalp, yyllocp, yyscanner); if (tok == 0) - yyerror(yyllocp, yyscanner, "unexpected end of function definition"); + yyerror(yyllocp, NULL, yyscanner, "unexpected end of function definition"); if (tok_is_keyword(tok, yylvalp, K_NEXT, "next")) @@ -3262,7 +3263,7 @@ read_fetch_direction(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { tok = yylex(yylvalp, yyllocp, yyscanner); if (tok != K_FROM && tok != K_IN) - yyerror(yyllocp, yyscanner, "expected FROM or IN"); + yyerror(yyllocp, NULL, yyscanner, "expected FROM or IN"); } return fetch; @@ -3281,7 +3282,7 @@ complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM, YYSTYPE *yylvalp tok = yylex(yylvalp, yyllocp, yyscanner); if (tok == 0) - yyerror(yyllocp, yyscanner, "unexpected end of function definition"); + yyerror(yyllocp, NULL, yyscanner, "unexpected end of function definition"); if (tok == K_FROM || tok == K_IN) { @@ -3882,7 +3883,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until, YYSTYPE *yylvalp, YYLTYPE *yyll parser_errposition(*yyllocp))); if (tok != until) - yyerror(yyllocp, yyscanner, "syntax error"); + yyerror(yyllocp, NULL, yyscanner, "syntax error"); return NULL; } @@ -3943,7 +3944,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until, YYSTYPE *yylvalp, YYLTYPE *yyll */ tok2 = yylex(yylvalp, yyllocp, yyscanner); if (tok2 != COLON_EQUALS) - yyerror(yyllocp, yyscanner, "syntax error"); + yyerror(yyllocp, NULL, yyscanner, "syntax error"); any_named = true; } @@ -4017,7 +4018,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until, YYSTYPE *yylvalp, YYLTYPE *yyll /* Next we'd better find the until token */ tok = yylex(yylvalp, yyllocp, yyscanner); if (tok != until) - yyerror(yyllocp, yyscanner, "syntax error"); + yyerror(yyllocp, NULL, yyscanner, "syntax error"); return expr; } @@ -4036,7 +4037,7 @@ read_raise_options(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) int tok; if ((tok = yylex(yylvalp, yyllocp, yyscanner)) == 0) - yyerror(yyllocp, yyscanner, "unexpected end of function definition"); + yyerror(yyllocp, NULL, yyscanner, "unexpected end of function definition"); opt = (PLpgSQL_raise_option *) palloc(sizeof(PLpgSQL_raise_option)); @@ -4068,11 +4069,11 @@ read_raise_options(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) K_SCHEMA, "schema")) opt->opt_type = PLPGSQL_RAISEOPTION_SCHEMA; else - yyerror(yyllocp, yyscanner, "unrecognized RAISE statement option"); + yyerror(yyllocp, NULL, yyscanner, "unrecognized RAISE statement option"); tok = yylex(yylvalp, yyllocp, yyscanner); if (tok != '=' && tok != COLON_EQUALS) - yyerror(yyllocp, yyscanner, "syntax error, expected \"=\""); + yyerror(yyllocp, NULL, yyscanner, "syntax error, expected \"=\""); opt->expr = read_sql_expression2(',', ';', ", or ;", &tok, yylvalp, yyllocp, yyscanner); diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c index 11d79a8a683..d08187dafcb 100644 --- a/src/pl/plpgsql/src/pl_scanner.c +++ b/src/pl/plpgsql/src/pl_scanner.c @@ -526,9 +526,12 @@ plpgsql_scanner_errposition(int location, yyscan_t yyscanner) * parsers report error as soon as the first unparsable token is reached. * Beware of using yyerror for other purposes, as the cursor position might * be misleading! + * + * (The second argument is enforced by Bison to match the second argument of + * yyparse(), but it is not used here.) */ void -plpgsql_yyerror(YYLTYPE *yyllocp, yyscan_t yyscanner, const char *message) +plpgsql_yyerror(YYLTYPE *yyllocp, PLpgSQL_stmt_block **plpgsql_parse_result_p, yyscan_t yyscanner, const char *message) { char *yytext = yyextra->core_yy_extra.scanbuf + *yyllocp; diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index c3ce4161a32..441df5354e2 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -1212,8 +1212,6 @@ extern int plpgsql_extra_errors; extern bool plpgsql_check_syntax; extern bool plpgsql_DumpExecTree; -extern PLpgSQL_stmt_block *plpgsql_parse_result; - extern int plpgsql_nDatums; extern PLpgSQL_datum **plpgsql_Datums; @@ -1332,7 +1330,7 @@ extern int plpgsql_peek(yyscan_t yyscanner); extern void plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc, yyscan_t yyscanner); extern int plpgsql_scanner_errposition(int location, yyscan_t yyscanner); -extern void plpgsql_yyerror(YYLTYPE *yyllocp, yyscan_t yyscanner, const char *message) pg_attribute_noreturn(); +extern void plpgsql_yyerror(YYLTYPE *yyllocp, PLpgSQL_stmt_block **plpgsql_parse_result_p, yyscan_t yyscanner, const char *message) pg_attribute_noreturn(); 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); @@ -1341,6 +1339,6 @@ extern void plpgsql_scanner_finish(yyscan_t yyscanner); /* * Externs in pl_gram.y */ -extern int plpgsql_yyparse(yyscan_t yyscanner); +extern int plpgsql_yyparse(PLpgSQL_stmt_block **plpgsql_parse_result_p, yyscan_t yyscanner); #endif /* PLPGSQL_H */