2 /*-------------------------------------------------------------------------
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"
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
);
43 %name
-prefix
="expr_yy"
45 %parse
-param
{yyscan_t yyscanner
}
46 %lex
-param
{yyscan_t yyscanner
}
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 */
74 %nonassoc IS_OP ISNULL_OP NOTNULL_OP
75 %nonassoc
'<' '>' '=' LE_OP GE_OP NE_OP
76 %left
'|' '#' '&' LS_OP RS_OP
'~'
84 expr_parse_result
= $1;
85 (void) yynerrs; /* suppress compiler warning */
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); }
124 | expr ISNULL_OP
{ $$
= make_op
(yyscanner
, "!is", $1, make_null_constant
()); }
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)));
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); }
150 | VARIABLE
{ $$
= make_variable
($1); }
151 | function
'(' elist
')' { $$
= make_func
(yyscanner
, $1, $3); }
152 | case_control
{ $$
= $1; }
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
)); }
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); }
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;
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
;
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
;
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
;
213 make_variable
(char *varname
)
215 PgBenchExpr
*expr
= pg_malloc
(sizeof
(PgBenchExpr
));
217 expr
->etype
= ENODE_VARIABLE
;
218 expr
->u.variable.varname
= varname
;
222 /* binary operators */
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
)));
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
255 } PGBENCH_FUNCTIONS
[] =
257 /* parsed as operators, executed as functions */
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
290 "sqrt", 1, PGBENCH_SQRT
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
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 */
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 */
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.
393 find_func
(yyscan_t yyscanner
, const char *fname
)
397 while
(PGBENCH_FUNCTIONS
[i
].fname
)
399 if
(pg_strcasecmp
(fname
, PGBENCH_FUNCTIONS
[i
].fname
) == 0)
404 expr_yyerror_more
(yyscanner
, "unexpected function name", fname
);
410 /* Expression linked list builder */
411 static PgBenchExprList
*
412 make_elist
(PgBenchExpr
*expr
, PgBenchExprList
*list
)
414 PgBenchExprLink
*cons
;
418 list
= pg_malloc
(sizeof
(PgBenchExprList
));
423 cons
= pg_malloc
(sizeof
(PgBenchExprLink
));
427 if
(list
->head
== NULL
)
430 list
->tail
->next
= cons
;
437 /* Return the length of an expression list */
439 elist_length
(PgBenchExprList
*list
)
441 PgBenchExprLink
*link
= list
!= NULL ? list
->head
: NULL
;
444 for
(; link
!= NULL
; link
= link
->next
)
450 /* Build function call expression */
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
:
466 expr_yyerror_more
(yyscanner
, "at least one argument expected",
467 PGBENCH_FUNCTIONS
[fnumber
].fname
);
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");
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
);
487 PgBenchExpr
*var
= make_variable
("default_seed");
488 args
= make_elist
(var
, args
);
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
);
500 PgBenchExpr
*var
= make_variable
("default_seed");
501 args
= make_elist
(var
, args
);
505 /* common case: positive arguments number */
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
;
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
));