diff --git a/contrib/pgbench/exprparse.y b/contrib/pgbench/exprparse.y index 243c6b9..fd396bd 100644 --- a/contrib/pgbench/exprparse.y +++ b/contrib/pgbench/exprparse.y @@ -20,6 +20,7 @@ static PgBenchExpr *make_integer_constant(int64 ival); static PgBenchExpr *make_variable(char *varname); static PgBenchExpr *make_op(char operator, PgBenchExpr *lexpr, PgBenchExpr *rexpr); +static PgBenchExpr *make_func(const char *fname, PgBenchExpr *arg1); %} @@ -35,8 +36,8 @@ static PgBenchExpr *make_op(char operator, PgBenchExpr *lexpr, %type expr %type INTEGER -%type VARIABLE -%token INTEGER VARIABLE +%type VARIABLE FUNCTION +%token INTEGER VARIABLE FUNCTION %token CHAR_ERROR /* never used, will raise a syntax error */ %left '+' '-' @@ -57,6 +58,7 @@ expr: '(' expr ')' { $$ = $2; } | expr '%' expr { $$ = make_op('%', $1, $3); } | INTEGER { $$ = make_integer_constant($1); } | VARIABLE { $$ = make_variable($1); } + | FUNCTION '(' expr ')' { $$ = make_func($1, $3); pg_free($1); } ; %% @@ -93,4 +95,32 @@ make_op(char operator, PgBenchExpr *lexpr, PgBenchExpr *rexpr) return expr; } +static struct { + char * fname; + int nargs; + PgBenchFunction tag; +} PGBENCH_FUNCTIONS[] = { + { "abs", 1, PGBENCH_ABS } +}; + +static PgBenchExpr * +make_func(const char * fname, PgBenchExpr *arg1) +{ + PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr)); + int nfunctions = sizeof(PGBENCH_FUNCTIONS) / sizeof(PGBENCH_FUNCTIONS[0]); + int i; + + expr->etype = ENODE_FUNCTION; + expr->u.function.function = PGBENCH_NONE; + + for (i = 0; i < nfunctions; i++) + if (pg_strcasecmp(fname, PGBENCH_FUNCTIONS[i].fname) == 0) + expr->u.function.function = PGBENCH_FUNCTIONS[i].tag; + + Assert(expr->u.function.function != PGBENCH_NONE); + + expr->u.function.arg1 = arg1; + return expr; +} + #include "exprscan.c" diff --git a/contrib/pgbench/exprscan.l b/contrib/pgbench/exprscan.l index 4c9229c..a276444 100644 --- a/contrib/pgbench/exprscan.l +++ b/contrib/pgbench/exprscan.l @@ -46,6 +46,7 @@ space [ \t\r\f] ")" { yycol += yyleng; return ')'; } :[a-zA-Z0-9_]+ { yycol += yyleng; yylval.str = pg_strdup(yytext + 1); return VARIABLE; } [0-9]+ { yycol += yyleng; yylval.ival = strtoint64(yytext); return INTEGER; } +[a-zA-Z]+ { yycol += yyleng; yylval.str = pg_strdup(yytext); return FUNCTION; } [\n] { yycol = 0; yyline++; } {space} { yycol += yyleng; /* ignore */ } diff --git a/contrib/pgbench/pgbench.c b/contrib/pgbench/pgbench.c index 706fdf5..1e9604d 100644 --- a/contrib/pgbench/pgbench.c +++ b/contrib/pgbench/pgbench.c @@ -959,6 +959,26 @@ evaluateExpr(CState *st, PgBenchExpr *expr, int64 *retval) return false; } + case ENODE_FUNCTION: + { + switch (expr->u.function.function) + { + case PGBENCH_ABS: + { + int64 arg1; + if (!evaluateExpr(st, expr->u.function.arg1, &arg1)) + return false; + + *retval = arg1 > 0? arg1: -arg1; + return true; + } + default: + fprintf(stderr, "bad function (%d)", + expr->u.function.function); + return false; + } + } + default: break; } diff --git a/contrib/pgbench/pgbench.h b/contrib/pgbench/pgbench.h index 128bf11..8697c7b 100644 --- a/contrib/pgbench/pgbench.h +++ b/contrib/pgbench/pgbench.h @@ -15,12 +15,19 @@ typedef enum PgBenchExprType { ENODE_INTEGER_CONSTANT, ENODE_VARIABLE, - ENODE_OPERATOR + ENODE_OPERATOR, + ENODE_FUNCTION } PgBenchExprType; struct PgBenchExpr; typedef struct PgBenchExpr PgBenchExpr; +typedef enum PgBenchFunction +{ + PGBENCH_NONE, + PGBENCH_ABS +} PgBenchFunction; + struct PgBenchExpr { PgBenchExprType etype; @@ -40,6 +47,11 @@ struct PgBenchExpr PgBenchExpr *lexpr; PgBenchExpr *rexpr; } operator; + struct + { + int function; + PgBenchExpr *arg1; + } function; } u; };