1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

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
This commit is contained in:
Peter Eisentraut
2025-01-24 06:55:39 +01:00
parent 6fc4fc42da
commit 473a575e05
18 changed files with 106 additions and 101 deletions

View File

@ -9,9 +9,9 @@ GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS) \
yyerror \ yyerror \
jsonpath_yyerror:4 \ jsonpath_yyerror:4 \
parser_yyerror \ parser_yyerror \
replication_yyerror:2 \ replication_yyerror:3 \
scanner_yyerror \ scanner_yyerror \
syncrep_yyerror:2 \ syncrep_yyerror:4 \
report_invalid_record:2 \ report_invalid_record:2 \
ereport_startup_progress \ ereport_startup_progress \
json_token_error:2 \ json_token_error:2 \

View File

@ -25,10 +25,6 @@
#include "repl_gram.h" #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, * 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 * 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} %parse-param {yyscan_t yyscanner}
%lex-param {yyscan_t yyscanner} %lex-param {yyscan_t yyscanner}
%pure-parser %pure-parser
@ -104,7 +101,7 @@ Node *replication_parse_result;
firstcmd: command opt_semicolon firstcmd: command opt_semicolon
{ {
replication_parse_result = $1; *replication_parse_result_p = $1;
(void) yynerrs; /* suppress compiler warning */ (void) yynerrs; /* suppress compiler warning */
} }

View File

