Skip to content

Commit 429ee5a

Browse files
committed
Make pgbench's expression lexer reentrant.
This is a necessary preliminary step for making it play with psqlscan.l given the way I set up the lexer input-buffer sharing mechanism in commit 0ea9efb. I've not tried to make it *actually* reentrant; there's still some static variables laying about. But flex thinks it's reentrant, and that's what counts. In support of that, fix exprparse.y to pass through the yyscan_t from the caller. Also do some minor code beautification, like not casting away const.
1 parent 1038bc9 commit 429ee5a

File tree

4 files changed

+117
-64
lines changed

4 files changed

+117
-64
lines changed

src/bin/pgbench/exprparse.y

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10+
* src/bin/pgbench/exprparse.y
11+
*
1012
*-------------------------------------------------------------------------
1113
*/
1214

@@ -19,16 +21,19 @@ PgBenchExpr *expr_parse_result;
1921
static PgBenchExprList *make_elist(PgBenchExpr *exp, PgBenchExprList *list);
2022
static PgBenchExpr *make_integer_constant(int64 ival);
2123
static PgBenchExpr *make_variable(char *varname);
22-
static PgBenchExpr *make_op(const char *operator, PgBenchExpr *lexpr,
23-
PgBenchExpr *rexpr);
24-
static int find_func(const char *fname);
25-
static PgBenchExpr *make_func(const int fnumber, PgBenchExprList *args);
24+
static PgBenchExpr *make_op(yyscan_t yyscanner, const char *operator,
25+
PgBenchExpr *lexpr, PgBenchExpr *rexpr);
26+
static int find_func(yyscan_t yyscanner, const char *fname);
27+
static PgBenchExpr *make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *args);
2628

2729
%}
2830

2931
%expect 0
3032
%name-prefix="expr_yy"
3133

34+
%parse-param {yyscan_t yyscanner}
35+
%lex-param {yyscan_t yyscanner}
36+
3237
%union
3338
{
3439
int64 ival;
@@ -43,7 +48,6 @@ static PgBenchExpr *make_func(const int fnumber, PgBenchExprList *args);
4348
%type <str> VARIABLE FUNCTION
4449

4550
%token INTEGER VARIABLE FUNCTION
46-
%token CHAR_ERROR /* never used, will raise a syntax error */
4751

4852
/* Precedence: lowest to highest */
4953
%left '+' '-'
@@ -61,18 +65,19 @@ elist: { $$ = NULL; }
6165

6266
expr: '(' expr ')' { $$ = $2; }
6367
| '+' expr %prec UMINUS { $$ = $2; }
64-
| '-' expr %prec UMINUS { $$ = make_op("-", make_integer_constant(0), $2); }
65-
| expr '+' expr { $$ = make_op("+", $1, $3); }
66-
| expr '-' expr { $$ = make_op("-", $1, $3); }
67-
| expr '*' expr { $$ = make_op("*", $1, $3); }
68-
| expr '/' expr { $$ = make_op("/", $1, $3); }
69-
| expr '%' expr { $$ = make_op("%", $1, $3); }
68+
| '-' expr %prec UMINUS { $$ = make_op(yyscanner, "-",
69+
make_integer_constant(0), $2); }
70+
| expr '+' expr { $$ = make_op(yyscanner, "+", $1, $3); }
71+
| expr '-' expr { $$ = make_op(yyscanner, "-", $1, $3); }
72+
| expr '*' expr { $$ = make_op(yyscanner, "*", $1, $3); }
73+
| expr '/' expr { $$ = make_op(yyscanner, "/", $1, $3); }
74+
| expr '%' expr { $$ = make_op(yyscanner, "%", $1, $3); }
7075
| INTEGER { $$ = make_integer_constant($1); }
7176
| VARIABLE { $$ = make_variable($1); }
72-
| function '(' elist ')'{ $$ = make_func($1, $3); }
77+
| function '(' elist ')' { $$ = make_func(yyscanner, $1, $3); }
7378
;
7479

75-
function: FUNCTION { $$ = find_func($1); pg_free($1); }
80+
function: FUNCTION { $$ = find_func(yyscanner, $1); pg_free($1); }
7681
;
7782

7883
%%
@@ -98,9 +103,10 @@ make_variable(char *varname)
98103
}
99104

