Skip to content

Commit 473a575

Browse files
committed
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
1 parent 6fc4fc4 commit 473a575

18 files changed

+106
-101
lines changed

src/backend/nls.mk

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS) \
99
yyerror \
1010
jsonpath_yyerror:4 \
1111
parser_yyerror \
12-
replication_yyerror:2 \
12+
replication_yyerror:3 \
1313
scanner_yyerror \
14-
syncrep_yyerror:2 \
14+
syncrep_yyerror:4 \
1515
report_invalid_record:2 \
1616
ereport_startup_progress \
1717
json_token_error:2 \

src/backend/replication/repl_gram.y

+2-5
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@
2525
#include "repl_gram.h"
2626

2727

28-
/* Result of the parsing is returned here */
29-
Node *replication_parse_result;
30-
31-
3228
/*
3329
* Bison doesn't allocate anything that needs to live across parser calls,
3430
* so we can easily have it use palloc instead of malloc. This prevents
@@ -39,6 +35,7 @@ Node *replication_parse_result;
3935

4036
%}
4137

38+
%parse-param {Node **replication_parse_result_p}
4239
%parse-param {yyscan_t yyscanner}
4340
%lex-param {yyscan_t yyscanner}
4441
%pure-parser
@@ -104,7 +101,7 @@ Node *replication_parse_result;
104101

105102
firstcmd: command opt_semicolon
106103
{
107-
replication_parse_result = $1;
104+
*replication_parse_result_p = $1;
108105

109106
(void) yynerrs; /* suppress compiler warning */
110107
}

src/backend/replication/repl_scanner.l

+7-3
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ UPLOAD_MANIFEST { return K_UPLOAD_MANIFEST; }
156156
uint32 hi,
157157
lo;
158158
if (sscanf(yytext, "%X/%X", &hi, &lo) != 2)
159-
replication_yyerror(yyscanner, "invalid streaming start location");
159+
replication_yyerror(NULL, yyscanner, "invalid streaming start location");
160160
yylval->recptr = ((uint64) hi) << 32 | lo;
161161
return RECPTR;
162162
}
@@ -213,7 +213,7 @@ UPLOAD_MANIFEST { return K_UPLOAD_MANIFEST; }
213213
return yytext[0];
214214
}
215215

216-
<xq,xd><<EOF>> { replication_yyerror(yyscanner, "unterminated quoted string"); }
216+
<xq,xd><<EOF>> { replication_yyerror(NULL, yyscanner, "unterminated quoted string"); }
217217

218218

219219
<<EOF>> {
@@ -252,8 +252,12 @@ addlitchar(unsigned char ychar, yyscan_t yyscanner)
252252
appendStringInfoChar(&yyextra->litbuf, ychar);
253253
}
254254