@ -156,7 +156,7 @@ UPLOAD_MANIFEST { return K_UPLOAD_MANIFEST; }
uint32 hi, uint32 hi,
lo; lo;
if (sscanf(yytext, "%X/%X", &hi, &lo) != 2) 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; yylval->recptr = ((uint64) hi) << 32 | lo;
return RECPTR; return RECPTR;
} }
@ -213,7 +213,7 @@ UPLOAD_MANIFEST { return K_UPLOAD_MANIFEST; }
return yytext[0]; return yytext[0];
} }
<xq,xd><<EOF>> { replication_yyerror(yyscanner, "unterminated quoted string"); } <xq,xd><<EOF>> { replication_yyerror(NULL, yyscanner, "unterminated quoted string"); }
<<EOF>> { <<EOF>> {
@ -252,8 +252,12 @@ addlitchar(unsigned char ychar, yyscan_t yyscanner)
appendStringInfoChar(&yyextra->litbuf, ychar); 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 void
replication_yyerror(yyscan_t yyscanner, const char *message) replication_yyerror(Node **replication_parse_result_p, yyscan_t yyscanner, const char *message)
{ {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),

View File

@ -996,13 +996,13 @@ check_synchronous_standby_names(char **newval, void **extra, GucSource source)
int parse_rc; int parse_rc;
SyncRepConfigData *pconf; SyncRepConfigData *pconf;
/* Reset communication variables to ensure a fresh start */ /* Result of parsing is returned in one of these two variables */
syncrep_parse_result = NULL; SyncRepConfigData *syncrep_parse_result = NULL;
syncrep_parse_error_msg = NULL; char *syncrep_parse_error_msg = NULL;
/* Parse the synchronous_standby_names string */ /* Parse the synchronous_standby_names string */
syncrep_scanner_init(*newval, &scanner); 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); syncrep_scanner_finish(scanner);
if (parse_rc != 0 || syncrep_parse_result == NULL) if (parse_rc != 0 || syncrep_parse_result == NULL)

View File

@ -19,10 +19,6 @@
#include "syncrep_gram.h" #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, static SyncRepConfigData *create_syncrep_config(const char *num_sync,
List *members, uint8 syncrep_method); 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} %parse-param {yyscan_t yyscanner}
%lex-param {char **syncrep_parse_error_msg_p}
%lex-param {yyscan_t yyscanner} %lex-param {yyscan_t yyscanner}
%pure-parser %pure-parser
%expect 0 %expect 0
@ -60,7 +59,7 @@ static SyncRepConfigData *create_syncrep_config(const char *num_sync,
%% %%
result: result:
standby_config { standby_config {
syncrep_parse_result = $1; *syncrep_parse_result_p = $1;
(void) yynerrs; /* suppress compiler warning */ (void) yynerrs; /* suppress compiler warning */
} }
; ;

View File

@ -42,6 +42,13 @@ struct syncrep_yy_extra_type
StringInfoData xdbuf; 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 */ /* LCOV_EXCL_START */
%} %}
@ -104,7 +111,7 @@ xdinside [^"]+
return NAME; return NAME;
} }
<xd><<EOF>> { <xd><<EOF>> {
syncrep_yyerror(yyscanner, "unterminated quoted identifier"); syncrep_yyerror(NULL, syncrep_parse_error_msg_p, yyscanner, "unterminated quoted identifier");
return JUNK; return JUNK;
} }
@ -136,12 +143,21 @@ xdinside [^"]+
#undef yyextra #undef yyextra
#define yyextra (((struct yyguts_t *) yyscanner)->yyextra_r) #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 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 struct yyguts_t *yyg = (struct yyguts_t *) yyscanner; /* needed for yytext
* macro */ * macro */
char *syncrep_parse_error_msg = *syncrep_parse_error_msg_p;
/* report only the first error in a parse operation */ /* report only the first error in a parse operation */
if (syncrep_parse_error_msg) if (syncrep_parse_error_msg)

View File

@ -2017,7 +2017,7 @@ exec_replication_command(const char *cmd_string)
/* /*
* Looks like a WalSender command, so parse it. * Looks like a WalSender command, so parse it.
*/ */
parse_rc = replication_yyparse(scanner); parse_rc = replication_yyparse(&cmd_node, scanner);
if (parse_rc != 0) if (parse_rc != 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
@ -2025,8 +2025,6 @@ exec_replication_command(const char *cmd_string)
parse_rc))); parse_rc)));
replication_scanner_finish(scanner); replication_scanner_finish(scanner);
cmd_node = replication_parse_result;
/* /*
* Report query to various monitoring facilities. For this purpose, we * Report query to various monitoring facilities. For this purpose, we
* report replication commands just like SQL commands. * report replication commands just like SQL commands.

View File

@ -21,8 +21,6 @@
#define PGBENCH_NARGS_HASH (-3) #define PGBENCH_NARGS_HASH (-3)
#define PGBENCH_NARGS_PERMUTE (-4) #define PGBENCH_NARGS_PERMUTE (-4)
PgBenchExpr *expr_parse_result;
static PgBenchExprList *make_elist(PgBenchExpr *expr, PgBenchExprList *list); static PgBenchExprList *make_elist(PgBenchExpr *expr, PgBenchExprList *list);
static PgBenchExpr *make_null_constant(void); static PgBenchExpr *make_null_constant(void);
static PgBenchExpr *make_boolean_constant(bool bval); static PgBenchExpr *make_boolean_constant(bool bval);
@ -42,6 +40,7 @@ static PgBenchExpr *make_case(yyscan_t yyscanner, PgBenchExprList *when_then_lis
%expect 0 %expect 0
%name-prefix="expr_yy" %name-prefix="expr_yy"
%parse-param {PgBenchExpr **expr_parse_result_p}
%parse-param {yyscan_t yyscanner} %parse-param {yyscan_t yyscanner}
%lex-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 { result: expr {
expr_parse_result = $1; *expr_parse_result_p = $1;
(void) yynerrs; /* suppress compiler warning */ (void) yynerrs; /* suppress compiler warning */
} }

View File

@ -296,8 +296,12 @@ expr_yyerror_more(yyscan_t yyscanner, const char *message, const char *more)
message, more, error_detection_offset - expr_start_offset); 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 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); expr_yyerror_more(yyscanner, message, NULL);
} }

View File