100105
static PgBenchExpr *
101-
make_op(const char *operator, PgBenchExpr *lexpr, PgBenchExpr *rexpr)
106+
make_op(yyscan_t yyscanner, const char *operator,
107+
PgBenchExpr *lexpr, PgBenchExpr *rexpr)
102108
{
103-
return make_func(find_func(operator),
109+
return make_func(yyscanner, find_func(yyscanner, operator),
104110
make_elist(rexpr, make_elist(lexpr, NULL)));
105111
}
106112

@@ -139,7 +145,7 @@ static struct
139145
* or fail if the function is unknown.
140146
*/
141147
static int
142-
find_func(const char * fname)
148+
find_func(yyscan_t yyscanner, const char *fname)
143149
{
144150
int i = 0;
145151

@@ -150,7 +156,7 @@ find_func(const char * fname)
150156
i++;
151157
}
152158

153-
expr_yyerror_more("unexpected function name", fname);
159+
expr_yyerror_more(yyscanner, "unexpected function name", fname);
154160

155161
/* not reached */
156162
return -1;
@@ -198,21 +204,21 @@ elist_length(PgBenchExprList *list)
198204

199205
/* Build function call expression */
200206
static PgBenchExpr *
201-
make_func(const int fnumber, PgBenchExprList *args)
207+
make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *args)
202208
{
203209
PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
204210

205211
Assert(fnumber >= 0);
206212

207213
if (PGBENCH_FUNCTIONS[fnumber].nargs >= 0 &&
208214
PGBENCH_FUNCTIONS[fnumber].nargs != elist_length(args))
209-
expr_yyerror_more("unexpected number of arguments",
215+
expr_yyerror_more(yyscanner, "unexpected number of arguments",
210216
PGBENCH_FUNCTIONS[fnumber].fname);
211217

212218
/* check at least one arg for min & max */
213219
if (PGBENCH_FUNCTIONS[fnumber].nargs == -1 &&
214220
elist_length(args) == 0)
215-
expr_yyerror_more("at least one argument expected",
221+
expr_yyerror_more(yyscanner, "at least one argument expected",
216222
PGBENCH_FUNCTIONS[fnumber].fname);
217223

218224
expr->etype = ENODE_FUNCTION;
@@ -226,4 +232,15 @@ make_func(const int fnumber, PgBenchExprList *args)
226232
return expr;
227233
}
228234

235+
/*
236+
* exprscan.l is compiled as part of exprparse.y. Currently, this is
237+
* unavoidable because exprparse does not create a .h file to export
238+
* its token symbols. If these files ever grow large enough to be
239+
* worth compiling separately, that could be fixed; but for now it
240+
* seems like useless complication.
241+
*/
242+
243+
/* First, get rid of "#define yyscan_t" from pgbench.h */
244+
#undef yyscan_t
245+
229246
#include "exprscan.c"

src/bin/pgbench/exprscan.l

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10+
* src/bin/pgbench/exprscan.l
11+
*
1012
*-------------------------------------------------------------------------
1113
*/
1214

@@ -16,16 +18,27 @@ static int yyline = 0, yycol = 0;
1618
/* Handles to the buffer that the lexer uses internally */
1719
static YY_BUFFER_STATE scanbufhandle;
1820
static char *scanbuf;
19-
static int scanbuflen;
2021

2122
/* context information for error reporting */
22-
static char *expr_source = NULL;
23+
static const char *expr_source = NULL;
2324
static int expr_lineno = 0;
24-
static char *expr_full_line = NULL;
25-
static char *expr_command = NULL;
25+
static const char *expr_full_line = NULL;
26+
static const char *expr_command = NULL;
2627
static int expr_col = 0;
28+
29+
/*
30+
* Work around a bug in flex 2.5.35: it emits a couple of functions that
31+
* it forgets to emit declarations for. Since we use -Wmissing-prototypes,
32+
* this would cause warnings. Providing our own declarations should be
33+
* harmless even when the bug gets fixed.
34+
*/
35+
extern int expr_yyget_column(yyscan_t yyscanner);
36+
extern void expr_yyset_column(int column_no, yyscan_t yyscanner);
37+
2738
%}
2839

40+
/* Except for the prefix, these options should match psqlscan.l */
41+
%option reentrant
2942
%option 8bit
3043
%option never-interactive
3144
%option nodefault
@@ -42,6 +55,15 @@ space [ \t\r\f]
4255

4356
%%
4457

58+
%{
59+
/*
60+
* Force flex into the appropriate start state ... which, for this
61+
* case, is always INITIAL. This ensures that we can transition
62+
* between different lexers sharing the same yyscan_t.
63+
*/
64+
BEGIN(INITIAL);
65+
%}
66+
4567
"+" { yycol += yyleng; return '+'; }
4668
"-" { yycol += yyleng; return '-'; }
4769
"*" { yycol += yyleng; return '*'; }
@@ -69,77 +91,76 @@ space [ \t\r\f]
6991

7092
[\n] { yycol = 0; yyline++; }
7193

72-
{space}+ { yycol += yyleng; /* ignore */ }
94+
{space}+ { yycol += yyleng; /* otherwise ignore */ }
7395

7496
. {
7597
yycol += yyleng;
7698
syntax_error(expr_source, expr_lineno, expr_full_line, expr_command,
7799
"unexpected character", yytext, expr_col + yycol);
78-
/* dead code, exit is called from syntax_error */
79-
return CHAR_ERROR;
100+
/* NOTREACHED, exit is called from syntax_error */
101+
return 0;
80102
}
81103
%%
82104

83105
void
84-
expr_yyerror_more(const char *message, const char *more)
106+
expr_yyerror_more(yyscan_t yyscanner, const char *message, const char *more)
85107
{
86108
syntax_error(expr_source, expr_lineno, expr_full_line, expr_command,
87109
message, more, expr_col + yycol);
88110
}
89111

90112
void
91-
yyerror(const char *message)
113+
yyerror(yyscan_t yyscanner, const char *message)
92114
{
93-
expr_yyerror_more(message, NULL);
115+
expr_yyerror_more(yyscanner, message, NULL);
94116
}
95117

96118
/*
97119
* Called before any actual parsing is done
98120
*/
99-
void
121+
yyscan_t
100122
expr_scanner_init(const char *str, const char *source,
101-
const int lineno, const char *line,
102-
const char *cmd, const int ecol)
123+
int lineno, const char *line,
124+
const char *cmd, int ecol)
103125
{
126+
yyscan_t yyscanner;
104127
Size slen = strlen(str);
105128

106-
/* save context informations for error messages */
107-
expr_source = (char *) source;
108-
expr_lineno = (int) lineno;
109-
expr_full_line = (char *) line;
110-
expr_command = (char *) cmd;
111-
expr_col = (int) ecol;
129+
/* Set up yyscan_t */
130+
yylex_init(&yyscanner);
131+
132+
/* save context information for error messages */
133+
expr_source = source;
134+
expr_lineno = lineno;
135+
expr_full_line = line;
136+
expr_command = cmd;
137+
expr_col = ecol;
112138

113139
/* reset error pointers for this scan */
114140
yycol = yyline = 0;
115141

116-
/*
117-
* Might be left over after error
118-
*/
119-
if (YY_CURRENT_BUFFER)
120-
yy_delete_buffer(YY_CURRENT_BUFFER);
121-
122142
/*
123143
* Make a scan buffer with special termination needed by flex.
124144
*/
125-
scanbuflen = slen;
126145
scanbuf = pg_malloc(slen + 2);
127146
memcpy(scanbuf, str, slen);
128147
scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
129-
scanbufhandle = yy_scan_buffer(scanbuf, slen + 2);
148+
scanbufhandle = yy_scan_buffer(scanbuf, slen + 2, yyscanner);
130149

131-
BEGIN(INITIAL);
150+
return yyscanner;
132151
}
133152

