Age Owner Branch data TLA 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 {
572 tgl@sss.pgh.pa.us 84 :CBC 367 : expr_parse_result = $1;
85 : : (void) yynerrs; /* suppress compiler warning */
86 : : }
87 : :
2287 teodor@sigaev.ru 88 : 5 : elist: { $$ = NULL; }
89 : 393 : | expr { $$ = make_elist($1, NULL); }
2966 rhaas@postgresql.org 90 : 343 : | elist ',' expr { $$ = make_elist($3, $1); }
91 : : ;
92 : :
3331 93 : 52 : expr: '(' expr ')' { $$ = $2; }
2287 teodor@sigaev.ru 94 : 2 : | '+' expr %prec UNARY { $$ = $2; }
95 : : /* unary minus "-x" implemented as "0 - x" */
96 : 46 : | '-' 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
2026 andres@anarazel.de 100 : 1 : { $$ = make_integer_constant(PG_INT64_MIN); }
101 : : /* binary ones complement "~x" implemented as 0xffff... xor x" */
2287 teodor@sigaev.ru 102 : 2 : | '~' expr { $$ = make_op(yyscanner, "#",
103 : : make_integer_constant(~INT64CONST(0)), $2); }
104 : 12 : | NOT_OP expr { $$ = make_uop(yyscanner, "!not", $2); }
2948 tgl@sss.pgh.pa.us 105 : 48 : | expr '+' expr { $$ = make_op(yyscanner, "+", $1, $3); }
106 : 18 : | expr '-' expr { $$ = make_op(yyscanner, "-", $1, $3); }
107 : 204 : | expr '*' expr { $$ = make_op(yyscanner, "*", $1, $3); }
108 : 13 : | expr '/' expr { $$ = make_op(yyscanner, "/", $1, $3); }
2287 teodor@sigaev.ru 109 : 2 : | expr '%' expr { $$ = make_op(yyscanner, "mod", $1, $3); }
110 : 10 : | expr '<' expr { $$ = make_op(yyscanner, "<", $1, $3); }
111 : 4 : | expr LE_OP expr { $$ = make_op(yyscanner, "<=", $1, $3); }
112 : 6 : | expr '>' expr { $$ = make_op(yyscanner, "<", $3, $1); }
113 : 3 : | expr GE_OP expr { $$ = make_op(yyscanner, "<=", $3, $1); }
114 : 32 : | expr '=' expr { $$ = make_op(yyscanner, "=", $1, $3); }
115 : 8 : | expr NE_OP expr { $$ = make_op(yyscanner, "<>", $1, $3); }
116 : 1 : | expr '&' expr { $$ = make_op(yyscanner, "&", $1, $3); }
117 : 2 : | expr '|' expr { $$ = make_op(yyscanner, "|", $1, $3); }
118 : 1 : | expr '#' expr { $$ = make_op(yyscanner, "#", $1, $3); }
119 : 7 : | expr LS_OP expr { $$ = make_op(yyscanner, "<<", $1, $3); }
120 : 1 : | expr RS_OP expr { $$ = make_op(yyscanner, ">>", $1, $3); }
121 : 44 : | expr AND_OP expr { $$ = make_op(yyscanner, "!and", $1, $3); }
122 : 5 : | expr OR_OP expr { $$ = make_op(yyscanner, "!or", $1, $3); }
123 : : /* IS variants */
124 : 1 : | expr ISNULL_OP { $$ = make_op(yyscanner, "!is", $1, make_null_constant()); }
125 : : | expr NOTNULL_OP {
126 : 2 : $$ = make_uop(yyscanner, "!not",
127 : 1 : make_op(yyscanner, "!is", $1, make_null_constant()));
128 : : }
129 : 4 : | expr IS_OP NULL_CONST { $$ = make_op(yyscanner, "!is", $1, make_null_constant()); }
130 : : | expr IS_OP NOT_OP NULL_CONST
131 : : {
132 : 4 : $$ = make_uop(yyscanner, "!not",
133 : 2 : make_op(yyscanner, "!is", $1, make_null_constant()));
134 : : }
135 : : | expr IS_OP BOOLEAN_CONST
136 : : {
137 : 1 : $$ = make_op(yyscanner, "!is", $1, make_boolean_constant($3));
138 : : }
139 : : | expr IS_OP NOT_OP BOOLEAN_CONST
140 : : {
141 : 1 : $$ = make_uop(yyscanner, "!not",
142 : 1 : make_op(yyscanner, "!is", $1, make_boolean_constant($4)));
143 : : }
144 : : /* constants */
145 : 6 : | NULL_CONST { $$ = make_null_constant(); }
146 : 20 : | BOOLEAN_CONST { $$ = make_boolean_constant($1); }
2938 tgl@sss.pgh.pa.us 147 : 794 : | INTEGER_CONST { $$ = make_integer_constant($1); }
148 : 61 : | DOUBLE_CONST { $$ = make_double_constant($1); }
149 : : /* misc */
2287 teodor@sigaev.ru 150 : 270 : | VARIABLE { $$ = make_variable($1); }
2948 tgl@sss.pgh.pa.us 151 : 398 : | function '(' elist ')' { $$ = make_func(yyscanner, $1, $3); }
2287 teodor@sigaev.ru 152 : 14 : | case_control { $$ = $1; }
153 : : ;
154 : :
155 : : when_then_list:
156 : 2 : when_then_list WHEN_KW expr THEN_KW expr { $$ = make_elist($5, make_elist($3, $1)); }
157 : 14 : | WHEN_KW expr THEN_KW expr { $$ = make_elist($4, make_elist($2, NULL)); }
158 : :
159 : : case_control:
160 : 4 : CASE_KW when_then_list END_KW { $$ = make_case(yyscanner, $2, make_null_constant()); }
161 : 10 : | CASE_KW when_then_list ELSE_KW expr END_KW { $$ = make_case(yyscanner, $2, $4); }
162 : :
2948 tgl@sss.pgh.pa.us 163 : 399 : function: FUNCTION { $$ = find_func(yyscanner, $1); pg_free($1); }
164 : : ;
165 : :
166 : : %%
167 : :
168 : : static PgBenchExpr *
2287 teodor@sigaev.ru 169 : 18 : make_null_constant(void)
170 : : {
171 : 18 : PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
172 : :
173 : 18 : expr->etype = ENODE_CONSTANT;
174 : 18 : expr->u.constant.type = PGBT_NULL;
175 : 18 : expr->u.constant.u.ival = 0;
176 : 18 : return expr;
177 : : }
178 : :
179 : : static PgBenchExpr *
3331 rhaas@postgresql.org 180 : 843 : make_integer_constant(int64 ival)
181 : : {
182 : 843 : PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
183 : :
2939 184 : 843 : expr->etype = ENODE_CONSTANT;
185 : 843 : expr->u.constant.type = PGBT_INT;
186 : 843 : expr->u.constant.u.ival = ival;
187 : 843 : return expr;
188 : : }
189 : :
190 : : static PgBenchExpr *
191 : 61 : make_double_constant(double dval)
192 : : {
193 : 61 : PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
194 : :
195 : 61 : expr->etype = ENODE_CONSTANT;
196 : 61 : expr->u.constant.type = PGBT_DOUBLE;
197 : 61 : expr->u.constant.u.dval = dval;
3331 198 : 61 : return expr;
199 : : }
200 : :
201 : : static PgBenchExpr *
2287 teodor@sigaev.ru 202 : 22 : make_boolean_constant(bool bval)
203 : : {
204 : 22 : PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
205 : :
206 : 22 : expr->etype = ENODE_CONSTANT;
207 : 22 : expr->u.constant.type = PGBT_BOOLEAN;
208 : 22 : expr->u.constant.u.bval = bval;
209 : 22 : return expr;
210 : : }
211 : :
212 : : static PgBenchExpr *
3331 rhaas@postgresql.org 213 : 307 : make_variable(char *varname)
214 : : {
215 : 307 : PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
216 : :
217 : 307 : expr->etype = ENODE_VARIABLE;
218 : 307 : expr->u.variable.varname = varname;
219 : 307 : return expr;
220 : : }
221 : :
222 : : /* binary operators */
223 : : static PgBenchExpr *
2948 tgl@sss.pgh.pa.us 224 : 467 : make_op(yyscan_t yyscanner, const char *operator,
225 : : PgBenchExpr *lexpr, PgBenchExpr *rexpr)
226 : : {
227 : 467 : return make_func(yyscanner, find_func(yyscanner, operator),
228 : : make_elist(rexpr, make_elist(lexpr, NULL)));
229 : : }
230 : :
231 : : /* unary operator */
232 : : static PgBenchExpr *
2287 teodor@sigaev.ru 233 : 16 : make_uop(yyscan_t yyscanner, const char *operator, PgBenchExpr *expr)
234 : : {
235 : 16 : 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
2948 tgl@sss.pgh.pa.us 393 : 896 : find_func(yyscan_t yyscanner, const char *fname)
394 : : {
2947 395 : 896 : int i = 0;
396 : :
2966 rhaas@postgresql.org 397 [ + + ]: 12490 : while (PGBENCH_FUNCTIONS[i].fname)
398 : : {
399 [ + + ]: 12489 : if (pg_strcasecmp(fname, PGBENCH_FUNCTIONS[i].fname) == 0)
400 : 895 : return i;
401 : 11594 : i++;
402 : : }
403 : :
2948 tgl@sss.pgh.pa.us 404 : 1 : 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 *
2966 rhaas@postgresql.org 412 : 1769 : make_elist(PgBenchExpr *expr, PgBenchExprList *list)
413 : : {
414 : : PgBenchExprLink *cons;
415 : :
416 [ + + ]: 1769 : if (list == NULL)
417 : : {
418 : 890 : list = pg_malloc(sizeof(PgBenchExprList));
419 : 890 : list->head = NULL;
420 : 890 : list->tail = NULL;
421 : : }
422 : :
423 : 1769 : cons = pg_malloc(sizeof(PgBenchExprLink));
424 : 1769 : cons->expr = expr;
425 : 1769 : cons->next = NULL;
426 : :
427 [ + + ]: 1769 : if (list->head == NULL)
428 : 890 : list->head = cons;
429 : : else
430 : 879 : list->tail->next = cons;
431 : :
432 : 1769 : list->tail = cons;
433 : :
434 : 1769 : return list;
435 : : }
436 : :
437 : : /* Return the length of an expression list */
438 : : static int
439 : 895 : elist_length(PgBenchExprList *list)
440 : : {
2947 tgl@sss.pgh.pa.us 441 [ + + ]: 895 : PgBenchExprLink *link = list != NULL ? list->head : NULL;
442 : 895 : int len = 0;
443 : :
2966 rhaas@postgresql.org 444 [ + + ]: 2627 : for (; link != NULL; link = link->next)
445 : 1732 : len++;
446 : :
447 : 895 : return len;
448 : : }
449 : :
450 : : /* Build function call expression */
451 : : static PgBenchExpr *
2948 tgl@sss.pgh.pa.us 452 : 895 : make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *args)
453 : : {
2216 teodor@sigaev.ru 454 : 895 : int len = elist_length(args);
455 : :
3331 rhaas@postgresql.org 456 : 895 : PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
457 : :
2966 458 [ - + ]: 895 : Assert(fnumber >= 0);
459 : :
460 : : /* validate arguments number including few special cases */
2216 teodor@sigaev.ru 461 [ + + + + : 895 : switch (PGBENCH_FUNCTIONS[fnumber].nargs)
+ ]
462 : : {
463 : : /* check at least one arg for least & greatest */
464 : 8 : case PGBENCH_NARGS_VARIABLE:
465 [ + + ]: 8 : if (len == 0)
466 : 3 : expr_yyerror_more(yyscanner, "at least one argument expected",
467 : 3 : PGBENCH_FUNCTIONS[fnumber].fname);
468 : 5 : break;
469 : :
470 : : /* case (when ... then ...)+ (else ...)? end */
471 : 14 : case PGBENCH_NARGS_CASE:
472 : : /* 'else' branch is always present, but could be a NULL-constant */
473 [ + - - + ]: 14 : if (len < 3 || len % 2 != 1)
2216 teodor@sigaev.ru 474 :UBC 0 : expr_yyerror_more(yyscanner,
475 : : "odd and >= 3 number of arguments expected",
476 : : "case control structure");
2216 teodor@sigaev.ru 477 :CBC 14 : break;
478 : :
479 : : /* hash functions with optional seed argument */
480 : 8 : case PGBENCH_NARGS_HASH:
2088 michael@paquier.xyz 481 [ + + + + ]: 8 : if (len < 1 || len > 2)
2216 teodor@sigaev.ru 482 : 2 : expr_yyerror_more(yyscanner, "unexpected number of arguments",
483 : 2 : PGBENCH_FUNCTIONS[fnumber].fname);
484 : :
485 [ + + ]: 6 : if (len == 1)
486 : : {
487 : 2 : PgBenchExpr *var = make_variable("default_seed");
488 : 2 : args = make_elist(var, args);
489 : : }
490 : 6 : break;
491 : :
492 : : /* pseudorandom permutation function with optional seed argument */
1104 dean.a.rasheed@gmail 493 : 48 : case PGBENCH_NARGS_PERMUTE:
494 [ + + + + ]: 48 : if (len < 2 || len > 3)
495 : 2 : expr_yyerror_more(yyscanner, "unexpected number of arguments",
496 : 2 : PGBENCH_FUNCTIONS[fnumber].fname);
497 : :
498 [ + + ]: 46 : if (len == 2)
499 : : {
500 : 35 : PgBenchExpr *var = make_variable("default_seed");
501 : 35 : args = make_elist(var, args);
502 : : }
503 : 46 : break;
504 : :
505 : : /* common case: positive arguments number */
2216 teodor@sigaev.ru 506 : 817 : default:
507 [ - + ]: 817 : Assert(PGBENCH_FUNCTIONS[fnumber].nargs >= 0);
508 : :
509 [ + + ]: 817 : if (PGBENCH_FUNCTIONS[fnumber].nargs != len)
510 : 1 : expr_yyerror_more(yyscanner, "unexpected number of arguments",
511 : 1 : PGBENCH_FUNCTIONS[fnumber].fname);
512 : : }
513 : :
2966 rhaas@postgresql.org 514 : 887 : expr->etype = ENODE_FUNCTION;
515 : 887 : expr->u.function.function = PGBENCH_FUNCTIONS[fnumber].tag;
516 : :
517 : : /* only the link is used, the head/tail is not useful anymore */
2947 tgl@sss.pgh.pa.us 518 [ + + ]: 887 : expr->u.function.args = args != NULL ? args->head : NULL;
2966 rhaas@postgresql.org 519 [ + + ]: 887 : if (args)
520 : 886 : pg_free(args);
521 : :
3331 522 : 887 : return expr;
523 : : }
524 : :
525 : : static PgBenchExpr *
2287 teodor@sigaev.ru 526 : 14 : make_case(yyscan_t yyscanner, PgBenchExprList *when_then_list, PgBenchExpr *else_part)
527 : : {
528 : 14 : return make_func(yyscanner,
529 : : find_func(yyscanner, "!case_end"),
530 : : make_elist(else_part, when_then_list));
531 : : }
|