LCOV - code coverage report
Current view: top level - src/bin/pgbench - exprparse.y (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 74 77 96.1 %
Date: 2017-09-21 23:18:17 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

          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         232 : result: expr                { expr_parse_result = $1; }
      64             : 
      65           1 : elist:                      { $$ = NULL; }
      66         234 :     | expr                  { $$ = make_elist($1, NULL); }
      67         231 :     | elist ',' expr        { $$ = make_elist($3, $1); }
      68             :     ;
      69             : 
      70           4 : expr: '(' expr ')'          { $$ = $2; }
      71           0 :     | '+' expr %prec UMINUS { $$ = $2; }
      72          28 :     | '-' expr %prec UMINUS { $$ = make_op(yyscanner, "-",
      73             :                                            make_integer_constant(0), $2); }
      74           9 :     | expr '+' expr         { $$ = make_op(yyscanner, "+", $1, $3); }
      75           4 :     | expr '-' expr         { $$ = make_op(yyscanner, "-", $1, $3); }
      76         191 :     | expr '*' expr         { $$ = make_op(yyscanner, "*", $1, $3); }
      77           7 :     | expr '/' expr         { $$ = make_op(yyscanner, "/", $1, $3); }
      78           2 :     | expr '%' expr         { $$ = make_op(yyscanner, "%", $1, $3); }
      79         466 :     | INTEGER_CONST         { $$ = make_integer_constant($1); }
      80          22 :     | DOUBLE_CONST          { $$ = make_double_constant($1); }
      81         188 :     | VARIABLE              { $$ = make_variable($1); }
      82         235 :     | function '(' elist ')' { $$ = make_func(yyscanner, $1, $3); }
      83             :     ;
      84             : 
      85         236 : function: FUNCTION          { $$ = find_func(yyscanner, $1); pg_free($1); }
      86             :     ;
      87             : 
      88             : %%
      89             : 
      90             : static PgBenchExpr *
      91         494 : make_integer_constant(int64 ival)
      92             : {
      93         494 :     PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
      94             : 
      95         494 :     expr->etype = ENODE_CONSTANT;
      96         494 :     expr->u.constant.type = PGBT_INT;
      97         494 :     expr->u.constant.u.ival = ival;
      98         494 :     return expr;
      99             : }
     100             : 
     101             : static PgBenchExpr *
     102          22 : make_double_constant(double dval)
     103             : {
     104          22 :     PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
     105             : 
     106          22 :     expr->etype = ENODE_CONSTANT;
     107          22 :     expr->u.constant.type = PGBT_DOUBLE;
     108          22 :     expr->u.constant.u.dval = dval;
     109          22 :     return expr;
     110             : }
     111             : 
     112             : static PgBenchExpr *
     113         188 : make_variable(char *varname)
     114             : {
     115         188 :     PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
     116             : 
     117         188 :     expr->etype = ENODE_VARIABLE;
     118         188 :     expr->u.variable.varname = varname;
     119         188 :     return expr;
     120             : }
     121             : 
     122             : static PgBenchExpr *
     123         241 : make_op(yyscan_t yyscanner, const char *operator,
     124             :         PgBenchExpr *lexpr, PgBenchExpr *rexpr)
     125             : {
     126         241 :     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         477 : find_func(yyscan_t yyscanner, const char *fname)
     208             : {
     209         477 :     int         i = 0;
     210             : 
     211        4303 :     while (PGBENCH_FUNCTIONS[i].fname)
     212             :     {
     213        3825 :         if (pg_strcasecmp(fname, PGBENCH_FUNCTIONS[i].fname) == 0)
     214         476 :             return i;
     215        3349 :         i++;
     216             :     }
     217             : 
     218           1 :     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         947 : make_elist(PgBenchExpr *expr, PgBenchExprList *list)
     227             : {
     228             :     PgBenchExprLink *cons;
     229             : 
     230         947 :     if (list == NULL)
     231             :     {
     232         475 :         list = pg_malloc(sizeof(PgBenchExprList));
     233         475 :         list->head = NULL;
     234         475 :         list->tail = NULL;
     235             :     }
     236             : 
     237         947 :     cons = pg_malloc(sizeof(PgBenchExprLink));
     238         947 :     cons->expr = expr;
     239         947 :     cons->next = NULL;
     240             : 
     241         947 :     if (list->head == NULL)
     242         475 :         list->head = cons;
     243             :     else
     244         472 :         list->tail->next = cons;
     245             : 
     246         947 :     list->tail = cons;
     247             : 
     248         947 :     return list;
     249             : }
     250             : 
     251             : /* Return the length of an expression list */
     252             : static int
     253         476 : elist_length(PgBenchExprList *list)
     254             : {
     255         476 :     PgBenchExprLink *link = list != NULL ? list->head : NULL;
     256         476 :     int         len = 0;
     257             : 
     258        1423 :     for (; link != NULL; link = link->next)
     259         947 :         len++;
     260             : 
     261         476 :     return len;
     262             : }
     263             : 
     264             : /* Build function call expression */
     265             : static PgBenchExpr *
     266         476 : make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *args)
     267             : {
     268         476 :     PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
     269             : 
     270         476 :     Assert(fnumber >= 0);
     271             : 
     272         947 :     if (PGBENCH_FUNCTIONS[fnumber].nargs >= 0 &&
     273         471 :         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         481 :     if (PGBENCH_FUNCTIONS[fnumber].nargs == -1 &&
     279           5 :         elist_length(args) == 0)
     280           0 :         expr_yyerror_more(yyscanner, "at least one argument expected",
     281             :                           PGBENCH_FUNCTIONS[fnumber].fname);
     282             : 
     283         476 :     expr->etype = ENODE_FUNCTION;
     284         476 :     expr->u.function.function = PGBENCH_FUNCTIONS[fnumber].tag;
     285             : 
     286             :     /* only the link is used, the head/tail is not useful anymore */
     287         476 :     expr->u.function.args = args != NULL ? args->head : NULL;
     288         476 :     if (args)
     289         475 :         pg_free(args);
     290             : 
     291         476 :     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.11