@ -5706,14 +5706,12 @@ process_backslash_command(PsqlScanState sstate, const char *source)
yyscanner = expr_scanner_init(sstate, source, lineno, start_offset, yyscanner = expr_scanner_init(sstate, source, lineno, start_offset,
my_command->argv[0]); 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 */ /* dead code: exit done from syntax_error called by yyerror */
exit(1); exit(1);
} }
my_command->expr = expr_parse_result;
/* Save line, trimming any trailing newline */ /* Save line, trimming any trailing newline */
my_command->first_line = my_command->first_line =
expr_scanner_get_substring(sstate, expr_scanner_get_substring(sstate,

View File

@ -138,11 +138,9 @@ struct PgBenchExprList
PgBenchExprLink *tail; PgBenchExprLink *tail;
}; };
extern PgBenchExpr *expr_parse_result; extern int expr_yyparse(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner);
extern int expr_yyparse(yyscan_t yyscanner);
extern int expr_yylex(union YYSTYPE *yylval_param, 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, extern void expr_yyerror_more(yyscan_t yyscanner, const char *message,
const char *more) pg_attribute_noreturn(); const char *more) pg_attribute_noreturn();
extern bool expr_lex_one_word(PsqlScanState state, PQExpBuffer word_buf, extern bool expr_lex_one_word(PsqlScanState state, PQExpBuffer word_buf,

View File

@ -73,10 +73,6 @@ typedef struct SyncRepConfigData
extern PGDLLIMPORT SyncRepConfigData *SyncRepConfig; 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 */ /* user-settable parameters for synchronous replication */
extern PGDLLIMPORT char *SyncRepStandbyNames; extern PGDLLIMPORT char *SyncRepStandbyNames;
@ -105,9 +101,9 @@ union YYSTYPE;
#define YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T
typedef void *yyscan_t; typedef void *yyscan_t;
#endif #endif
extern int syncrep_yyparse(yyscan_t yyscanner); 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, yyscan_t yyscanner); extern int syncrep_yylex(union YYSTYPE *yylval_param, char **syncrep_parse_error_msg_p, yyscan_t yyscanner);
extern void syncrep_yyerror(yyscan_t yyscanner, const char *str); 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_init(const char *str, yyscan_t *yyscannerp);
extern void syncrep_scanner_finish(yyscan_t yyscanner); extern void syncrep_scanner_finish(yyscan_t yyscanner);

View File

@ -130,13 +130,11 @@ union YYSTYPE;
#define YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T
typedef void *yyscan_t; typedef void *yyscan_t;
#endif #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 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_init(const char *str, yyscan_t *yyscannerp);
extern void replication_scanner_finish(yyscan_t yyscanner); extern void replication_scanner_finish(yyscan_t yyscanner);
extern bool replication_scanner_is_replication_command(yyscan_t yyscanner); extern bool replication_scanner_is_replication_command(yyscan_t yyscanner);
extern PGDLLIMPORT Node *replication_parse_result;
#endif /* _WALSENDER_PRIVATE_H */ #endif /* _WALSENDER_PRIVATE_H */

View File

@ -6,5 +6,5 @@ GETTEXT_FILES = pl_comp.c \
pl_funcs.c \ pl_funcs.c \
pl_handler.c \ pl_handler.c \
pl_scanner.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) GETTEXT_FLAGS = $(BACKEND_COMMON_GETTEXT_FLAGS)

View File