255+
/*
256+
* (The first argument is enforced by Bison to match the first argument of
257+
* yyparse(), but it is not used here.)
258+
*/
255259
void
256-
replication_yyerror(yyscan_t yyscanner, const char *message)
260+
replication_yyerror(Node **replication_parse_result_p, yyscan_t yyscanner, const char *message)
257261
{
258262
ereport(ERROR,
259263
(errcode(ERRCODE_SYNTAX_ERROR),

src/backend/replication/syncrep.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -996,13 +996,13 @@ check_synchronous_standby_names(char **newval, void **extra, GucSource source)
996996
int parse_rc;
997997
SyncRepConfigData *pconf;
998998

999-
/* Reset communication variables to ensure a fresh start */
1000-
syncrep_parse_result = NULL;
1001-
syncrep_parse_error_msg = NULL;
999+
/* Result of parsing is returned in one of these two variables */
1000+
SyncRepConfigData *syncrep_parse_result = NULL;
1001+
char *syncrep_parse_error_msg = NULL;
10021002

10031003
/* Parse the synchronous_standby_names string */
10041004
syncrep_scanner_init(*newval, &scanner);
1005-
parse_rc = syncrep_yyparse(scanner);
1005+
parse_rc = syncrep_yyparse(&syncrep_parse_result, &syncrep_parse_error_msg, scanner);
10061006
syncrep_scanner_finish(scanner);
10071007

10081008
if (parse_rc != 0 || syncrep_parse_result == NULL)

src/backend/replication/syncrep_gram.y

+4-5
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@
1919

2020
#include "syncrep_gram.h"
2121

22-
/* Result of parsing is returned in one of these two variables */
23-
SyncRepConfigData *syncrep_parse_result;
24-
char *syncrep_parse_error_msg;
25-
2622
static SyncRepConfigData *create_syncrep_config(const char *num_sync,
2723
List *members, uint8 syncrep_method);
2824

@@ -36,7 +32,10 @@ static SyncRepConfigData *create_syncrep_config(const char *num_sync,
3632

3733
%}
3834

35+
%parse-param {SyncRepConfigData **syncrep_parse_result_p}
36+
%parse-param {char **syncrep_parse_error_msg_p}
3937
%parse-param {yyscan_t yyscanner}
38+
%lex-param {char **syncrep_parse_error_msg_p}
4039
%lex-param {yyscan_t yyscanner}
4140
%pure-parser
4241
%expect 0
@@ -60,7 +59,7 @@ static SyncRepConfigData *create_syncrep_config(const char *num_sync,
6059
%%
6160
result:
6261
standby_config {
63-
syncrep_parse_result = $1;
62+
*syncrep_parse_result_p = $1;
6463
(void) yynerrs; /* suppress compiler warning */
6564
}
6665
;

src/backend/replication/syncrep_scanner.l

+19-3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ struct syncrep_yy_extra_type
4242
StringInfoData xdbuf;
4343
};
4444

45+
/*
46+
* Better keep this definition here than put it in replication/syncrep.h and
47+
* save a bit of duplication. Putting it in replication/syncrep.h would leak
48+
* the definition to other parts and possibly affect other scanners.
49+
*/
50+
#define YY_DECL extern int syncrep_yylex(union YYSTYPE *yylval_param, char **syncrep_parse_error_msg_p, yyscan_t yyscanner)
51+
4552
/* LCOV_EXCL_START */
4653

4754
%}
@@ -104,7 +111,7 @@ xdinside [^"]+
104111
return NAME;
105112
}
106113
<xd><<EOF>> {
107-
syncrep_yyerror(yyscanner, "unterminated quoted identifier");
114+
syncrep_yyerror(NULL, syncrep_parse_error_msg_p, yyscanner, "unterminated quoted identifier");
108115
return JUNK;
109116
}
110117

@@ -136,12 +143,21 @@ xdinside [^"]+
136143
#undef yyextra
137144
#define yyextra (((struct yyguts_t *) yyscanner)->yyextra_r)
138145

139-
/* Needs to be here for access to yytext */
146+
/*
147+
* This yyerror() function does not raise an error (elog or similar), it just
148+
* collects the error message in *syncrep_parse_error_msg_p and leaves it to
149+
* the ultimate caller of the syncrep parser to raise the error. (The
150+
* ultimate caller will do that with special GUC error functions.)
151+
*
152+
* (The first argument is enforced by Bison to match the first argument of
153+
* yyparse(), but it is not used here.)
154+
*/
140155
void
141-
syncrep_yyerror(yyscan_t yyscanner, const char *message)
156+
syncrep_yyerror(SyncRepConfigData **syncrep_parse_result_p, char **syncrep_parse_error_msg_p, yyscan_t yyscanner, const char *message)
142157
{
143158
struct yyguts_t *yyg = (struct yyguts_t *) yyscanner; /* needed for yytext
144159
* macro */
160+
char *syncrep_parse_error_msg = *syncrep_parse_error_msg_p;
145161

146162
/* report only the first error in a parse operation */
147163
if (syncrep_parse_error_msg)

src/backend/replication/walsender.c

+1-3
Original file line numberDiff line numberDiff line change
@@ -2017,16 +2017,14 @@ exec_replication_command(const char *cmd_string)
20172017
/*
20182018
* Looks like a WalSender command, so parse it.
20192019
*/
2020-
parse_rc = replication_yyparse(scanner);
2020+
parse_rc = replication_yyparse(&cmd_node, scanner);
20212021
if (parse_rc != 0)
20222022
ereport(ERROR,
20232023
(errcode(ERRCODE_SYNTAX_ERROR),
20242024
errmsg_internal("replication command parser returned %d",
20252025
parse_rc)));
20262026
replication_scanner_finish(scanner);
20272027

2028-
cmd_node = replication_parse_result;
2029-
20302028
/*
20312029
* Report query to various monitoring facilities. For this purpose, we
20322030
* report replication commands just like SQL commands.

src/bin/pgbench/exprparse.y

+2-3
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
#define PGBENCH_NARGS_HASH (-3)
2222
#define PGBENCH_NARGS_PERMUTE (-4)
2323

24-
PgBenchExpr *expr_parse_result;
25-
2624
static PgBenchExprList *make_elist(PgBenchExpr *expr, PgBenchExprList *list);
2725
static PgBenchExpr *make_null_constant(void);
2826
static PgBenchExpr *make_boolean_constant(bool bval);
@@ -42,6 +40,7 @@ static PgBenchExpr *make_case(yyscan_t yyscanner, PgBenchExprList *when_then_lis
4240
%expect 0
4341
%name-prefix="expr_yy"
4442

43+
%parse-param {PgBenchExpr **expr_parse_result_p}
4544
%parse-param {yyscan_t yyscanner}
4645
%lex-param {yyscan_t yyscanner}
4746

@@ -81,7 +80,7 @@ static PgBenchExpr *make_case(yyscan_t yyscanner, PgBenchExprList *when_then_lis
8180
%%
8281

8382
result: expr {
84-
expr_parse_result = $1;
83+
*expr_parse_result_p = $1;
8584
(void) yynerrs; /* suppress compiler warning */
8685
}
8786

src/bin/pgbench/exprscan.l

+5-1
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,12 @@ expr_yyerror_more(yyscan_t yyscanner, const char *message, const char *more)
296296
message, more, error_detection_offset - expr_start_offset);
297297
}
298298

299+
/*
300+
* (The first argument is enforced by Bison to match the first argument of
301+
* yyparse(), but it is not used here.)
302+
*/
299303
void
300-
expr_yyerror(yyscan_t yyscanner, const char *message)
304+
expr_yyerror(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner, const char *message)
301305
{
302306
expr_yyerror_more(yyscanner, message, NULL);
303307
}

src/bin/pgbench/pgbench.c

+1-3
Original file line numberDiff line numberDiff line change
@@ -5706,14 +5706,12 @@ process_backslash_command(PsqlScanState sstate, const char *source)
57065706
yyscanner = expr_scanner_init(sstate, source, lineno, start_offset,
57075707
my_command->argv[0]);
57085708

5709-
if (expr_yyparse(yyscanner) != 0)
5709+
if (expr_yyparse(&my_command->expr, yyscanner) != 0)
57105710
{
57115711
/* dead code: exit done from syntax_error called by yyerror */
57125712
exit(1);
57135713
}
57145714

5715-
my_command->expr = expr_parse_result;
5716-
57175715
/* Save line, trimming any trailing newline */
57185716
my_command->first_line =
57195717
expr_scanner_get_substring(sstate,

src/bin/pgbench/pgbench.h

+2-4
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,9 @@ struct PgBenchExprList
138138
PgBenchExprLink *tail;
139139
};
140140

141-
extern PgBenchExpr *expr_parse_result;
142-
143-
extern int expr_yyparse(yyscan_t yyscanner);
141+
extern int expr_yyparse(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner);
144142
extern int expr_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner);
145-
extern void expr_yyerror(yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
143+
extern void expr_yyerror(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
146144
extern void expr_yyerror_more(yyscan_t yyscanner, const char *message,
147145
const char *more) pg_attribute_noreturn();
148146
extern bool expr_lex_one_word(PsqlScanState state, PQExpBuffer word_buf,

src/include/replication/syncrep.h

+3-7
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,6 @@ typedef struct SyncRepConfigData
7373

7474
extern PGDLLIMPORT SyncRepConfigData *SyncRepConfig;
7575

76-
/* communication variables for parsing synchronous_standby_names GUC */
77-
extern PGDLLIMPORT SyncRepConfigData *syncrep_parse_result;
78-
extern PGDLLIMPORT char *syncrep_parse_error_msg;
79-
8076
/* user-settable parameters for synchronous replication */
8177
extern PGDLLIMPORT char *SyncRepStandbyNames;
8278

@@ -105,9 +101,9 @@ union YYSTYPE;
105101
#define YY_TYPEDEF_YY_SCANNER_T
106102
typedef void *yyscan_t;
107103
#endif
108-
extern int syncrep_yyparse(yyscan_t yyscanner);
109-
extern int syncrep_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner);
110-
extern void syncrep_yyerror(yyscan_t yyscanner, const char *str);
104+
extern int syncrep_yyparse(SyncRepConfigData **syncrep_parse_result_p, char **syncrep_parse_error_msg_p, yyscan_t yyscanner);
105+
extern int syncrep_yylex(union YYSTYPE *yylval_param, char **syncrep_parse_error_msg_p, yyscan_t yyscanner);
106+
extern void syncrep_yyerror(SyncRepConfigData **syncrep_parse_result_p, char **syncrep_parse_error_msg_p, yyscan_t yyscanner, const char *str);
111107
extern void syncrep_scanner_init(const char *str, yyscan_t *yyscannerp);
112108
extern void syncrep_scanner_finish(yyscan_t yyscanner);
113109

src/include/replication/walsender_private.h

+2-4
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,11 @@ union YYSTYPE;
130130
#define YY_TYPEDEF_YY_SCANNER_T
131131
typedef void *yyscan_t;
132132
#endif
133-
extern int replication_yyparse(yyscan_t yyscanner);
133+
extern int replication_yyparse(Node **replication_parse_result_p, yyscan_t yyscanner);
134134
extern int replication_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner);
135-
extern void replication_yyerror(yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
135+
extern void replication_yyerror(Node **replication_parse_result_p, yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
136136
extern void replication_scanner_init(const char *str, yyscan_t *yyscannerp);
137137
extern void replication_scanner_finish(yyscan_t yyscanner);
138138
extern bool replication_scanner_is_replication_command(yyscan_t yyscanner);
139139

140-
extern PGDLLIMPORT Node *replication_parse_result;
141-
142140
#endif /* _WALSENDER_PRIVATE_H */

src/pl/plpgsql/src/nls.mk

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ GETTEXT_FILES = pl_comp.c \
66
pl_funcs.c \
77
pl_handler.c \
88
pl_scanner.c
9-
GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS) yyerror:3 plpgsql_yyerror:3
9+
GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS) yyerror:4 plpgsql_yyerror:4
1010
GETTEXT_FLAGS = $(BACKEND_COMMON_GETTEXT_FLAGS)

src/pl/plpgsql/src/pl_comp.c

+2-6
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@
3838
* Our own local and global variables
3939
* ----------
4040
*/
41-
PLpgSQL_stmt_block *plpgsql_parse_result;
42-
4341
static int datums_alloc;
4442
int plpgsql_nDatums;
4543
PLpgSQL_datum **plpgsql_Datums;
@@ -787,10 +785,9 @@ do_compile(FunctionCallInfo fcinfo,
787785
/*
788786
* Now parse the function's text
789787
*/
790-
parse_rc = plpgsql_yyparse(scanner);
788+
parse_rc = plpgsql_yyparse(&function->action, scanner);
791789
if (parse_rc != 0)
792790
elog(ERROR, "plpgsql parser returned %d", parse_rc);
793-
function->action = plpgsql_parse_result;
794791

795792
plpgsql_scanner_finish(scanner);
796793
pfree(proc_source);
@@ -945,10 +942,9 @@ plpgsql_compile_inline(char *proc_source)
945942
/*
946943
* Now parse the function's text
947944
*/
948-
parse_rc = plpgsql_yyparse(scanner);
945+
parse_rc = plpgsql_yyparse(&function->action, scanner);
949946
if (parse_rc != 0)
950947
elog(ERROR, "plpgsql parser returned %d", parse_rc);
951-
function->action = plpgsql_parse_result;
952948

953949
plpgsql_scanner_finish(scanner);
954950

0 commit comments

Comments
 (0)