LCOV - code coverage report
Current view: top level - src/bin/pgbench - exprparse.y (source / functions) Hit Total Coverage
Test: PostgreSQL 11devel Lines: 73 76 96.1 %
Date: 2017-11-22 12:18:04 Functions: 8 8 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 22 24 91.7 %

           Branch data     Line data    Source code
       1                 :            : %{
       2                 :            : /*-------------------------------------------------------------------------
       3                 :            :  *
       4                 :            :  * exprparse.y
       5                 :            :  *    bison grammar for a simple expression syntax
       6                 :            :  *
       7                 :            :  * Portions Copyright (c) 1996-2017, 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                 :            : PgBenchExpr *expr_parse_result;
      20                 :            : 
      21                 :            : static PgBenchExprList *make_elist(PgBenchExpr *exp, PgBenchExprList *list);
      22                 :            : static PgBenchExpr *make_integer_constant(int64 ival);
      23                 :            : static PgBenchExpr *make_double_constant(double dval);
      24                 :            : static PgBenchExpr *make_variable(char *varname);
      25                 :            : static PgBenchExpr *make_op(yyscan_t yyscanner, const char *operator,
      26                 :            :         PgBenchExpr *lexpr, PgBenchExpr *rexpr);
      27                 :            : static int  find_func(yyscan_t yyscanner, const char *fname);
      28                 :            : static PgBenchExpr *make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *args);
      29                 :            : 
      30                 :            : %}
      31                 :            : 
      32                 :            : %pure-parser
      33                 :            : %expect 0
      34                 :            : %name-prefix="expr_yy"
      35                 :            : 
      36                 :            : %parse-param {yyscan_t yyscanner}
      37                 :            : %lex-param   {yyscan_t yyscanner}
      38                 :            : 
      39                 :            : %union
      40                 :            : {
      41                 :            :     int64       ival;
      42                 :            :     double      dval;
      43                 :            :     char       *str;
      44                 :            :     PgBenchExpr *expr;
      45                 :            :     PgBenchExprList *elist;
      46                 :            : }
      47                 :            : 
      48                 :            : %type <elist> elist
      49                 :            : %type <expr> expr
      50                 :            : %type <ival> INTEGER_CONST function
      51                 :            : %type <dval> DOUBLE_CONST
      52                 :            : %type <str> VARIABLE FUNCTION
      53                 :            : 
      54                 :            : %token INTEGER_CONST DOUBLE_CONST VARIABLE FUNCTION
      55                 :            : 
      56                 :            : /* Precedence: lowest to highest */
      57                 :            : %left   '+' '-'
      58                 :            : %left   '*' '/' '%'
      59                 :            : %right  UMINUS
      60                 :            : 
      61                 :            : %%
      62                 :            : 
      63                 :        476 : result: expr                { expr_parse_result = $1; }
      64                 :            : 
      65                 :          2 : elist:                      { $$ = NULL; }
      66                 :        480 :     | expr                  { $$ = make_elist($1, NULL); }
      67                 :        474 :     | elist ',' expr        { $$ = make_elist($3, $1); }
      68                 :            :     ;
      69                 :            : 
      70                 :          8 : expr: '(' expr ')'          { $$ = $2; }
      71                 :          0 :     | '+' expr %prec UMINUS { $$ = $2; }
      72                 :         60 :     | '-' expr %prec UMINUS { $$ = make_op(yyscanner, "-",
      73                 :            :                                            make_integer_constant(0), $2); }
      74                 :         18 :     | expr '+' expr         { $$ = make_op(yyscanner, "+", $1, $3); }
      75                 :          8 :     | expr '-' expr         { $$ = make_op(yyscanner, "-", $1, $3); }
      76                 :        390 :     | expr '*' expr         { $$ = make_op(yyscanner, "*", $1, $3); }
      77                 :         14 :     | expr '/' expr         { $$ = make_op(yyscanner, "/", $1, $3); }
      78                 :          4 :     | expr '%' expr         { $$ = make_op(yyscanner, "%", $1, $3); }
      79                 :        956 :     | INTEGER_CONST         { $$ = make_integer_constant($1); }
      80                 :         44 :     | DOUBLE_CONST          { $$ = make_double_constant($1); }
      81                 :        384 :     | VARIABLE              { $$ = make_variable($1); }
      82                 :        482 :     | function '(' elist ')' { $$ = make_func(yyscanner, $1, $3); }
      83                 :            :     ;
      84                 :            : 
      85                 :        484 : function: FUNCTION          { $$ = find_func(yyscanner, $1); pg_free($1); }
      86                 :            :     ;
      87                 :            : 
      88                 :            : %%
      89                 :            : 
      90                 :            : static PgBenchExpr *
      91                 :       1016 : make_integer_constant(int64 ival)
      92                 :            : {
      93                 :       1016 :     PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
      94                 :            : 
      95                 :       1016 :     expr->etype = ENODE_CONSTANT;
      96                 :       1016 :     expr->u.constant.type = PGBT_INT;
      97                 :       1016 :     expr->u.constant.u.ival = ival;
      98                 :       1016 :     return expr;
      99                 :            : }
     100                 :            : 
     101                 :            : static PgBenchExpr *
     102                 :         44 : make_double_constant(double dval)
     103                 :            : {
     104                 :         44 :     PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
     105                 :            : 
     106                 :         44 :     expr->etype = ENODE_CONSTANT;
     107                 :         44 :     expr->u.constant.type = PGBT_DOUBLE;
     108                 :         44 :     expr->u.constant.u.dval = dval;
     109                 :         44 :     return expr;
     110                 :            : }
     111                 :            : 
     112                 :            : static PgBenchExpr *
     113                 :        384 : make_variable(char *varname)
     114                 :            : {
     115                 :        384 :     PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
     116                 :            : 
     117                 :        384 :     expr->etype = ENODE_VARIABLE;
     118                 :        384 :     expr->u.variable.varname = varname;
     119                 :        384 :     return expr;
     120                 :            : }
     121                 :            : 
     122                 :            : static PgBenchExpr *
     123                 :        494 : make_op(yyscan_t yyscanner, const char *operator,
     124                 :            :         PgBenchExpr *lexpr, PgBenchExpr *rexpr)
     125                 :            : {
     126                 :        494 :     return make_func(yyscanner, find_func(yyscanner, operator),
     127                 :            :                      make_elist(rexpr, make_elist(lexpr, NULL)));
     128                 :            : }
     129                 :            : 
     130                 :            : /*
     131                 :            :  * List of available functions:
     132                 :            :  * - fname: function name
     133                 :            :  * - nargs: number of arguments
     134                 :            :  *          -1 is a special value for least & greatest meaning #args >= 1
     135                 :            :  * - tag: function identifier from PgBenchFunction enum
     136                 :            :  */
     137                 :            : static const struct
     138                 :            : {
     139                 :            :     const char *fname;
     140                 :            :     int         nargs;
     141                 :            :     PgBenchFunction tag;
     142                 :            : }   PGBENCH_FUNCTIONS[] =
     143                 :            : {
     144                 :            :     /* parsed as operators, executed as functions */
     145                 :            :     {
     146                 :            :         "+", 2, PGBENCH_ADD
     147                 :            :     },
     148                 :            :     {
     149                 :            :         "-", 2, PGBENCH_SUB
     150                 :            :     },
     151                 :            :     {
     152                 :            :         "*", 2, PGBENCH_MUL
     153                 :            :     },
     154                 :            :     {
     155                 :            :         "/", 2, PGBENCH_DIV
     156                 :            :     },
     157                 :            :     {
     158                 :            :         "%", 2, PGBENCH_MOD
     159                 :            :     },
     160                 :            :     /* actual functions */
     161                 :            :     {
     162                 :            :         "abs", 1, PGBENCH_ABS
     163                 :            :     },
     164                 :            :     {
     165                 :            :         "least", -1, PGBENCH_LEAST
     166                 :            :     },
     167                 :            :     {
     168                 :            :         "greatest", -1, PGBENCH_GREATEST
     169                 :            :     },
     170                 :            :     {
     171                 :            :         "debug", 1, PGBENCH_DEBUG
     172                 :            :     },
     173                 :            :     {
     174                 :            :         "pi", 0, PGBENCH_PI
     175                 :            :     },
     176                 :            :     {
     177                 :            :         "sqrt", 1, PGBENCH_SQRT
     178                 :            :     },
     179                 :            :     {
     180                 :            :         "int", 1, PGBENCH_INT
     181                 :            :     },
     182                 :            :     {
     183                 :            :         "double", 1, PGBENCH_DOUBLE
     184                 :            :     },
     185                 :            :     {
     186                 :            :         "random", 2, PGBENCH_RANDOM
     187                 :            :     },
     188                 :            :     {
     189                 :            :         "random_gaussian", 3, PGBENCH_RANDOM_GAUSSIAN
     190                 :            :     },
     191                 :            :     {
     192                 :            :         "random_exponential", 3, PGBENCH_RANDOM_EXPONENTIAL
     193                 :            :     },
     194                 :            :     /* keep as last array element */
     195                 :            :     {
     196                 :            :         NULL, 0, 0
     197                 :            :     }
     198                 :            : };
     199                 :            : 
     200                 :            : /*
     201                 :            :  * Find a function from its name
     202                 :            :  *
     203                 :            :  * return the index of the function from the PGBENCH_FUNCTIONS array
     204                 :            :  * or fail if the function is unknown.
     205                 :            :  */
     206                 :            : static int
     207                 :        978 : find_func(yyscan_t yyscanner, const char *fname)
     208                 :            : {
     209                 :        978 :     int         i = 0;
     210                 :            : 
     211         [ +  + ]:       7852 :     while (PGBENCH_FUNCTIONS[i].fname)
     212                 :            :     {
     213         [ +  + ]:       7850 :         if (pg_strcasecmp(fname, PGBENCH_FUNCTIONS[i].fname) == 0)
     214                 :        976 :             return i;
     215                 :       6874 :         i++;
     216                 :            :     }
     217                 :            : 
     218                 :          2 :     expr_yyerror_more(yyscanner, "unexpected function name", fname);
     219                 :            : 
     220                 :            :     /* not reached */
     221                 :            :     return -1;
     222                 :            : }
     223                 :            : 
     224                 :            : /* Expression linked list builder */
     225                 :            : static PgBenchExprList *
     226                 :       1942 : make_elist(PgBenchExpr *expr, PgBenchExprList *list)
     227                 :            : {
     228                 :            :     PgBenchExprLink *cons;
     229                 :            : 
     230         [ +  + ]:       1942 :     if (list == NULL)
     231                 :            :     {
     232                 :        974 :         list = pg_malloc(sizeof(PgBenchExprList));
     233                 :        974 :         list->head = NULL;
     234                 :        974 :         list->tail = NULL;
     235                 :            :     }
     236                 :            : 
     237                 :       1942 :     cons = pg_malloc(sizeof(PgBenchExprLink));
     238                 :       1942 :     cons->expr = expr;
     239                 :       1942 :     cons->next = NULL;
     240                 :            : 
     241         [ +  + ]:       1942 :     if (list->head == NULL)
     242                 :        974 :         list->head = cons;
     243                 :            :     else
     244                 :        968 :         list->tail->next = cons;
     245                 :            : 
     246                 :       1942 :     list->tail = cons;
     247                 :            : 
     248                 :       1942 :     return list;
     249                 :            : }
     250                 :            : 
     251                 :            : /* Return the length of an expression list */
     252                 :            : static int
     253                 :        976 : elist_length(PgBenchExprList *list)
     254                 :            : {
     255         [ +  + ]:        976 :     PgBenchExprLink *link = list != NULL ? list->head : NULL;
     256                 :        976 :     int         len = 0;
     257                 :            : 
     258         [ +  + ]:       2918 :     for (; link != NULL; link = link->next)
     259                 :       1942 :         len++;
     260                 :            : 
     261                 :        976 :     return len;
     262                 :            : }
     263                 :            : 
     264                 :            : /* Build function call expression */
     265                 :            : static PgBenchExpr *
     266                 :        976 : make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *args)
     267                 :            : {
     268                 :        976 :     PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
     269                 :            : 
     270                 :            :     Assert(fnumber >= 0);
     271                 :            : 
     272   [ +  +  -  + ]:       1942 :     if (PGBENCH_FUNCTIONS[fnumber].nargs >= 0 &&
     273                 :        966 :         PGBENCH_FUNCTIONS[fnumber].nargs != elist_length(args))
     274                 :          0 :         expr_yyerror_more(yyscanner, "unexpected number of arguments",
     275                 :            :                           PGBENCH_FUNCTIONS[fnumber].fname);
     276                 :            : 
     277                 :            :     /* check at least one arg for least & greatest */
     278   [ +  +  -  + ]:        986 :     if (PGBENCH_FUNCTIONS[fnumber].nargs == -1 &&
     279                 :         10 :         elist_length(args) == 0)
     280                 :          0 :         expr_yyerror_more(yyscanner, "at least one argument expected",
     281                 :            :                           PGBENCH_FUNCTIONS[fnumber].fname);
     282                 :            : 
     283                 :        976 :     expr->etype = ENODE_FUNCTION;
     284                 :        976 :     expr->u.function.function = PGBENCH_FUNCTIONS[fnumber].tag;
     285                 :            : 
     286                 :            :     /* only the link is used, the head/tail is not useful anymore */
     287         [ +  + ]:        976 :     expr->u.function.args = args != NULL ? args->head : NULL;
     288         [ +  + ]:        976 :     if (args)
     289                 :        974 :         pg_free(args);
     290                 :            : 
     291                 :        976 :     return expr;
     292                 :            : }
     293                 :            : 
     294                 :            : /*
     295                 :            :  * exprscan.l is compiled as part of exprparse.y.  Currently, this is
     296                 :            :  * unavoidable because exprparse does not create a .h file to export
     297                 :            :  * its token symbols.  If these files ever grow large enough to be
     298                 :            :  * worth compiling separately, that could be fixed; but for now it
     299                 :            :  * seems like useless complication.
     300                 :            :  */
     301                 :            : 
     302                 :            : /* First, get rid of "#define yyscan_t" from pgbench.h */
     303                 :            : #undef yyscan_t
     304                 :            : /* ... and the yylval macro, which flex will have its own definition for */
     305                 :            : #undef yylval
     306                 :            : 
     307                 :            : #include "exprscan.c"

Generated by: LCOV version 1.13