@ -38,8 +38,6 @@
* Our own local and global variables * Our own local and global variables
* ---------- * ----------
*/ */
PLpgSQL_stmt_block *plpgsql_parse_result;
static int datums_alloc; static int datums_alloc;
int plpgsql_nDatums; int plpgsql_nDatums;
PLpgSQL_datum **plpgsql_Datums; PLpgSQL_datum **plpgsql_Datums;
@ -787,10 +785,9 @@ do_compile(FunctionCallInfo fcinfo,
/* /*
* Now parse the function's text * Now parse the function's text
*/ */
parse_rc = plpgsql_yyparse(scanner); parse_rc = plpgsql_yyparse(&function->action, scanner);
if (parse_rc != 0) if (parse_rc != 0)
elog(ERROR, "plpgsql parser returned %d", parse_rc); elog(ERROR, "plpgsql parser returned %d", parse_rc);
function->action = plpgsql_parse_result;
plpgsql_scanner_finish(scanner); plpgsql_scanner_finish(scanner);
pfree(proc_source); pfree(proc_source);
@ -945,10 +942,9 @@ plpgsql_compile_inline(char *proc_source)
/* /*
* Now parse the function's text * Now parse the function's text
*/ */
parse_rc = plpgsql_yyparse(scanner); parse_rc = plpgsql_yyparse(&function->action, scanner);
if (parse_rc != 0) if (parse_rc != 0)
elog(ERROR, "plpgsql parser returned %d", parse_rc); elog(ERROR, "plpgsql parser returned %d", parse_rc);
function->action = plpgsql_parse_result;
plpgsql_scanner_finish(scanner); plpgsql_scanner_finish(scanner);

View File

@ -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} %parse-param {yyscan_t yyscanner}
%lex-param {yyscan_t yyscanner} %lex-param {yyscan_t yyscanner}
%pure-parser %pure-parser
@ -368,7 +369,7 @@ static void check_raise_parameters(PLpgSQL_stmt_raise *stmt);
pl_function : comp_options pl_block opt_semi 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 */ (void) yynerrs; /* suppress compiler warning */
} }
; ;
@ -712,7 +713,7 @@ decl_varname : T_WORD
if (plpgsql_ns_lookup(plpgsql_ns_top(), true, if (plpgsql_ns_lookup(plpgsql_ns_top(), true,
$1.ident, NULL, NULL, $1.ident, NULL, NULL,
NULL) != NULL) NULL) != NULL)
yyerror(&yylloc, yyscanner, "duplicate declaration"); yyerror(&yylloc, NULL, yyscanner, "duplicate declaration");
if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR || if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR ||
plpgsql_curr_compile->extra_errors & 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, if (plpgsql_ns_lookup(plpgsql_ns_top(), true,
$1, NULL, NULL, $1, NULL, NULL,
NULL) != NULL) NULL) != NULL)
yyerror(&yylloc, yyscanner, "duplicate declaration"); yyerror(&yylloc, NULL, yyscanner, "duplicate declaration");
if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR || if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR ||
plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_SHADOWVAR) plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_SHADOWVAR)
@ -1143,7 +1144,7 @@ getdiag_item :
K_RETURNED_SQLSTATE, "returned_sqlstate")) K_RETURNED_SQLSTATE, "returned_sqlstate"))
$$ = PLPGSQL_GETDIAG_RETURNED_SQLSTATE; $$ = PLPGSQL_GETDIAG_RETURNED_SQLSTATE;
else 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); tok = yylex(&yylval, &yylloc, yyscanner);
if (tok == 0) 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, if (tok_is_keyword(tok, &yylval,
K_NEXT, "next")) K_NEXT, "next"))
@ -1815,7 +1816,7 @@ stmt_raise : K_RAISE
tok = yylex(&yylval, &yylloc, yyscanner); tok = yylex(&yylval, &yylloc, yyscanner);
if (tok == 0) 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 * We could have just RAISE, meaning to re-throw
@ -1863,7 +1864,7 @@ stmt_raise : K_RAISE
tok = yylex(&yylval, &yylloc, yyscanner); tok = yylex(&yylval, &yylloc, yyscanner);
} }
if (tok == 0) 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 * Next we can have a condition name, or
@ -1883,7 +1884,7 @@ stmt_raise : K_RAISE
*/ */
tok = yylex(&yylval, &yylloc, yyscanner); tok = yylex(&yylval, &yylloc, yyscanner);
if (tok != ',' && tok != ';' && tok != K_USING) if (tok != ',' && tok != ';' && tok != K_USING)
yyerror(&yylloc, yyscanner, "syntax error"); yyerror(&yylloc, NULL, yyscanner, "syntax error");
while (tok == ',') while (tok == ',')
{ {
@ -1908,13 +1909,13 @@ stmt_raise : K_RAISE
char *sqlstatestr; char *sqlstatestr;
if (yylex(&yylval, &yylloc, yyscanner) != SCONST) if (yylex(&yylval, &yylloc, yyscanner) != SCONST)
yyerror(&yylloc, yyscanner, "syntax error"); yyerror(&yylloc, NULL, yyscanner, "syntax error");
sqlstatestr = yylval.str; sqlstatestr = yylval.str;
if (strlen(sqlstatestr) != 5) if (strlen(sqlstatestr) != 5)
yyerror(&yylloc, yyscanner, "invalid SQLSTATE code"); yyerror(&yylloc, NULL, yyscanner, "invalid SQLSTATE code");
if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5) if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5)
yyerror(&yylloc, yyscanner, "invalid SQLSTATE code"); yyerror(&yylloc, NULL, yyscanner, "invalid SQLSTATE code");
new->condname = sqlstatestr; new->condname = sqlstatestr;
} }
else else
@ -1924,13 +1925,13 @@ stmt_raise : K_RAISE
else if (plpgsql_token_is_unreserved_keyword(tok)) else if (plpgsql_token_is_unreserved_keyword(tok))
new->condname = pstrdup(yylval.keyword); new->condname = pstrdup(yylval.keyword);
else else
yyerror(&yylloc, yyscanner, "syntax error"); yyerror(&yylloc, NULL, yyscanner, "syntax error");
plpgsql_recognize_err_condition(new->condname, plpgsql_recognize_err_condition(new->condname,
false); false);
} }
tok = yylex(&yylval, &yylloc, yyscanner); tok = yylex(&yylval, &yylloc, yyscanner);
if (tok != ';' && tok != K_USING) if (tok != ';' && tok != K_USING)
yyerror(&yylloc, yyscanner, "syntax error"); yyerror(&yylloc, NULL, yyscanner, "syntax error");
} }
if (tok == K_USING) if (tok == K_USING)
@ -2056,7 +2057,7 @@ stmt_dynexecute : K_EXECUTE
if (endtoken == K_INTO) if (endtoken == K_INTO)
{ {
if (new->into) /* multiple INTO */ if (new->into) /* multiple INTO */
yyerror(&yylloc, yyscanner, "syntax error"); yyerror(&yylloc, NULL, yyscanner, "syntax error");
new->into = true; new->into = true;
read_into_target(&new->target, &new->strict, &yylval, &yylloc, yyscanner); read_into_target(&new->target, &new->strict, &yylval, &yylloc, yyscanner);
endtoken = yylex(&yylval, &yylloc, yyscanner); endtoken = yylex(&yylval, &yylloc, yyscanner);
@ -2064,7 +2065,7 @@ stmt_dynexecute : K_EXECUTE
else if (endtoken == K_USING) else if (endtoken == K_USING)
{ {
if (new->params) /* multiple USING */ if (new->params) /* multiple USING */
yyerror(&yylloc, yyscanner, "syntax error"); yyerror(&yylloc, NULL, yyscanner, "syntax error");
do do
{ {
expr = read_sql_construct(',', ';', K_INTO, expr = read_sql_construct(',', ';', K_INTO,
@ -2079,7 +2080,7 @@ stmt_dynexecute : K_EXECUTE
else if (endtoken == ';') else if (endtoken == ';')
break; break;
else else
yyerror(&yylloc, yyscanner, "syntax error"); yyerror(&yylloc, NULL, yyscanner, "syntax error");
} }
$$ = (PLpgSQL_stmt *) new; $$ = (PLpgSQL_stmt *) new;
@ -2122,7 +2123,7 @@ stmt_open : K_OPEN cursor_variable
} }
if (tok != K_FOR) if (tok != K_FOR)
yyerror(&yylloc, yyscanner, "syntax error, expected \"FOR\""); yyerror(&yylloc, NULL, yyscanner, "syntax error, expected \"FOR\"");
tok = yylex(&yylval, &yylloc, yyscanner); tok = yylex(&yylval, &yylloc, yyscanner);
if (tok == K_EXECUTE) 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); read_into_target(&target, NULL, &yylval, &yylloc, yyscanner);
if (yylex(&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 * 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 */ /* next token should be a string literal */
if (yylex(&yylval, &yylloc, yyscanner) != SCONST) if (yylex(&yylval, &yylloc, yyscanner) != SCONST)
yyerror(&yylloc, yyscanner, "syntax error"); yyerror(&yylloc, NULL, yyscanner, "syntax error");
sqlstatestr = yylval.str; sqlstatestr = yylval.str;
if (strlen(sqlstatestr) != 5) if (strlen(sqlstatestr) != 5)
yyerror(&yylloc, yyscanner, "invalid SQLSTATE code"); yyerror(&yylloc, NULL, yyscanner, "invalid SQLSTATE code");
if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5) if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5)
yyerror(&yylloc, yyscanner, "invalid SQLSTATE code"); yyerror(&yylloc, NULL, yyscanner, "invalid SQLSTATE code");
new = palloc(sizeof(PLpgSQL_condition)); new = palloc(sizeof(PLpgSQL_condition));
new->sqlerrstate = new->sqlerrstate =
@ -2488,7 +2489,7 @@ any_identifier : T_WORD
| T_DATUM | T_DATUM
{ {
if ($1.ident == NULL) /* composite name not OK */ if ($1.ident == NULL) /* composite name not OK */
yyerror(&yylloc, yyscanner, "syntax error"); yyerror(&yylloc, NULL, yyscanner, "syntax error");
$$ = $1.ident; $$ = $1.ident;
} }
; ;
@ -2647,7 +2648,7 @@ current_token_is_not_variable(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yysca
else if (tok == T_CWORD) else if (tok == T_CWORD)
cword_is_not_variable(&(yylvalp->cword), *yyllocp, yyscanner); cword_is_not_variable(&(yylvalp->cword), *yyllocp, yyscanner);
else else
yyerror(yyllocp, yyscanner, "syntax error"); yyerror(yyllocp, NULL, yyscanner, "syntax error");
} }
/* Convenience routine to read an expression with one possible terminator */ /* Convenience routine to read an expression with one possible terminator */
@ -2739,7 +2740,7 @@ read_sql_construct(int until,
{ {
parenlevel--; parenlevel--;
if (parenlevel < 0) 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 (tok == 0 || tok == ';')
{ {
if (parenlevel != 0) if (parenlevel != 0)
yyerror(yyllocp, yyscanner, "mismatched parentheses"); yyerror(yyllocp, NULL, yyscanner, "mismatched parentheses");
if (isexpression) if (isexpression)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
@ -2779,9 +2780,9 @@ read_sql_construct(int until,
if (startlocation >= endlocation) if (startlocation >= endlocation)
{ {
if (isexpression) if (isexpression)
yyerror(yyllocp, yyscanner, "missing expression"); yyerror(yyllocp, NULL, yyscanner, "missing expression");
else 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) if (tok == ICONST)
tok = yylex(yylvalp, yyllocp, yyscanner); tok = yylex(yylvalp, yyllocp, yyscanner);
if (tok != ']') if (tok != ']')
yyerror(yyllocp, yyscanner, "syntax error, expected \"]\""); yyerror(yyllocp, NULL, yyscanner, "syntax error, expected \"]\"");
tok = yylex(yylvalp, yyllocp, yyscanner); tok = yylex(yylvalp, yyllocp, yyscanner);
} }
plpgsql_push_back_token(tok, 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 (tok == 0)
{ {
if (parenlevel != 0) if (parenlevel != 0)
yyerror(yyllocp, yyscanner, "mismatched parentheses"); yyerror(yyllocp, NULL, yyscanner, "mismatched parentheses");
else else
yyerror(yyllocp, yyscanner, "incomplete data type declaration"); yyerror(yyllocp, NULL, yyscanner, "incomplete data type declaration");
} }
/* Possible followers for datatype in a declaration */ /* Possible followers for datatype in a declaration */
if (tok == K_COLLATE || tok == K_NOT || 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; type_name = ds.data;
if (type_name[0] == '\0') 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); 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) if (tok == ';' && paren_depth == 0 && begin_depth == 0)
break; break;
if (tok == 0) 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 (tok == K_INTO)
{ {
if (prev_tok == K_INSERT) if (prev_tok == K_INSERT)
@ -3092,7 +3093,7 @@ make_execsql_stmt(int firsttoken, int location, PLword *word, YYSTYPE *yylvalp,
if (firsttoken == K_IMPORT) if (firsttoken == K_IMPORT)
continue; /* IMPORT ... INTO is not an INTO-target */ continue; /* IMPORT ... INTO is not an INTO-target */
if (have_into) if (have_into)
yyerror(yyllocp, yyscanner, "INTO specified more than once"); yyerror(yyllocp, NULL, yyscanner, "INTO specified more than once");
have_into = true; have_into = true;
into_start_loc = *yyllocp; into_start_loc = *yyllocp;
plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL; plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
@ -3170,7 +3171,7 @@ read_fetch_direction(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
tok = yylex(yylvalp, yyllocp, yyscanner); tok = yylex(yylvalp, yyllocp, yyscanner);
if (tok == 0) 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, if (tok_is_keyword(tok, yylvalp,
K_NEXT, "next")) K_NEXT, "next"))
@ -3262,7 +3263,7 @@ read_fetch_direction(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
{ {
tok = yylex(yylvalp, yyllocp, yyscanner); tok = yylex(yylvalp, yyllocp, yyscanner);
if (tok != K_FROM && tok != K_IN) if (tok != K_FROM && tok != K_IN)
yyerror(yyllocp, yyscanner, "expected FROM or IN"); yyerror(yyllocp, NULL, yyscanner, "expected FROM or IN");
} }
return fetch; return fetch;
@ -3281,7 +3282,7 @@ complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM, YYSTYPE *yylvalp
tok = yylex(yylvalp, yyllocp, yyscanner); tok = yylex(yylvalp, yyllocp, yyscanner);
if (tok == 0) 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) 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))); parser_errposition(*yyllocp)));
if (tok != until) if (tok != until)
yyerror(yyllocp, yyscanner, "syntax error"); yyerror(yyllocp, NULL, yyscanner, "syntax error");
return NULL; return NULL;
} }
@ -3943,7 +3944,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until, YYSTYPE *yylvalp, YYLTYPE *yyll
*/ */
tok2 = yylex(yylvalp, yyllocp, yyscanner); tok2 = yylex(yylvalp, yyllocp, yyscanner);
if (tok2 != COLON_EQUALS) if (tok2 != COLON_EQUALS)
yyerror(yyllocp, yyscanner, "syntax error"); yyerror(yyllocp, NULL, yyscanner, "syntax error");
any_named = true; 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 */ /* Next we'd better find the until token */
tok = yylex(yylvalp, yyllocp, yyscanner); tok = yylex(yylvalp, yyllocp, yyscanner);
if (tok != until) if (tok != until)
yyerror(yyllocp, yyscanner, "syntax error"); yyerror(yyllocp, NULL, yyscanner, "syntax error");
return expr; return expr;
} }
@ -4036,7 +4037,7 @@ read_raise_options(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
int tok; int tok;
if ((tok = yylex(yylvalp, yyllocp, yyscanner)) == 0) 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)); 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")) K_SCHEMA, "schema"))
opt->opt_type = PLPGSQL_RAISEOPTION_SCHEMA; opt->opt_type = PLPGSQL_RAISEOPTION_SCHEMA;
else else
yyerror(yyllocp, yyscanner, "unrecognized RAISE statement option"); yyerror(yyllocp, NULL, yyscanner, "unrecognized RAISE statement option");
tok = yylex(yylvalp, yyllocp, yyscanner); tok = yylex(yylvalp, yyllocp, yyscanner);
if (tok != '=' && tok != COLON_EQUALS) 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); opt->expr = read_sql_expression2(',', ';', ", or ;", &tok, yylvalp, yyllocp, yyscanner);

View File

@ -526,9 +526,12 @@ plpgsql_scanner_errposition(int location, yyscan_t yyscanner)
* parsers report error as soon as the first unparsable token is reached. * parsers report error as soon as the first unparsable token is reached.
* Beware of using yyerror for other purposes, as the cursor position might * Beware of using yyerror for other purposes, as the cursor position might
* be misleading! * be misleading!
*
* (The second argument is enforced by Bison to match the second argument of
* yyparse(), but it is not used here.)
*/ */
void 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; char *yytext = yyextra->core_yy_extra.scanbuf + *yyllocp;

View File

@ -1212,8 +1212,6 @@ extern int plpgsql_extra_errors;
extern bool plpgsql_check_syntax; extern bool plpgsql_check_syntax;
extern bool plpgsql_DumpExecTree; extern bool plpgsql_DumpExecTree;
extern PLpgSQL_stmt_block *plpgsql_parse_result;
extern int plpgsql_nDatums; extern int plpgsql_nDatums;
extern PLpgSQL_datum **plpgsql_Datums; 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, extern void plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc,
int *tok2_loc, yyscan_t yyscanner); int *tok2_loc, yyscan_t yyscanner);
extern int plpgsql_scanner_errposition(int location, 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_location_to_lineno(int location, yyscan_t yyscanner);
extern int plpgsql_latest_lineno(yyscan_t yyscanner); extern int plpgsql_latest_lineno(yyscan_t yyscanner);
extern yyscan_t plpgsql_scanner_init(const char *str); 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 * 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 */ #endif /* PLPGSQL_H */