Add empty placeholder LINGUAS file for pg_combinebackup.
[pgsql.git] / src / bin / pgbench / exprparse.y
blob6cb063c98c9b5b90c3a57d667c0a340a70cc3937
1 %{
2 /*-------------------------------------------------------------------------
4 * exprparse.y
5 * bison grammar for a simple expression syntax
7 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
10 * src/bin/pgbench/exprparse.y
12 *-------------------------------------------------------------------------
15 #include "postgres_fe.h"
17 #include "pgbench.h"
19 #define PGBENCH_NARGS_VARIABLE (-1)
20 #define PGBENCH_NARGS_CASE (-2)
21 #define PGBENCH_NARGS_HASH (-3)
22 #define PGBENCH_NARGS_PERMUTE (-4)
24 PgBenchExpr *expr_parse_result;
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);
41 %pure-parser
42 %expect 0
43 %name-prefix="expr_yy"
45 %parse-param {yyscan_t yyscanner}
46 %lex-param {yyscan_t yyscanner}
48 %union
50 int64 ival;
51 double dval;
52 bool bval;
53 char *str;
54 PgBenchExpr *expr;
55 PgBenchExprList *elist;
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
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
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
83 result: expr {
84 expr_parse_result = $1;
85 (void) yynerrs; /* suppress compiler warning */
88 elist: { $$ = NULL; }
89 | expr { $$ = make_elist($1, NULL); }
90 | elist ',' expr { $$ = make_elist($3, $1); }
93 expr: '(' expr ')' { $$ = $2; }
94 | '+' expr %prec UNARY { $$ = $2; }
95 /* unary minus "-x" implemented as "0 - x" */
96 | '-' 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 { $$ = make_integer_constant(PG_INT64_MIN); }
101 /* binary ones complement "~x" implemented as 0xffff... xor x" */
102 | '~' expr { $$ = make_op(yyscanner, "#",
103 make_integer_constant(~INT64CONST(0)), $2); }
104 | NOT_OP expr { $$ = make_uop(yyscanner, "!not", $2); }
105 | expr '+' expr { $$ = make_op(yyscanner, "+", $1, $3); }
106 | expr '-' expr { $$ = make_op(yyscanner, "-", $1, $3); }
107 | expr '*' expr { $$ = make_op(yyscanner, "*", $1, $3); }
108 | expr '/' expr { $$ = make_op(yyscanner, "/", $1, $3); }
109 | expr '%' expr { $$ = make_op(yyscanner, "mod", $1, $3); }
110 | expr '<' expr { $$ = make_op(yyscanner, "<", $1, $3); }
111 | expr LE_OP expr { $$ = make_op(yyscanner, "<=", $1, $3); }
112 | expr '>' expr { $$ = make_op(yyscanner, "<", $3, $1); }
113 | expr GE_OP expr { $$ = make_op(yyscanner, "<=", $3, $1); }
114 | expr '=' expr { $$ = make_op(yyscanner, "=", $1, $3); }
115 | expr NE_OP expr { $$ = make_op(yyscanner, "<>", $1, $3); }
116 | expr '&' expr { $$ = make_op(yyscanner, "&", $1, $3); }
117 | expr '|' expr { $$ = make_op(yyscanner, "|", $1, $3); }
118 | expr '#' expr { $$ = make_op(yyscanner, "#", $1, $3); }
119 | expr LS_OP expr { $$ = make_op(yyscanner, "<<", $1, $3); }
120 | expr RS_OP expr { $$ = make_op(yyscanner, ">>", $1, $3); }
121 | expr AND_OP expr { $$ = make_op(yyscanner, "!and", $1, $3); }
122 | expr OR_OP expr { $$ = make_op(yyscanner, "!or", $1, $3); }
123 /* IS variants */
124 | expr ISNULL_OP { $$ = make_op(yyscanner, "!is", $1, make_null_constant()); }
125 | expr NOTNULL_OP {
126 $$ = make_uop(yyscanner, "!not",
127 make_op(yyscanner, "!is", $1, make_null_constant()));
129 | expr IS_OP NULL_CONST { $$ = make_op(yyscanner, "!is", $1, make_null_constant()); }
130 | expr IS_OP NOT_OP NULL_CONST
132 $$ = make_uop(yyscanner, "!not",
133 make_op(yyscanner, "!is", $1, make_null_constant()));
135 | expr IS_OP BOOLEAN_CONST
137 $$ = make_op(yyscanner, "!is", $1, make_boolean_constant($3));
139 | expr IS_OP NOT_OP BOOLEAN_CONST
141 $$ = make_uop(yyscanner, "!not",
142 make_op(yyscanner, "!is", $1, make_boolean_constant($4)));
144 /* constants */
145 | NULL_CONST { $$ = make_null_constant(); }
146 | BOOLEAN_CONST { $$ = make_boolean_constant($1); }
147 | INTEGER_CONST { $$ = make_integer_constant($1); }
148 | DOUBLE_CONST { $$ = make_double_constant($1); }
149 /* misc */
150 | VARIABLE { $$ = make_variable($1); }
151 | function '(' elist ')' { $$ = make_func(yyscanner, $1, $3); }
152 | case_control { $$ = $1; }
155 when_then_list:
156 when_then_list WHEN_KW expr THEN_KW expr { $$ = make_elist($5, make_elist($3, $1)); }
157 | WHEN_KW expr THEN_KW expr { $$ = make_elist($4, make_elist($2, NULL)); }
159 case_control:
160 CASE_KW when_then_list END_KW { $$ = make_case(yyscanner, $2, make_null_constant()); }
161 | CASE_KW when_then_list ELSE_KW expr END_KW { $$ = make_case(yyscanner, $2, $4); }
163 function: FUNCTION { $$ = find_func(yyscanner, $1); pg_free($1); }
168 static PgBenchExpr *
169 make_null_constant(void)
171 PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
173 expr->etype = ENODE_CONSTANT;
174 expr->u.constant.type = PGBT_NULL;
175 expr->u.constant.u.ival = 0;
176 return expr;
179 static PgBenchExpr *
180 make_integer_constant(int64 ival)
182 PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
184 expr->etype = ENODE_CONSTANT;
185 expr->u.constant.type = PGBT_INT;
186 expr->u.constant.u.ival = ival;
187 return expr;
190 static PgBenchExpr *
191 make_double_constant(double dval)
193 PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
195 expr->etype = ENODE_CONSTANT;
196 expr->u.constant.type = PGBT_DOUBLE;
197 expr->u.constant.u.dval = dval;
198 return expr;
201 static PgBenchExpr *
202 make_boolean_constant(bool bval)
204 PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
206 expr->etype = ENODE_CONSTANT;
207 expr->u.constant.type = PGBT_BOOLEAN;
208 expr->u.constant.u.bval = bval;
209 return expr;
212 static PgBenchExpr *
213 make_variable(char *varname)
215 PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
217 expr->etype = ENODE_VARIABLE;
218 expr->u.variable.varname = varname;
219 return expr;
222 /* binary operators */
223 static PgBenchExpr *
224 make_op(yyscan_t yyscanner, const char *operator,
225 PgBenchExpr *lexpr, PgBenchExpr *rexpr)
227 return make_func(yyscanner, find_func(yyscanner, operator),
228 make_elist(rexpr, make_elist(lexpr, NULL)));
231 /* unary operator */
232 static PgBenchExpr *
233 make_uop(yyscan_t yyscanner, const char *operator, PgBenchExpr *expr)
235 return make_func(yyscanner, find_func(yyscanner, operator), make_elist(expr, NULL));
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
250 static const struct
252 const char *fname;
253 int nargs;
254 PgBenchFunction tag;
255 } PGBENCH_FUNCTIONS[] =
257 /* parsed as operators, executed as functions */
259 "+", 2, PGBENCH_ADD
262 "-", 2, PGBENCH_SUB
265 "*", 2, PGBENCH_MUL
268 "/", 2, PGBENCH_DIV
271 "mod", 2, PGBENCH_MOD
273 /* actual functions */
275 "abs", 1, PGBENCH_ABS
278 "least", PGBENCH_NARGS_VARIABLE, PGBENCH_LEAST
281 "greatest", PGBENCH_NARGS_VARIABLE, PGBENCH_GREATEST
284 "debug", 1, PGBENCH_DEBUG
287 "pi", 0, PGBENCH_PI
290 "sqrt", 1, PGBENCH_SQRT
293 "ln", 1, PGBENCH_LN
296 "exp", 1, PGBENCH_EXP
299 "int", 1, PGBENCH_INT
302 "double", 1, PGBENCH_DOUBLE
305 "random", 2, PGBENCH_RANDOM
308 "random_gaussian", 3, PGBENCH_RANDOM_GAUSSIAN
311 "random_exponential", 3, PGBENCH_RANDOM_EXPONENTIAL
314 "random_zipfian", 3, PGBENCH_RANDOM_ZIPFIAN
317 "pow", 2, PGBENCH_POW
320 "power", 2, PGBENCH_POW
322 /* logical operators */
324 "!and", 2, PGBENCH_AND
327 "!or", 2, PGBENCH_OR
330 "!not", 1, PGBENCH_NOT
332 /* bitwise integer operators */
334 "&", 2, PGBENCH_BITAND
337 "|", 2, PGBENCH_BITOR
340 "#", 2, PGBENCH_BITXOR
343 "<<", 2, PGBENCH_LSHIFT
346 ">>", 2, PGBENCH_RSHIFT
348 /* comparison operators */
350 "=", 2, PGBENCH_EQ
353 "<>", 2, PGBENCH_NE
356 "<=", 2, PGBENCH_LE
359 "<", 2, PGBENCH_LT
362 "!is", 2, PGBENCH_IS
364 /* "case when ... then ... else ... end" construction */
366 "!case_end", PGBENCH_NARGS_CASE, PGBENCH_CASE
369 "hash", PGBENCH_NARGS_HASH, PGBENCH_HASH_MURMUR2
372 "hash_murmur2", PGBENCH_NARGS_HASH, PGBENCH_HASH_MURMUR2
375 "hash_fnv1a", PGBENCH_NARGS_HASH, PGBENCH_HASH_FNV1A
378 "permute", PGBENCH_NARGS_PERMUTE, PGBENCH_PERMUTE
380 /* keep as last array element */
382 NULL, 0, 0
387 * Find a function from its name
389 * return the index of the function from the PGBENCH_FUNCTIONS array
390 * or fail if the function is unknown.
392 static int
393 find_func(yyscan_t yyscanner, const char *fname)
395 int i = 0;
397 while (PGBENCH_FUNCTIONS[i].fname)
399 if (pg_strcasecmp(fname, PGBENCH_FUNCTIONS[i].fname) == 0)
400 return i;
401 i++;
404 expr_yyerror_more(yyscanner, "unexpected function name", fname);
406 /* not reached */
407 return -1;
410 /* Expression linked list builder */
411 static PgBenchExprList *
412 make_elist(PgBenchExpr *expr, PgBenchExprList *list)
414 PgBenchExprLink *cons;
416 if (list == NULL)
418 list = pg_malloc(sizeof(PgBenchExprList));
419 list->head = NULL;
420 list->tail = NULL;
423 cons = pg_malloc(sizeof(PgBenchExprLink));
424 cons->expr = expr;
425 cons->next = NULL;
427 if (list->head == NULL)
428 list->head = cons;
429 else
430 list->tail->next = cons;
432 list->tail = cons;
434 return list;
437 /* Return the length of an expression list */
438 static int
439 elist_length(PgBenchExprList *list)
441 PgBenchExprLink *link = list != NULL ? list->head : NULL;
442 int len = 0;
444 for (; link != NULL; link = link->next)
445 len++;
447 return len;
450 /* Build function call expression */
451 static PgBenchExpr *
452 make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *args)
454 int len = elist_length(args);
456 PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
458 Assert(fnumber >= 0);
460 /* validate arguments number including few special cases */
461 switch (PGBENCH_FUNCTIONS[fnumber].nargs)
463 /* check at least one arg for least & greatest */
464 case PGBENCH_NARGS_VARIABLE:
465 if (len == 0)
466 expr_yyerror_more(yyscanner, "at least one argument expected",
467 PGBENCH_FUNCTIONS[fnumber].fname);
468 break;
470 /* case (when ... then ...)+ (else ...)? end */
471 case PGBENCH_NARGS_CASE:
472 /* 'else' branch is always present, but could be a NULL-constant */
473 if (len < 3 || len % 2 != 1)
474 expr_yyerror_more(yyscanner,
475 "odd and >= 3 number of arguments expected",
476 "case control structure");
477 break;
479 /* hash functions with optional seed argument */
480 case PGBENCH_NARGS_HASH:
481 if (len < 1 || len > 2)
482 expr_yyerror_more(yyscanner, "unexpected number of arguments",
483 PGBENCH_FUNCTIONS[fnumber].fname);
485 if (len == 1)
487 PgBenchExpr *var = make_variable("default_seed");
488 args = make_elist(var, args);
490 break;
492 /* pseudorandom permutation function with optional seed argument */
493 case PGBENCH_NARGS_PERMUTE:
494 if (len < 2 || len > 3)
495 expr_yyerror_more(yyscanner, "unexpected number of arguments",
496 PGBENCH_FUNCTIONS[fnumber].fname);
498 if (len == 2)
500 PgBenchExpr *var = make_variable("default_seed");
501 args = make_elist(var, args);
503 break;
505 /* common case: positive arguments number */
506 default:
507 Assert(PGBENCH_FUNCTIONS[fnumber].nargs >= 0);
509 if (PGBENCH_FUNCTIONS[fnumber].nargs != len)
510 expr_yyerror_more(yyscanner, "unexpected number of arguments",
511 PGBENCH_FUNCTIONS[fnumber].fname);
514 expr->etype = ENODE_FUNCTION;
515 expr->u.function.function = PGBENCH_FUNCTIONS[fnumber].tag;
517 /* only the link is used, the head/tail is not useful anymore */
518 expr->u.function.args = args != NULL ? args->head : NULL;
519 if (args)
520 pg_free(args);
522 return expr;
525 static PgBenchExpr *
526 make_case(yyscan_t yyscanner, PgBenchExprList *when_then_list, PgBenchExpr *else_part)
528 return make_func(yyscanner,
529 find_func(yyscanner, "!case_end"),
530 make_elist(else_part, when_then_list));