Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7e137f8

Browse files
committed
Extend pgbench's expression syntax to support a few built-in functions.
Fabien Coelho, reviewed mostly by Michael Paquier and me, but also byHeikki Linnakangas, BeomYong Lee, Kyotaro Horiguchi, OleksanderShulgin, and Álvaro Herrera.
1 parentbd6cf3f commit7e137f8

File tree

5 files changed

+409
-97
lines changed

5 files changed

+409
-97
lines changed

‎doc/src/sgml/ref/pgbench.sgml

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
786786
</para>
787787

788788
<variablelist>
789-
<varlistentry>
789+
<varlistentry id='pgbench-metacommand-set'>
790790
<term>
791791
<literal>\set <replaceable>varname</> <replaceable>expression</></literal>
792792
</term>
@@ -798,8 +798,10 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
798798
The expression may contain integer constants such as <literal>5432</>,
799799
references to variables <literal>:</><replaceable>variablename</>,
800800
and expressions composed of unary (<literal>-</>) or binary operators
801-
(<literal>+</>, <literal>-</>, <literal>*</>, <literal>/</>, <literal>%</>)
802-
with their usual associativity, and parentheses.
801+
(<literal>+</>, <literal>-</>, <literal>*</>, <literal>/</>,
802+
<literal>%</>) with their usual associativity,
803+
<link linkend="pgbench-builtin-functions">function calls</>, and
804+
parentheses.
803805
</para>
804806

805807
<para>
@@ -994,6 +996,62 @@ END;
994996

995997
</refsect2>
996998

999+
<refsect2 id="pgbench-builtin-functions">
1000+
<title>Built-In Functions</title>
1001+
1002+
<para>
1003+
The following functions are built into <application>pgbench</> and
1004+
may be used in conjunction with
1005+
<link linkend="pgbench-metacommand-set"><literal>\set</literal></link>.
1006+
</para>
1007+
1008+
<!-- list pgbench functions in alphabetical order -->
1009+
<table>
1010+
<title>pgbench Functions</title>
1011+
<tgroup cols="5">
1012+
<thead>
1013+
<row>
1014+
<entry>Function</entry>
1015+
<entry>Return Type</entry>
1016+
<entry>Description</entry>
1017+
<entry>Example</entry>
1018+
<entry>Result</entry>
1019+
</row>
1020+
</thead>
1021+
<tbody>
1022+
<row>
1023+
<entry><literal><function>abs(<replaceable>a</>)</></></>
1024+
<entry>same as <replaceable>a</></>
1025+
<entry>integer value</>
1026+
<entry><literal>abs(-17)</></>
1027+
<entry><literal>17</></>
1028+
</row>
1029+
<row>
1030+
<entry><literal><function>debug(<replaceable>a</>)</></></>
1031+
<entry>same as <replaceable>a</> </>
1032+
<entry>print to <systemitem>stderr</systemitem> the given argument</>
1033+
<entry><literal>debug(5432)</></>
1034+
<entry><literal>5432</></>
1035+
</row>
1036+
<row>
1037+
<entry><literal><function>max(<replaceable>i</> [, <replaceable>...</> ] )</></></>
1038+
<entry>integer</>
1039+
<entry>maximum value</>
1040+
<entry><literal>max(5, 4, 3, 2)</></>
1041+
<entry><literal>5</></>
1042+
</row>
1043+
<row>
1044+
<entry><literal><function>min(<replaceable>i</> [, <replaceable>...</> ] )</></></>
1045+
<entry>integer</>
1046+
<entry>minimum value</>
1047+
<entry><literal>min(5, 4, 3, 2)</></>
1048+
<entry><literal>2</></>
1049+
</row>
1050+
</tbody>
1051+
</tgroup>
1052+
</table>
1053+
</refsect2>
1054+
9971055
<refsect2>
9981056
<title>Per-Transaction Logging</title>
9991057

‎src/bin/pgbench/exprparse.y

Lines changed: 146 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@
1616

1717
PgBenchExpr *expr_parse_result;
1818

19+
static PgBenchExprList *make_elist(PgBenchExpr *exp, PgBenchExprList *list);
1920
static PgBenchExpr *make_integer_constant(int64 ival);
2021
static PgBenchExpr *make_variable(char *varname);
21-
static PgBenchExpr *make_op(charoperator, PgBenchExpr *lexpr,
22+
static PgBenchExpr *make_op(constchar*operator, PgBenchExpr *lexpr,
2223
PgBenchExpr *rexpr);
24+
staticintfind_func(constchar *fname);
25+
static PgBenchExpr *make_func(constint fnumber, PgBenchExprList *args);
2326

2427
%}
2528

@@ -31,13 +34,15 @@ static PgBenchExpr *make_op(char operator, PgBenchExpr *lexpr,
3134
int64ival;
3235
char *str;
3336
PgBenchExpr *expr;
37+
PgBenchExprList *elist;
3438
}
3539

40+
%type<elist>elist
3641
%type<expr>expr
37-
%type<ival>INTEGER
38-
%type<str>VARIABLE
42+
%type<ival>INTEGERfunction
43+
%type<str>VARIABLEFUNCTION
3944

40-
%tokenINTEGERVARIABLE
45+
%tokenINTEGERVARIABLEFUNCTION
4146
%tokenCHAR_ERROR/* never used, will raise a syntax error*/
4247

4348
/* Precedence: lowest to highest*/
@@ -49,16 +54,25 @@ static PgBenchExpr *make_op(char operator, PgBenchExpr *lexpr,
4954

5055
result:expr{ expr_parse_result =$1; }
5156

57+
elist: {$$ =NULL; }
58+
|expr {$$ = make_elist($1,NULL); }
59+
|elist','expr{$$ = make_elist($3,$1); }
60+
;
61+
5262
expr:'('expr')'{$$ =$2; }
5363
|'+'expr %precUMINUS{$$ =$2; }
54-
|'-'expr %precUMINUS{$$ = make_op('-', make_integer_constant(0),$2); }
55-
|expr'+'expr{$$ = make_op('+',$1,$3); }
56-
|expr'-'expr{$$ = make_op('-',$1,$3); }
57-
|expr'*'expr{$$ = make_op('*',$1,$3); }
58-
|expr'/'expr{$$ = make_op('/',$1,$3); }
59-
|expr'%'expr{$$ = make_op('%',$1,$3); }
64+
|'-'expr %precUMINUS{$$ = 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); }
6070
|INTEGER{$$ = make_integer_constant($1); }
6171
|VARIABLE {$$ = make_variable($1); }
72+
|function'('elist')'{$$ = make_func($1,$3); }
73+
;
74+
75+
function:FUNCTION{$$ = find_func($1); pg_free($1); }
6276
;
6377

6478
%%
@@ -84,14 +98,131 @@ make_variable(char *varname)
8498
}
8599

86100
static PgBenchExpr *
87-
make_op(charoperator, PgBenchExpr *lexpr, PgBenchExpr *rexpr)
101+
make_op(constchar *operator, PgBenchExpr *lexpr, PgBenchExpr *rexpr)
102+
{
103+
returnmake_func(find_func(operator),
104+
make_elist(rexpr,make_elist(lexpr,NULL)));
105+
}
106+
107+
/*
108+
* List of available functions:
109+
* - fname: function name
110+
* - nargs: number of arguments
111+
* -1 is a special value for min & max meaning #args >= 1
112+
* - tag: function identifier from PgBenchFunction enum
113+
*/
114+
staticstruct
115+
{
116+
char * fname;
117+
int nargs;
118+
PgBenchFunction tag;
119+
} PGBENCH_FUNCTIONS[] = {
120+
/* parsed as operators, executed as functions*/
121+
{"+",2, PGBENCH_ADD },
122+
{"-",2, PGBENCH_SUB },
123+
{"*",2, PGBENCH_MUL },
124+
{"/",2, PGBENCH_DIV },
125+
{"%",2, PGBENCH_MOD },
126+
/* actual functions*/
127+
{"abs",1, PGBENCH_ABS },
128+
{"min", -1, PGBENCH_MIN },
129+
{"max", -1, PGBENCH_MAX },
130+
{"debug",1, PGBENCH_DEBUG },
131+
/* keep as last array element*/
132+
{NULL,0,0 }
133+
};
134+
135+
/*
136+
* Find a function from its name
137+
*
138+
* return the index of the function from the PGBENCH_FUNCTIONS array
139+
* or fail if the function is unknown.
140+
*/
141+
staticint
142+
find_func(constchar * fname)
143+
{
144+
int i =0;
145+
146+
while (PGBENCH_FUNCTIONS[i].fname)
147+
{
148+
if (pg_strcasecmp(fname, PGBENCH_FUNCTIONS[i].fname) ==0)
149+
return i;
150+
i++;
151+
}
152+
153+
expr_yyerror_more("unexpected function name", fname);
154+
155+
/* not reached*/
156+
return -1;
157+
}
158+
159+
/* Expression linked list builder*/
160+
static PgBenchExprList *
161+
make_elist(PgBenchExpr *expr, PgBenchExprList *list)
162+
{
163+
PgBenchExprLink * cons;
164+
165+
if (list ==NULL)
166+
{
167+
list =pg_malloc(sizeof(PgBenchExprList));
168+
list->head =NULL;
169+
list->tail =NULL;
170+
}
171+
172+
cons =pg_malloc(sizeof(PgBenchExprLink));
173+
cons->expr = expr;
174+
cons->next =NULL;
175+
176+
if (list->head ==NULL)
177+
list->head = cons;
178+
else
179+
list->tail->next = cons;
180+
181+
list->tail = cons;
182+
183+
return list;
184+
}
185+
186+
/* Return the length of an expression list*/
187+
staticint
188+
elist_length(PgBenchExprList *list)
189+
{
190+
PgBenchExprLink *link = list !=NULL? list->head:NULL;
191+
int len =0;
192+
193+
for (; link !=NULL; link = link->next)
194+
len++;
195+
196+
return len;
197+
}
198+
199+
/* Build function call expression*/
200+
static PgBenchExpr *
201+
make_func(constint fnumber, PgBenchExprList *args)
88202
{
89203
PgBenchExpr *expr =pg_malloc(sizeof(PgBenchExpr));
90204

91-
expr->etype = ENODE_OPERATOR;
92-
expr->u.operator.operator =operator;
93-
expr->u.operator.lexpr = lexpr;
94-
expr->u.operator.rexpr = rexpr;
205+
Assert(fnumber >=0);
206+
207+
if (PGBENCH_FUNCTIONS[fnumber].nargs >=0 &&
208+
PGBENCH_FUNCTIONS[fnumber].nargs !=elist_length(args))
209+
expr_yyerror_more("unexpected number of arguments",
210+
PGBENCH_FUNCTIONS[fnumber].fname);
211+
212+
/* check at least one arg for min & max*/
213+
if (PGBENCH_FUNCTIONS[fnumber].nargs == -1 &&
214+
elist_length(args) ==0)
215+
expr_yyerror_more("at least one argument expected",
216+
PGBENCH_FUNCTIONS[fnumber].fname);
217+
218+
expr->etype = ENODE_FUNCTION;
219+
expr->u.function.function = PGBENCH_FUNCTIONS[fnumber].tag;
220+
221+
/* only the link is used, the head/tail is not useful anymore*/
222+
expr->u.function.args = args !=NULL? args->head:NULL;
223+
if (args)
224+
pg_free(args);
225+
95226
return expr;
96227
}
97228

‎src/bin/pgbench/exprscan.l

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ space[ \t\r\f]
4646
"%"{ yycol += yyleng;return'%'; }
4747
"("{ yycol += yyleng;return'('; }
4848
")"{ yycol += yyleng;return')'; }
49+
","{ yycol += yyleng;return','; }
4950

5051
:[a-zA-Z0-9_]+{
5152
yycol += yyleng;
@@ -57,8 +58,14 @@ space[ \t\r\f]
5758
yylval.ival =strtoint64(yytext);
5859
return INTEGER;
5960
}
61+
[a-zA-Z0-9_]+ {
62+
yycol += yyleng;
63+
yylval.str =pg_strdup(yytext);
64+
return FUNCTION;
65+
}
6066

6167
[\n]{ yycol =0; yyline++; }
68+
6269
{space}+{ yycol += yyleng;/* ignore */ }
6370

6471
.{
@@ -71,10 +78,16 @@ space[ \t\r\f]
7178
%%
7279

7380
void
74-
yyerror(constchar *message)
81+
expr_yyerror_more(constchar *message,constchar *more)
7582
{
7683
syntax_error(expr_source, expr_lineno, expr_full_line, expr_command,
77-
message,NULL, expr_col + yycol);
84+
message, more, expr_col + yycol);
85+
}
86+
87+
void
88+
yyerror(constchar *message)
89+
{
90+
expr_yyerror_more(message,NULL);
7891
}
7992

8093
/*
@@ -94,6 +107,9 @@ expr_scanner_init(const char *str, const char *source,
94107
expr_command = (char *) cmd;
95108
expr_col = (int) ecol;
96109

110+
/* reset column count for this scan */
111+
yycol =0;
112+
97113
/*
98114
* Might be left over after error
99115
*/

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp