LCOV - differential code coverage report
Current view: top level - src/bin/pgbench - exprparse.y (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 99.3 % 151 150 1 150
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 12 12 12
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           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-2023, 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 CBC         365 :                                 expr_parse_result = $1;
      85                 :                                 (void) yynerrs; /* suppress compiler warning */
      86                 :                             }
      87                 : 
      88               5 : elist:                      { $$ = NULL; }
      89             393 :     | expr                  { $$ = make_elist($1, NULL); }
      90             343 :     | elist ',' expr        { $$ = make_elist($3, $1); }
      91                 :     ;
      92                 : 
      93              52 : expr: '(' expr ')'          { $$ = $2; }
      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
     100               1 :                             { $$ = make_integer_constant(PG_INT64_MIN); }
     101                 :     /* binary ones complement "~x" implemented as 0xffff... xor x" */
     102               2 :     | '~' expr              { $$ = make_op(yyscanner, "#",
     103                 :                                            make_integer_constant(~INT64CONST(0)), $2); }
     104              12 :     | NOT_OP expr           { $$ = make_uop(yyscanner, "!not", $2); }
     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              12 :     | expr '/' expr         { $$ = make_op(yyscanner, "/", $1, $3); }
     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              31 :     | 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); }
     147             791 :     | INTEGER_CONST         { $$ = make_integer_constant($1); }
     148              61 :     | DOUBLE_CONST          { $$ = make_double_constant($1); }
     149                 :     /* misc */
     150             269 :     | VARIABLE              { $$ = make_variable($1); }
     151             398 :     | function '(' elist ')' { $$ = make_func(yyscanner, $1, $3); }
     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                 : 
     163             399 : function: FUNCTION          { $$ = find_func(yyscanner, $1); pg_free($1); }
     164                 :     ;
     165                 : 
     166                 : %%
     167                 : 
     168                 : static PgBenchExpr *
     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 *
     180             840 : make_integer_constant(int64 ival)
     181                 : {
     182             840 :     PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
     183                 : 
     184             840 :     expr->etype = ENODE_CONSTANT;
     185             840 :     expr->u.constant.type = PGBT_INT;
     186             840 :     expr->u.constant.u.ival = ival;
     187             840 :     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;
     198              61 :     return expr;
     199                 : }
     200                 : 
     201                 : static PgBenchExpr *
     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 *
     213             306 : make_variable(char *varname)
     214                 : {
     215             306 :     PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
     216                 : 
     217             306 :     expr->etype = ENODE_VARIABLE;
     218             306 :     expr->u.variable.varname = varname;
     219             306 :     return expr;
     220                 : }
     221                 : 
     222                 : /* binary operators */
     223                 : static PgBenchExpr *
     224             465 : make_op(yyscan_t yyscanner, const char *operator,
     225                 :         PgBenchExpr *lexpr, PgBenchExpr *rexpr)
     226                 : {
     227             465 :     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              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
     393             894 : find_func(yyscan_t yyscanner, const char *fname)
     394                 : {
     395             894 :     int         i = 0;
     396                 : 
     397           12456 :     while (PGBENCH_FUNCTIONS[i].fname)
     398                 :     {
     399           12455 :         if (pg_strcasecmp(fname, PGBENCH_FUNCTIONS[i].fname) == 0)
     400             893 :             return i;
     401           11562 :         i++;
     402                 :     }
     403                 : 
     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 *
     412            1765 : make_elist(PgBenchExpr *expr, PgBenchExprList *list)
     413                 : {
     414                 :     PgBenchExprLink *cons;
     415                 : 
     416            1765 :     if (list == NULL)
     417                 :     {
     418             888 :         list = pg_malloc(sizeof(PgBenchExprList));
     419             888 :         list->head = NULL;
     420             888 :         list->tail = NULL;
     421                 :     }
     422                 : 
     423            1765 :     cons = pg_malloc(sizeof(PgBenchExprLink));
     424            1765 :     cons->expr = expr;
     425            1765 :     cons->next = NULL;
     426                 : 
     427            1765 :     if (list->head == NULL)
     428             888 :         list->head = cons;
     429                 :     else
     430             877 :         list->tail->next = cons;
     431                 : 
     432            1765 :     list->tail = cons;
     433                 : 
     434            1765 :     return list;
     435                 : }
     436                 : 
     437                 : /* Return the length of an expression list */
     438                 : static int
     439             893 : elist_length(PgBenchExprList *list)
     440                 : {
     441             893 :     PgBenchExprLink *link = list != NULL ? list->head : NULL;
     442             893 :     int         len = 0;
     443                 : 
     444            2621 :     for (; link != NULL; link = link->next)
     445            1728 :         len++;
     446                 : 
     447             893 :     return len;
     448                 : }
     449                 : 
     450                 : /* Build function call expression */
     451                 : static PgBenchExpr *
     452             893 : make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *args)
     453                 : {
     454             893 :     int len = elist_length(args);
     455                 : 
     456             893 :     PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
     457                 : 
     458             893 :     Assert(fnumber >= 0);
     459                 : 
     460                 :     /* validate arguments number including few special cases */
     461             893 :     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)
     474 UBC           0 :                 expr_yyerror_more(yyscanner,
     475                 :                                   "odd and >= 3 number of arguments expected",
     476                 :                                   "case control structure");
     477 CBC          14 :             break;
     478                 : 
     479                 :         /* hash functions with optional seed argument */
     480               8 :         case PGBENCH_NARGS_HASH:
     481               8 :             if (len < 1 || len > 2)
     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 */
     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 */
     506             815 :         default:
     507             815 :             Assert(PGBENCH_FUNCTIONS[fnumber].nargs >= 0);
     508                 : 
     509             815 :             if (PGBENCH_FUNCTIONS[fnumber].nargs != len)
     510               1 :                 expr_yyerror_more(yyscanner, "unexpected number of arguments",
     511               1 :                                   PGBENCH_FUNCTIONS[fnumber].fname);
     512                 :     }
     513                 : 
     514             885 :     expr->etype = ENODE_FUNCTION;
     515             885 :     expr->u.function.function = PGBENCH_FUNCTIONS[fnumber].tag;
     516                 : 
     517                 :     /* only the link is used, the head/tail is not useful anymore */
     518             885 :     expr->u.function.args = args != NULL ? args->head : NULL;
     519             885 :     if (args)
     520             884 :         pg_free(args);
     521                 : 
     522             885 :     return expr;
     523                 : }
     524                 : 
     525                 : static PgBenchExpr *
     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                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a