134153

135154
/*
136-
* Called after parsing is done to clean up after seg_scanner_init()
155+
* Called after parsing is done to clean up after expr_scanner_init()
137156
*/
138157
void
139-
expr_scanner_finish(void)
158+
expr_scanner_finish(yyscan_t yyscanner)
140159
{
141-
yy_delete_buffer(scanbufhandle);
160+
yy_delete_buffer(scanbufhandle, yyscanner);
142161
pg_free(scanbuf);
162+
yylex_destroy(yyscanner);
163+
143164
expr_source = NULL;
144165
expr_lineno = 0;
145166
expr_full_line = NULL;

src/bin/pgbench/pgbench.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2495,25 +2495,30 @@ process_commands(char *buf, const char *source, const int lineno)
24952495
}
24962496
else if (pg_strcasecmp(my_commands->argv[0], "set") == 0)
24972497
{
2498+
yyscan_t yyscanner;
2499+
24982500
if (my_commands->argc < 3)
24992501
{
25002502
syntax_error(source, lineno, my_commands->line, my_commands->argv[0],
25012503
"missing argument", NULL, -1);
25022504
}
25032505

2504-
expr_scanner_init(my_commands->argv[2], source, lineno,
2505-
my_commands->line, my_commands->argv[0],
2506-
my_commands->cols[2] - 1);
2506+
yyscanner = expr_scanner_init(my_commands->argv[2],
2507+
source,
2508+
lineno,
2509+
my_commands->line,
2510+
my_commands->argv[0],
2511+
my_commands->cols[2] - 1);
25072512

2508-
if (expr_yyparse() != 0)
2513+
if (expr_yyparse(yyscanner) != 0)
25092514
{
25102515
/* dead code: exit done from syntax_error called by yyerror */
25112516
exit(1);
25122517
}
25132518

25142519
my_commands->expr = expr_parse_result;
25152520

2516-
expr_scanner_finish();
2521+
expr_scanner_finish(yyscanner);
25172522
}
25182523
else if (pg_strcasecmp(my_commands->argv[0], "sleep") == 0)
25192524
{

src/bin/pgbench/pgbench.h

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@
1111
#ifndef PGBENCH_H
1212
#define PGBENCH_H
1313

14+
/*
15+
* This file is included outside exprscan.l, in places where we can't see
16+
* flex's definition of typedef yyscan_t. Fortunately, it's documented as
17+
* being "void *", so we can use a macro to keep the function declarations
18+
* here looking like the definitions in exprscan.l. exprparse.y also
19+
* uses this to be able to declare things as "yyscan_t".
20+
*/
21+
#define yyscan_t void *
22+
1423
/* Types of expression nodes */
1524
typedef enum PgBenchExprType
1625
{
@@ -73,17 +82,18 @@ struct PgBenchExprList
7382

7483
extern PgBenchExpr *expr_parse_result;
7584

76-
extern int expr_yyparse(void);
77-
extern int expr_yylex(void);
78-
extern void expr_yyerror(const char *str);
79-
extern void expr_yyerror_more(const char *str, const char *more);
80-
extern void expr_scanner_init(const char *str, const char *source,
81-
const int lineno, const char *line,
82-
const char *cmd, const int ecol);
85+
extern int expr_yyparse(yyscan_t yyscanner);
86+
extern int expr_yylex(yyscan_t yyscanner);
87+
extern void expr_yyerror(yyscan_t yyscanner, const char *str);
88+
extern void expr_yyerror_more(yyscan_t yyscanner, const char *str,
89+
const char *more);
90+
extern yyscan_t expr_scanner_init(const char *str, const char *source,
91+
int lineno, const char *line,
92+
const char *cmd, int ecol);
8393
extern void syntax_error(const char *source, const int lineno, const char *line,
8494
const char *cmd, const char *msg, const char *more,
8595
const int col);
86-
extern void expr_scanner_finish(void);
96+
extern void expr_scanner_finish(yyscan_t yyscanner);
8797

8898
extern int64 strtoint64(const char *str);
8999

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy