Line data Source code
1 : %{
2 : /*-------------------------------------------------------------------------
3 : *
4 : * exprparse.y
5 : * bison grammar for a simple expression syntax
6 : *
7 : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8 : * Portions Copyright (c) 1994, Regents of the University of California
9 : *
10 : * src/bin/pgbench/exprparse.y
11 : *
12 : *-------------------------------------------------------------------------
13 : */
14 :
15 : #include "postgres_fe.h"
16 :
17 : #include "pgbench.h"
18 :
19 : #define PGBENCH_NARGS_VARIABLE (-1)
20 : #define PGBENCH_NARGS_CASE (-2)
21 : #define PGBENCH_NARGS_HASH (-3)
22 : #define PGBENCH_NARGS_PERMUTE (-4)
23 :
24 : PgBenchExpr *expr_parse_result;
25 :
26 : static PgBenchExprList *make_elist(PgBenchExpr *expr, PgBenchExprList *list);
27 : static PgBenchExpr *make_null_constant(void);
28 : static PgBenchExpr *make_boolean_constant(bool bval);
29 : static PgBenchExpr *make_integer_constant(int64 ival);
30 : static PgBenchExpr *make_double_constant(double dval);
31 : static PgBenchExpr *make_variable(char *varname);
32 : static PgBenchExpr *make_op(yyscan_t yyscanner, const char *operator,
33 : PgBenchExpr *lexpr, PgBenchExpr *rexpr);
34 : static PgBenchExpr *make_uop(yyscan_t yyscanner, const char *operator, PgBenchExpr *expr);
35 : static int find_func(yyscan_t yyscanner, const char *fname);
36 : static PgBenchExpr *make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *args);
37 : static PgBenchExpr *make_case(yyscan_t yyscanner, PgBenchExprList *when_then_list, PgBenchExpr *else_part);
38 :
39 : %}
40 :
41 : %pure-parser
42 : %expect 0
43 : %name-prefix="expr_yy"
44 :
45 : %parse-param {yyscan_t yyscanner}
46 : %lex-param {yyscan_t yyscanner}
47 :
48 : %union
49 : {
50 : int64 ival;
51 : double dval;
52 : bool bval;
53 : char *str;
54 : PgBenchExpr *expr;
55 : PgBenchExprList *elist;
56 : }
57 :
58 : %type <elist> elist when_then_list
59 : %type <expr> expr case_control
60 : %type <ival> INTEGER_CONST function
61 : %type <dval> DOUBLE_CONST
62 : %type <bval> BOOLEAN_CONST
63 : %type <str> VARIABLE FUNCTION
64 :
65 : %token NULL_CONST INTEGER_CONST MAXINT_PLUS_ONE_CONST DOUBLE_CONST
66 : %token BOOLEAN_CONST VARIABLE FUNCTION
67 : %token AND_OP OR_OP NOT_OP NE_OP LE_OP GE_OP LS_OP RS_OP IS_OP
68 : %token CASE_KW WHEN_KW THEN_KW ELSE_KW END_KW
69 :
70 : /* Precedence: lowest to highest, taken from postgres SQL parser */
71 : %left OR_OP
72 : %left AND_OP
73 : %right NOT_OP
74 : %nonassoc IS_OP ISNULL_OP NOTNULL_OP
75 : %nonassoc '<' '>' '=' LE_OP GE_OP NE_OP
76 : %left '|' '#' '&' LS_OP RS_OP '~'
77 : %left '+' '-'
78 : %left '*' '/' '%'
79 : %right UNARY
80 :
81 : %%
82 :
83 : result: expr {
84 734 : expr_parse_result = $1;
85 : (void) yynerrs; /* suppress compiler warning */
86 : }
87 :
88 10 : elist: { $$ = NULL; }
89 786 : | expr { $$ = make_elist($1, NULL); }
90 686 : | elist ',' expr { $$ = make_elist($3, $1); }
91 : ;
92 :
93 104 : expr: '(' expr ')' { $$ = $2; }
94 4 : | '+' expr %prec UNARY { $$ = $2; }
95 : /* unary minus "-x" implemented as "0 - x" */
96 92 : | '-' expr %prec UNARY { $$ = make_op(yyscanner, "-",
97 : make_integer_constant(0), $2); }
98 : /* special PG_INT64_MIN handling, only after a unary minus */
99 : | '-' MAXINT_PLUS_ONE_CONST %prec UNARY
100 2 : { $$ = make_integer_constant(PG_INT64_MIN); }
101 : /* binary ones complement "~x" implemented as 0xffff... xor x" */
102 4 : | '~' expr { $$ = make_op(yyscanner, "#",
103 : make_integer_constant(~INT64CONST(0)), $2); }
104 24 : | NOT_OP expr { $$ = make_uop(yyscanner, "!not", $2); }
105 96 : | expr '+' expr { $$ = make_op(yyscanner, "+", $1, $3); }
106 36 : | expr '-' expr { $$ = make_op(yyscanner, "-", $1, $3); }
107 408 : | expr '*' expr { $$ = make_op(yyscanner, "*", $1, $3); }
108 26 : | expr '/' expr { $$ = make_op(yyscanner, "/", $1, $3); }
109 4 : | expr '%' expr { $$ = make_op(yyscanner, "mod", $1, $3); }
110 20 : | expr '<' expr { $$ = make_op(yyscanner, "<", $1, $3); }
111 8 : | expr LE_OP expr { $$ = make_op(yyscanner, "<=", $1, $3); }
112 12 : | expr '>' expr { $$ = make_op(yyscanner, "<", $3, $1); }
113 6 : | expr GE_OP expr { $$ = make_op(yyscanner, "<=", $3, $1); }
114 64 : | expr '=' expr { $$ = make_op(yyscanner, "=", $1, $3); }
115 16 : | expr NE_OP expr { $$ = make_op(yyscanner, "<>", $1, $3); }
116 2 : | expr '&' expr { $$ = make_op(yyscanner, "&", $1, $3); }
117 4 : | expr '|' expr { $$ = make_op(yyscanner, "|", $1, $3); }
118 2 : | expr '#' expr { $$ = make_op(yyscanner, "#", $1, $3); }
119 14 : | expr LS_OP expr { $$ = make_op(yyscanner, "<<", $1, $3); }
120 2 : | expr RS_OP expr { $$ = make_op(yyscanner, ">>", $1, $3); }
121 88 : | expr AND_OP expr { $$ = make_op(yyscanner, "!and", $1, $3); }
122 10 : | expr OR_OP expr { $$ = make_op(yyscanner, "!or", $1, $3); }
123 : /* IS variants */
124 2 : | expr ISNULL_OP { $$ = make_op(yyscanner, "!is", $1, make_null_constant()); }
125 : | expr NOTNULL_OP {
126 4 : $$ = make_uop(yyscanner, "!not",
127 2 : make_op(yyscanner, "!is", $1, make_null_constant()));
128 : }
129 8 : | expr IS_OP NULL_CONST { $$ = make_op(yyscanner, "!is", $1, make_null_constant()); }
130 : | expr IS_OP NOT_OP NULL_CONST
131 : {
132 8 : $$ = make_uop(yyscanner, "!not",
133 4 : make_op(yyscanner, "!is", $1, make_null_constant()));
134 : }
135 : | expr IS_OP BOOLEAN_CONST
136 : {
137 2 : $$ = make_op(yyscanner, "!is", $1, make_boolean_constant($3));
138 : }
139 : | expr IS_OP NOT_OP BOOLEAN_CONST
140 : {
141 2 : $$ = make_uop(yyscanner, "!not",
142 2 : make_op(yyscanner, "!is", $1, make_boolean_constant($4)));
143 : }
144 : /* constants */
145 12 : | NULL_CONST { $$ = make_null_constant(); }
146 40 : | BOOLEAN_CONST { $$ = make_boolean_constant($1); }
147 1588 : | INTEGER_CONST { $$ = make_integer_constant($1); }
148 122 : | DOUBLE_CONST { $$ = make_double_constant($1); }
149 : /* misc */
150 540 : | VARIABLE { $$ = make_variable($1); }
151 796 : | function '(' elist ')' { $$ = make_func(yyscanner, $1, $3); }
152 28 : | case_control { $$ = $1; }
153 : ;
154 :
155 : when_then_list:
156 4 : when_then_list WHEN_KW expr THEN_KW expr { $$ = make_elist($5, make_elist($3, $1)); }
157 28 : | WHEN_KW expr THEN_KW expr { $$ = make_elist($4, make_elist($2, NULL)); }
158 :
159 : case_control:
160 8 : CASE_KW when_then_list END_KW { $$ = make_case(yyscanner, $2, make_null_constant()); }
161 20 : | CASE_KW when_then_list ELSE_KW expr END_KW { $$ = make_case(yyscanner, $2, $4); }
162 :
163 798 : function: FUNCTION { $$ = find_func(yyscanner, $1); pg_free($1); }
164 : ;
165 :
166 : %%
167 :
168 : static PgBenchExpr *
169 36 : make_null_constant(void)
170 : {
171 36 : PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
172 :
173 36 : expr->etype = ENODE_CONSTANT;
174 36 : expr->u.constant.type = PGBT_NULL;
175 36 : expr->u.constant.u.ival = 0;
176 36 : return expr;
177 : }
178 :
179 : static PgBenchExpr *
180 1686 : make_integer_constant(int64 ival)
181 : {
182 1686 : PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
183 :
184 1686 : expr->etype = ENODE_CONSTANT;
185 1686 : expr->u.constant.type = PGBT_INT;
186 1686 : expr->u.constant.u.ival = ival;
187 1686 : return expr;
188 : }
189 :
190 : static PgBenchExpr *
191 122 : make_double_constant(double dval)
192 : {
193 122 : PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
194 :
195 122 : expr->etype = ENODE_CONSTANT;
196 122 : expr->u.constant.type = PGBT_DOUBLE;
197 122 : expr->u.constant.u.dval = dval;
198 122 : return expr;
199 : }
200 :
201 : static PgBenchExpr *
202 44 : make_boolean_constant(bool bval)
203 : {
204 44 : PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
205 :
206 44 : expr->etype = ENODE_CONSTANT;
207 44 : expr->u.constant.type = PGBT_BOOLEAN;
208 44 : expr->u.constant.u.bval = bval;
209 44 : return expr;
210 : }
211 :
212 : static PgBenchExpr *
213 614 : make_variable(char *varname)
214 : {
215 614 : PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
216 :
217 614 : expr->etype = ENODE_VARIABLE;
218 614 : expr->u.variable.varname = varname;
219 614 : return expr;
220 : }
221 :
222 : /* binary operators */
223 : static PgBenchExpr *
224 934 : make_op(yyscan_t yyscanner, const char *operator,
225 : PgBenchExpr *lexpr, PgBenchExpr *rexpr)
226 : {
227 934 : return make_func(yyscanner, find_func(yyscanner, operator),
228 : make_elist(rexpr, make_elist(lexpr, NULL)));
229 : }
230 :
231 : /* unary operator */
232 : static PgBenchExpr *
233 32 : make_uop(yyscan_t yyscanner, const char *operator, PgBenchExpr *expr)
234 : {
235 32 : return make_func(yyscanner, find_func(yyscanner, operator), make_elist(expr, NULL));
236 : }
237 :
238 : /*
239 : * List of available functions:
240 : * - fname: function name, "!..." for special internal functions
241 : * - nargs: number of arguments. Special cases:
242 : * - PGBENCH_NARGS_VARIABLE is a special value for least & greatest
243 : * meaning #args >= 1;
244 : * - PGBENCH_NARGS_CASE is for the "CASE WHEN ..." function, which
245 : * has #args >= 3 and odd;
246 : * - PGBENCH_NARGS_HASH is for hash functions, which have one required
247 : * and one optional argument;
248 : * - tag: function identifier from PgBenchFunction enum
249 : */
250 : static const struct
251 : {
252 : const char *fname;
253 : int nargs;
254 : PgBenchFunction tag;
255 : } PGBENCH_FUNCTIONS[] =
256 : {
257 : /* parsed as operators, executed as functions */
258 : {
259 : "+", 2, PGBENCH_ADD
260 : },
261 : {
262 : "-", 2, PGBENCH_SUB
263 : },
264 : {
265 : "*", 2, PGBENCH_MUL
266 : },
267 : {
268 : "/", 2, PGBENCH_DIV
269 : },
270 : {
271 : "mod", 2, PGBENCH_MOD
272 : },
273 : /* actual functions */
274 : {
275 : "abs", 1, PGBENCH_ABS
276 : },
277 : {
278 : "least", PGBENCH_NARGS_VARIABLE, PGBENCH_LEAST
279 : },
280 : {
281 : "greatest", PGBENCH_NARGS_VARIABLE, PGBENCH_GREATEST
282 : },
283 : {
284 : "debug", 1, PGBENCH_DEBUG
285 : },
286 : {
287 : "pi", 0, PGBENCH_PI
288 : },
289 : {
290 : "sqrt", 1, PGBENCH_SQRT
291 : },
292 : {
293 : "ln", 1, PGBENCH_LN
294 : },
295 : {
296 : "exp", 1, PGBENCH_EXP
297 : },
298 : {
299 : "int", 1, PGBENCH_INT
300 : },
301 : {
302 : "double", 1, PGBENCH_DOUBLE
303 : },
304 : {
305 : "random", 2, PGBENCH_RANDOM
306 : },
307 : {
308 : "random_gaussian", 3, PGBENCH_RANDOM_GAUSSIAN
309 : },
310 : {
311 : "random_exponential", 3, PGBENCH_RANDOM_EXPONENTIAL
312 : },
313 : {
314 : "random_zipfian", 3, PGBENCH_RANDOM_ZIPFIAN
315 : },
316 : {
317 : "pow", 2, PGBENCH_POW
318 : },
319 : {
320 : "power", 2, PGBENCH_POW
321 : },
322 : /* logical operators */
323 : {
324 : "!and", 2, PGBENCH_AND
325 : },
326 : {
327 : "!or", 2, PGBENCH_OR
328 : },
329 : {
330 : "!not", 1, PGBENCH_NOT
331 : },
332 : /* bitwise integer operators */
333 : {
334 : "&", 2, PGBENCH_BITAND
335 : },
336 : {
337 : "|", 2, PGBENCH_BITOR
338 : },
339 : {
340 : "#", 2, PGBENCH_BITXOR
341 : },
342 : {
343 : "<<", 2, PGBENCH_LSHIFT
344 : },
345 : {
346 : ">>", 2, PGBENCH_RSHIFT
347 : },
348 : /* comparison operators */
349 : {
350 : "=", 2, PGBENCH_EQ
351 : },
352 : {
353 : "<>", 2, PGBENCH_NE
354 : },
355 : {
356 : "<=", 2, PGBENCH_LE
357 : },
358 : {
359 : "<", 2, PGBENCH_LT
360 : },
361 : {
362 : "!is", 2, PGBENCH_IS
363 : },
364 : /* "case when ... then ... else ... end" construction */
365 : {
366 : "!case_end", PGBENCH_NARGS_CASE, PGBENCH_CASE
367 : },
368 : {
369 : "hash", PGBENCH_NARGS_HASH, PGBENCH_HASH_MURMUR2
370 : },
371 : {
372 : "hash_murmur2", PGBENCH_NARGS_HASH, PGBENCH_HASH_MURMUR2
373 : },
374 : {
375 : "hash_fnv1a", PGBENCH_NARGS_HASH, PGBENCH_HASH_FNV1A
376 : },
377 : {
378 : "permute", PGBENCH_NARGS_PERMUTE, PGBENCH_PERMUTE
379 : },
380 : /* keep as last array element */
381 : {
382 : NULL, 0, 0
383 : }
384 : };
385 :
386 : /*
387 : * Find a function from its name
388 : *
389 : * return the index of the function from the PGBENCH_FUNCTIONS array
390 : * or fail if the function is unknown.
391 : */
392 : static int
393 1792 : find_func(yyscan_t yyscanner, const char *fname)
394 : {
395 1792 : int i = 0;
396 :
397 24980 : while (PGBENCH_FUNCTIONS[i].fname)
398 : {
399 24978 : if (pg_strcasecmp(fname, PGBENCH_FUNCTIONS[i].fname) == 0)
400 1790 : return i;
401 23188 : i++;
402 : }
403 :
404 2 : expr_yyerror_more(yyscanner, "unexpected function name", fname);
405 :
406 : /* not reached */
407 : return -1;
408 : }
409 :
410 : /* Expression linked list builder */
411 : static PgBenchExprList *
412 3538 : make_elist(PgBenchExpr *expr, PgBenchExprList *list)
413 : {
414 : PgBenchExprLink *cons;
415 :
416 3538 : if (list == NULL)
417 : {
418 1780 : list = pg_malloc(sizeof(PgBenchExprList));
419 1780 : list->head = NULL;
420 1780 : list->tail = NULL;
421 : }
422 :
423 3538 : cons = pg_malloc(sizeof(PgBenchExprLink));
424 3538 : cons->expr = expr;
425 3538 : cons->next = NULL;
426 :
427 3538 : if (list->head == NULL)
428 1780 : list->head = cons;
429 : else
430 1758 : list->tail->next = cons;
431 :
432 3538 : list->tail = cons;
433 :
434 3538 : return list;
435 : }
436 :
437 : /* Return the length of an expression list */
438 : static int
439 1790 : elist_length(PgBenchExprList *list)
440 : {
441 1790 : PgBenchExprLink *link = list != NULL ? list->head : NULL;
442 1790 : int len = 0;
443 :
444 5254 : for (; link != NULL; link = link->next)
445 3464 : len++;
446 :
447 1790 : return len;
448 : }
449 :
450 : /* Build function call expression */
451 : static PgBenchExpr *
452 1790 : make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *args)
453 : {
454 1790 : int len = elist_length(args);
455 :
456 1790 : PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
457 :
458 : Assert(fnumber >= 0);
459 :
460 : /* validate arguments number including few special cases */
461 1790 : switch (PGBENCH_FUNCTIONS[fnumber].nargs)
462 : {
463 : /* check at least one arg for least & greatest */
464 16 : case PGBENCH_NARGS_VARIABLE:
465 16 : if (len == 0)
466 6 : expr_yyerror_more(yyscanner, "at least one argument expected",
467 : PGBENCH_FUNCTIONS[fnumber].fname);
468 10 : break;
469 :
470 : /* case (when ... then ...)+ (else ...)? end */
471 28 : case PGBENCH_NARGS_CASE:
472 : /* 'else' branch is always present, but could be a NULL-constant */
473 28 : if (len < 3 || len % 2 != 1)
474 0 : expr_yyerror_more(yyscanner,
475 : "odd and >= 3 number of arguments expected",
476 : "case control structure");
477 28 : break;
478 :
479 : /* hash functions with optional seed argument */
480 16 : case PGBENCH_NARGS_HASH:
481 16 : if (len < 1 || len > 2)
482 4 : expr_yyerror_more(yyscanner, "unexpected number of arguments",
483 : PGBENCH_FUNCTIONS[fnumber].fname);
484 :
485 12 : if (len == 1)
486 : {
487 4 : PgBenchExpr *var = make_variable("default_seed");
488 4 : args = make_elist(var, args);
489 : }
490 12 : break;
491 :
492 : /* pseudorandom permutation function with optional seed argument */
493 96 : case PGBENCH_NARGS_PERMUTE:
494 96 : if (len < 2 || len > 3)
495 4 : expr_yyerror_more(yyscanner, "unexpected number of arguments",
496 : PGBENCH_FUNCTIONS[fnumber].fname);
497 :
498 92 : if (len == 2)
499 : {
500 70 : PgBenchExpr *var = make_variable("default_seed");
501 70 : args = make_elist(var, args);
502 : }
503 92 : break;
504 :
505 : /* common case: positive arguments number */
506 1634 : default:
507 : Assert(PGBENCH_FUNCTIONS[fnumber].nargs >= 0);
508 :
509 1634 : if (PGBENCH_FUNCTIONS[fnumber].nargs != len)
510 2 : expr_yyerror_more(yyscanner, "unexpected number of arguments",
511 : PGBENCH_FUNCTIONS[fnumber].fname);
512 : }
513 :
514 1774 : expr->etype = ENODE_FUNCTION;
515 1774 : expr->u.function.function = PGBENCH_FUNCTIONS[fnumber].tag;
516 :
517 : /* only the link is used, the head/tail is not useful anymore */
518 1774 : expr->u.function.args = args != NULL ? args->head : NULL;
519 1774 : if (args)
520 1772 : pg_free(args);
521 :
522 1774 : return expr;
523 : }
524 :
525 : static PgBenchExpr *
526 28 : make_case(yyscan_t yyscanner, PgBenchExprList *when_then_list, PgBenchExpr *else_part)
527 : {
528 28 : return make_func(yyscanner,
529 : find_func(yyscanner, "!case_end"),
530 : make_elist(else_part, when_then_list));
531 : }
|