diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml
index a808546..d09b2bf 100644
--- a/doc/src/sgml/ref/pgbench.sgml
+++ b/doc/src/sgml/ref/pgbench.sgml
@@ -762,7 +762,7 @@ pgbench options dbname
references to variables :variablename,
and expressions composed of unary (-) or binary operators
(+, -, *, /, %)
- with their usual associativity, and parentheses.
+ with their usual associativity, function abs and parentheses.
diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y
index e68631e..035322d 100644
--- a/src/bin/pgbench/exprparse.y
+++ b/src/bin/pgbench/exprparse.y
@@ -20,6 +20,8 @@ static PgBenchExpr *make_integer_constant(int64 ival);
static PgBenchExpr *make_variable(char *varname);
static PgBenchExpr *make_op(char operator, PgBenchExpr *lexpr,
PgBenchExpr *rexpr);
+static int find_func(const char * fname);
+static PgBenchExpr *make_func(const int fnumber, PgBenchExpr *arg1);
%}
@@ -34,10 +36,10 @@ static PgBenchExpr *make_op(char operator, PgBenchExpr *lexpr,
}
%type expr
-%type INTEGER
-%type VARIABLE
+%type INTEGER function
+%type VARIABLE FUNCTION
-%token INTEGER VARIABLE
+%token INTEGER VARIABLE FUNCTION
%token CHAR_ERROR /* never used, will raise a syntax error */
/* Precedence: lowest to highest */
@@ -59,6 +61,10 @@ expr: '(' expr ')' { $$ = $2; }
| expr '%' expr { $$ = make_op('%', $1, $3); }
| INTEGER { $$ = make_integer_constant($1); }
| VARIABLE { $$ = make_variable($1); }
+ | function '(' expr ')' { $$ = make_func($1, $3); }
+ ;
+
+function: FUNCTION { $$ = find_func($1); pg_free($1); }
;
%%
@@ -95,4 +101,41 @@ 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 int
+find_func(const char * fname)
+{
+ int nfunctions = sizeof(PGBENCH_FUNCTIONS) / sizeof(PGBENCH_FUNCTIONS[0]);
+ int i;
+
+ for (i = 0; i < nfunctions; i++)
+ if (pg_strcasecmp(fname, PGBENCH_FUNCTIONS[i].fname) == 0)
+ return i;
+
+ expr_yyerror_more("unexpected function name", fname);
+
+ /* not reached */
+ return -1;
+}
+
+static PgBenchExpr *
+make_func(const int fnumber, PgBenchExpr *arg1)
+{
+ PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
+
+ Assert(fnumber >= 0);
+
+ expr->etype = ENODE_FUNCTION;
+ expr->u.function.function = PGBENCH_FUNCTIONS[fnumber].tag;
+ expr->u.function.arg1 = arg1;
+ return expr;
+}
+
#include "exprscan.c"
diff --git a/src/bin/pgbench/exprscan.l b/src/bin/pgbench/exprscan.l
index 5331ab7..0e07bfe 100644
--- a/src/bin/pgbench/exprscan.l
+++ b/src/bin/pgbench/exprscan.l
@@ -57,6 +57,11 @@ space [ \t\r\f]
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 */ }
@@ -71,10 +76,16 @@ space [ \t\r\f]
%%
void
-yyerror(const char *message)
+expr_yyerror_more(const char *message, const char *more)
{
syntax_error(expr_source, expr_lineno, expr_full_line, expr_command,
- message, NULL, expr_col + yycol);
+ message, more, expr_col + yycol);
+}
+
+void
+yyerror(const char *message)
+{
+ expr_yyerror_more(message, NULL);
}
/*
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index 6f35db4..de0855a 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -978,6 +978,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)\n",
+ expr->u.function.function);
+ return false;
+ }
+ }
+
default:
break;
}
diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h
index 42e2aae..356353e 100644
--- a/src/bin/pgbench/pgbench.h
+++ b/src/bin/pgbench/pgbench.h
@@ -15,11 +15,18 @@ typedef enum PgBenchExprType
{
ENODE_INTEGER_CONSTANT,
ENODE_VARIABLE,
- ENODE_OPERATOR
+ ENODE_OPERATOR,
+ ENODE_FUNCTION
} PgBenchExprType;
typedef struct PgBenchExpr PgBenchExpr;
+typedef enum PgBenchFunction
+{
+ PGBENCH_NONE,
+ PGBENCH_ABS
+} PgBenchFunction;
+
struct PgBenchExpr
{
PgBenchExprType etype;
@@ -39,6 +46,11 @@ struct PgBenchExpr
PgBenchExpr *lexpr;
PgBenchExpr *rexpr;
} operator;
+ struct
+ {
+ PgBenchFunction function;
+ PgBenchExpr *arg1;
+ } function;
} u;
};
@@ -47,6 +59,7 @@ extern PgBenchExpr *expr_parse_result;
extern int expr_yyparse(void);
extern int expr_yylex(void);
extern void expr_yyerror(const char *str);
+extern void expr_yyerror_more(const char *str, const char *more);
extern void expr_scanner_init(const char *str, const char *source,
const int lineno, const char *line,
const char *cmd, const int ecol);