[...]
Here is a v10 where I did that when it did not add too much code repetition
(eg I kept the shared branches for MIN & MAX and for the 3 RANDOM functions
so as to avoid large copy pastes).
Ooops, forgotten attachement.
--
Fabien.
diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml
index ba3edc4..58ccf5e 100644
--- a/doc/src/sgml/ref/pgbench.sgml
+++ b/doc/src/sgml/ref/pgbench.sgml
@@ -758,17 +758,20 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
Sets variable <replaceable>varname</> to an integer value calculated
from <replaceable>expression</>.
The expression may contain integer constants such as <literal>5432</>,
- references to variables <literal>:</><replaceable>variablename</>,
+ double constants such as <literal>3.14156</>,
+ references to integer variables <literal>:</><replaceable>variablename</>,
and expressions composed of unary (<literal>-</>) or binary operators
(<literal>+</>, <literal>-</>, <literal>*</>, <literal>/</>, <literal>%</>)
- with their usual associativity, and parentheses.
+ with their usual associativity, function calls and parentheses.
+ <xref linkend="functions-pgbench-func-table"> shows the available
+ functions.
</para>
<para>
Examples:
<programlisting>
\set ntellers 10 * :scale
-\set aid (1021 * :aid) % (100000 * :scale) + 1
+\set aid (1021 * random(1, 100000 * :scale)) % (100000 * :scale) + 1
</programlisting></para>
</listitem>
</varlistentry>
@@ -918,18 +921,110 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
</varlistentry>
</variablelist>
+ <!-- list pgbench functions in alphabetical order -->
+ <table id="functions-pgbench-func-table">
+ <title>PgBench Functions</title>
+ <tgroup cols="5">
+ <thead>
+ <row>
+ <entry>Function</entry>
+ <entry>Return Type</entry>
+ <entry>Description</entry>
+ <entry>Example</entry>
+ <entry>Result</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal><function>abs(<replaceable>a</>)</></></>
+ <entry>same as <replaceable>a</></>
+ <entry>integer or double absolute value</>
+ <entry><literal>abs(-17)</></>
+ <entry><literal>17</></>
+ </row>
+ <row>
+ <entry><literal><function>ddebug(<replaceable>x</>)</></></>
+ <entry>double</>
+ <entry>stderr print for debug and return argument</>
+ <entry><literal>ddebug(5432.1)</></>
+ <entry><literal>5432.1</></>
+ </row>
+ <row>
+ <entry><literal><function>double(<replaceable>i</>)</></></>
+ <entry>double</>
+ <entry>evaluate as int and cast to double</>
+ <entry><literal>double(5432)</></>
+ <entry><literal>5432.0</></>
+ </row>
+ <row>
+ <entry><literal><function>exporand(<replaceable>i</>, <replaceable>j</>, <replaceable>t</>)</></></>
+ <entry>integer</>
+ <entry>exponentially distributed random integer in the bounds, see below</>
+ <entry><literal>exporand(1, 10, 3.0)</></>
+ <entry>int between <literal>1</> and <literal>10</></>
+ </row>
+ <row>
+ <entry><literal><function>idebug(<replaceable>i</>)</></></>
+ <entry>integer</>
+ <entry>stderr print for debug and return argument</>
+ <entry><literal>idebug(5432)</></>
+ <entry><literal>5432</></>
+ </row>
+ <row>
+ <entry><literal><function>int(<replaceable>x</>)</></></>
+ <entry>integer</>
+ <entry>evaluate as double and cast to int</>
+ <entry><literal>int(5.4 + 3.8)</></>
+ <entry><literal>9</></>
+ </row>
+ <row>
+ <entry><literal><function>gaussrand(<replaceable>i</>, <replaceable>j</>, <replaceable>t</>)</></></>
+ <entry>integer</>
+ <entry>gaussian distributed random integer in the bounds, see below</>
+ <entry><literal>gaussrand(1, 10, 2.5)</></>
+ <entry>int between <literal>1</> and <literal>10</></>
+ </row>
+ <row>
+ <entry><literal><function>min(<replaceable>i</>, <replaceable>...</>)</></></>
+ <entry>integer</>
+ <entry>minimum value</>
+ <entry><literal>min(5, 4, 3, 2)</></>
+ <entry><literal>2</></>
+ </row>
+ <row>
+ <entry><literal><function>max(<replaceable>i</>, <replaceable>...</>)</></></>
+ <entry>integer</>
+ <entry>maximum value</>
+ <entry><literal>max(5, 4, 3, 2)</></>
+ <entry><literal>5</></>
+ </row>
+ <row>
+ <entry><literal><function>random(<replaceable>i</>, <replaceable>j</>)</></></>
+ <entry>integer</>
+ <entry>uniformly distributed random integer in the bounds</>
+ <entry><literal>random(1, 10)</></>
+ <entry>int between <literal>1</> and <literal>10</></>
+ </row>
+ <row>
+ <entry><literal><function>sqrt(<replaceable>x</>)</></></>
+ <entry>double</>
+ <entry>square root</>
+ <entry><literal>sqrt(2.0)</></>
+ <entry><literal>1.414213562</></>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
<para>
As an example, the full definition of the built-in TPC-B-like
transaction is:
<programlisting>
-\set nbranches :scale
-\set ntellers 10 * :scale
-\set naccounts 100000 * :scale
-\setrandom aid 1 :naccounts
-\setrandom bid 1 :nbranches
-\setrandom tid 1 :ntellers
-\setrandom delta -5000 5000
+\set aid random(1, 100000 * :scale)
+\set bid random(1, 1 * :scale)
+\set tid random(1, 10 * :scale)
+\set delta random(-5000, 5000)
BEGIN;
UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y
index e68631e..97bb559 100644
--- a/src/bin/pgbench/exprparse.y
+++ b/src/bin/pgbench/exprparse.y
@@ -16,10 +16,14 @@
PgBenchExpr *expr_parse_result;
+static PgBenchExprList *make_elist(PgBenchExpr *exp, PgBenchExprList *list);
static PgBenchExpr *make_integer_constant(int64 ival);
+static PgBenchExpr *make_double_constant(double dval);
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, PgBenchExprList *args);
%}
@@ -29,15 +33,19 @@ static PgBenchExpr *make_op(char operator, PgBenchExpr *lexpr,
%union
{
int64 ival;
+ double dval;
char *str;
PgBenchExpr *expr;
+ PgBenchExprList *elist;
}
+%type <elist> elist
%type <expr> expr
-%type <ival> INTEGER
-%type <str> VARIABLE
+%type <ival> INTEGER function
+%type <dval> DOUBLE
+%type <str> VARIABLE FUNCTION
-%token INTEGER VARIABLE
+%token INTEGER DOUBLE VARIABLE FUNCTION
%token CHAR_ERROR /* never used, will raise a syntax error */
/* Precedence: lowest to highest */
@@ -49,6 +57,10 @@ static PgBenchExpr *make_op(char operator, PgBenchExpr *lexpr,
result: expr { expr_parse_result = $1; }
+elist: expr { $$ = make_elist($1, NULL); }
+ | elist ',' expr { $$ = make_elist($3, $1); }
+ ;
+
expr: '(' expr ')' { $$ = $2; }
| '+' expr %prec UMINUS { $$ = $2; }
| '-' expr %prec UMINUS { $$ = make_op('-', make_integer_constant(0), $2); }
@@ -58,7 +70,12 @@ expr: '(' expr ')' { $$ = $2; }
| expr '/' expr { $$ = make_op('/', $1, $3); }
| expr '%' expr { $$ = make_op('%', $1, $3); }
| INTEGER { $$ = make_integer_constant($1); }
+ | DOUBLE { $$ = make_double_constant($1); }
| VARIABLE { $$ = make_variable($1); }
+ | function '(' elist ')'{ $$ = make_func($1, $3); }
+ ;
+
+function: FUNCTION { $$ = find_func($1); pg_free($1); }
;
%%
@@ -74,6 +91,16 @@ make_integer_constant(int64 ival)
}
static PgBenchExpr *
+make_double_constant(double dval)
+{
+ PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
+
+ expr->etype = ENODE_DOUBLE_CONSTANT;
+ expr->u.double_constant.dval = dval;
+ return expr;
+}
+
+static PgBenchExpr *
make_variable(char *varname)
{
PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
@@ -95,4 +122,93 @@ make_op(char operator, PgBenchExpr *lexpr, PgBenchExpr *rexpr)
return expr;
}
+static struct {
+ char * fname;
+ int nargs;
+ PgBenchFunction tag;
+} PGBENCH_FUNCTIONS[] = {
+ { "abs", 1, PGBENCH_ABS },
+ { "sqrt", 1, PGBENCH_SQRT },
+ { "int", 1, PGBENCH_INT },
+ { "double", 1, PGBENCH_DOUBLE },
+ { "min", -1, PGBENCH_MIN },
+ { "max", -1, PGBENCH_MAX },
+ { "random", 2, PGBENCH_RANDOM },
+ { "gaussrand", 3, PGBENCH_GAUSSRAND },
+ { "exporand", 3, PGBENCH_EXPORAND },
+ { "idebug", 1, PGBENCH_IDEBUG },
+ { "ddebug", 1, PGBENCH_DDEBUG }
+};
+
+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 PgBenchExprList *
+make_elist(PgBenchExpr *expr, PgBenchExprList *list)
+{
+ PgBenchExprList *cons = pg_malloc(sizeof(PgBenchExprList));
+ cons->expr = expr;
+ cons->next = list;
+ return cons;
+}
+
+static PgBenchExprList *
+reverse_elist(PgBenchExprList *list)
+{
+ PgBenchExprList *cur = list, *prec = NULL, *next = NULL;
+
+ while (cur != NULL)
+ {
+ next = cur->next;
+ cur->next = prec;
+ prec = cur;
+ cur = next;
+ }
+
+ return prec;
+}
+
+static int
+elist_length(PgBenchExprList *list)
+{
+ int len = 0;
+
+ for (; list != NULL; list = list->next)
+ len++;
+
+ return len;
+}
+
+static PgBenchExpr *
+make_func(const int fnumber, PgBenchExprList *args)
+{
+ PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
+
+ Assert(fnumber >= 0);
+
+ if (PGBENCH_FUNCTIONS[fnumber].nargs != -1 &&
+ PGBENCH_FUNCTIONS[fnumber].nargs != elist_length(args))
+ expr_yyerror_more("unexpected number of arguments",
+ PGBENCH_FUNCTIONS[fnumber].fname);
+
+ expr->etype = ENODE_FUNCTION;
+ expr->u.function.function = PGBENCH_FUNCTIONS[fnumber].tag;
+ expr->u.function.args = reverse_elist(args);
+
+ return expr;
+}
+
#include "exprscan.c"
diff --git a/src/bin/pgbench/exprscan.l b/src/bin/pgbench/exprscan.l
index 5331ab7..bf8aa0f 100644
--- a/src/bin/pgbench/exprscan.l
+++ b/src/bin/pgbench/exprscan.l
@@ -46,6 +46,7 @@ space [ \t\r\f]
"%" { yycol += yyleng; return '%'; }
"(" { yycol += yyleng; return '('; }
")" { yycol += yyleng; return ')'; }
+"," { yycol += yyleng; return ','; }
:[a-zA-Z0-9_]+ {
yycol += yyleng;
@@ -57,8 +58,19 @@ space [ \t\r\f]
yylval.ival = strtoint64(yytext);
return INTEGER;
}
+[0-9]+\.[0-9]+ {
+ yycol += yyleng;
+ yylval.dval = atof(yytext);
+ return DOUBLE;
+ }
+[a-zA-Z]+ {
+ yycol += yyleng;
+ yylval.str = pg_strdup(yytext);
+ return FUNCTION;
+ }
+
+[\n] { yycol = 0; yyline++; /* never occurs, input on one line */ }
-[\n] { yycol = 0; yyline++; }
{space}+ { yycol += yyleng; /* ignore */ }
. {
@@ -71,10 +83,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);
}
/*
@@ -94,15 +112,14 @@ expr_scanner_init(const char *str, const char *source,
expr_command = (char *) cmd;
expr_col = (int) ecol;
- /*
- * Might be left over after error
- */
+ /* reset column count for this scan */
+ yycol = 0;
+
+ /* Might be left over after error */
if (YY_CURRENT_BUFFER)
yy_delete_buffer(YY_CURRENT_BUFFER);
- /*
- * Make a scan buffer with special termination needed by flex.
- */
+ /* Make a scan buffer with special termination needed by flex. */
scanbuflen = slen;
scanbuf = pg_malloc(slen + 2);
memcpy(scanbuf, str, slen);
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index 6894345..c66a34b 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -302,13 +302,10 @@ static int debug = 0; /* debug flag */
/* default scenario */
static char *tpc_b = {
- "\\set nbranches " CppAsString2(nbranches) " * :scale\n"
- "\\set ntellers " CppAsString2(ntellers) " * :scale\n"
- "\\set naccounts " CppAsString2(naccounts) " * :scale\n"
- "\\setrandom aid 1 :naccounts\n"
- "\\setrandom bid 1 :nbranches\n"
- "\\setrandom tid 1 :ntellers\n"
- "\\setrandom delta -5000 5000\n"
+ "\\set aid random(1, " CppAsString2(naccounts) " * :scale)\n"
+ "\\set bid random(1, " CppAsString2(nbranches) " * :scale)\n"
+ "\\set tid random(1, " CppAsString2(ntellers) " * :scale)\n"
+ "\\set delta random(-5000, 5000)\n"
"BEGIN;\n"
"UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
@@ -320,13 +317,10 @@ static char *tpc_b = {
/* -N case */
static char *simple_update = {
- "\\set nbranches " CppAsString2(nbranches) " * :scale\n"
- "\\set ntellers " CppAsString2(ntellers) " * :scale\n"
- "\\set naccounts " CppAsString2(naccounts) " * :scale\n"
- "\\setrandom aid 1 :naccounts\n"
- "\\setrandom bid 1 :nbranches\n"
- "\\setrandom tid 1 :ntellers\n"
- "\\setrandom delta -5000 5000\n"
+ "\\set aid random(1, " CppAsString2(naccounts) " * :scale)\n"
+ "\\set bid random(1, " CppAsString2(nbranches) " * :scale)\n"
+ "\\set tid random(1, " CppAsString2(ntellers) " * :scale)\n"
+ "\\set delta random(-5000, 5000)\n"
"BEGIN;\n"
"UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
@@ -336,8 +330,7 @@ static char *simple_update = {
/* -S case */
static char *select_only = {
- "\\set naccounts " CppAsString2(naccounts) " * :scale\n"
- "\\setrandom aid 1 :naccounts\n"
+ "\\set aid random(1, " CppAsString2(naccounts) " * :scale)\n"
"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
};
@@ -885,6 +878,123 @@ getQueryParams(CState *st, const Command *command, const char **params)
params[i] = getVariable(st, command->argv[i + 1]);
}
+static bool evalInt(TState *, CState *, PgBenchExpr *, int64 *);
+
+static bool
+evalDouble(TState *thread, CState *st, PgBenchExpr *expr, double *retval)
+{
+ switch (expr->etype)
+ {
+ case ENODE_DOUBLE_CONSTANT:
+ {
+ *retval = expr->u.double_constant.dval;
+ return true;
+ }
+ case ENODE_OPERATOR:
+ {
+ double lval, rval;
+
+ if (!evalDouble(thread, st, expr->u.operator.lexpr, &lval))
+ return false;
+ if (!evalDouble(thread, st, expr->u.operator.rexpr, &rval))
+ return false;
+
+ switch (expr->u.operator.operator)
+ {
+ case '+':
+ *retval = lval + rval;
+ return true;
+
+ case '-':
+ *retval = lval - rval;
+ return true;
+
+ case '*':
+ *retval = lval * rval;
+ return true;
+
+ case '/':
+ *retval = lval / rval;
+ return true;
+
+ case '%':
+ default: /* *MUST* be an int operator */
+ {
+ int64 ival;
+ if (!evalInt(thread, st, expr, &ival))
+ return false;
+ *retval = (double) ival;
+ return true;
+ }
+ }
+ }
+ case ENODE_FUNCTION:
+ {
+ PgBenchFunction func = expr->u.function.function;
+ PgBenchExprList *args = expr->u.function.args;
+
+ switch (func)
+ {
+ case PGBENCH_ABS: /* also an integer function */
+ {
+ if (!evalDouble(thread, st, args->expr, retval))
+ return false;
+
+ if ((*retval) < 0.0)
+ *retval = - *retval;
+
+ return true;
+ }
+ case PGBENCH_SQRT:
+ {
+ double arg;
+
+ if (!evalDouble(thread, st, args->expr, &arg))
+ return false;
+
+ *retval = sqrt(arg);
+
+ return true;
+ }
+ case PGBENCH_DDEBUG:
+ {
+ if (!evalDouble(thread, st, args->expr, retval))
+ return false;
+
+ fprintf(stderr, "ddebug(script=%d,command=%d): %f\n",
+ st->use_file, st->state+1, *retval);
+
+ return true;
+ }
+ case PGBENCH_DOUBLE:
+ {
+ int64 ival;
+ if (!evalInt(thread, st, args->expr, &ival))
+ return false;
+ *retval = (double) ival;
+ return true;
+ }
+ default: /* *MUST* be an integer function */
+ {
+ int64 ival;
+ if (!evalInt(thread, st, expr, &ival))
+ return false;
+ *retval = (double) ival;
+ return true;
+ }
+ }
+ }
+ default: /* *MUST* be an integer expression */
+ {
+ int64 ival;
+ if (!evalInt(thread, st, expr, &ival))
+ return false;
+ *retval = (double) ival;
+ return true;
+ }
+ }
+}
+
/*
* Recursive evaluation of an expression in a pgbench script
* using the current state of variables.
@@ -892,7 +1002,7 @@ getQueryParams(CState *st, const Command *command, const char **params)
* the value itself is returned through the retval pointer.
*/
static bool
-evaluateExpr(CState *st, PgBenchExpr *expr, int64 *retval)
+evalInt(TState *thread, CState *st, PgBenchExpr *expr, int64 *retval)
{
switch (expr->etype)
{
@@ -902,6 +1012,12 @@ evaluateExpr(CState *st, PgBenchExpr *expr, int64 *retval)
return true;
}
+ case ENODE_DOUBLE_CONSTANT:
+ {
+ *retval = (int64) expr->u.double_constant.dval;
+ return true;
+ }
+
case ENODE_VARIABLE:
{
char *var;
@@ -921,9 +1037,9 @@ evaluateExpr(CState *st, PgBenchExpr *expr, int64 *retval)
int64 lval;
int64 rval;
- if (!evaluateExpr(st, expr->u.operator.lexpr, &lval))
+ if (!evalInt(thread, st, expr->u.operator.lexpr, &lval))
return false;
- if (!evaluateExpr(st, expr->u.operator.rexpr, &rval))
+ if (!evalInt(thread, st, expr->u.operator.rexpr, &rval))
return false;
switch (expr->u.operator.operator)
{
@@ -962,8 +1078,134 @@ evaluateExpr(CState *st, PgBenchExpr *expr, int64 *retval)
return false;
}
- default:
- break;
+ case ENODE_FUNCTION:
+ {
+ PgBenchFunction func = expr->u.function.function;
+ PgBenchExprList *args = expr->u.function.args;
+
+ switch (func)
+ {
+ case PGBENCH_RANDOM:
+ case PGBENCH_GAUSSRAND:
+ case PGBENCH_EXPORAND:
+ {
+ int64 arg1, arg2;
+
+ if (!evalInt(thread, st, args->expr, &arg1))
+ return false;
+ if (!evalInt(thread, st, args->next->expr, &arg2))
+ return false;
+
+ /* check random range */
+ if (arg1 > arg2)
+ {
+ fprintf(stderr, "empty range given to random\n");
+ st->ecnt++;
+ return false;
+ }
+ else if (arg2 - arg1 < 0 || (arg2 - arg1) + 1 < 0)
+ {
+ /* prevent int overflows in random functions */
+ fprintf(stderr, "random range is too large\n");
+ st->ecnt++;
+ return false;
+ }
+
+ if (func == PGBENCH_RANDOM)
+ *retval = getrand(thread, arg1, arg2);
+ else /* gaussian & exponential */
+ {
+ double threshold;
+ if (!evalDouble(thread, st, args->next->next->expr,
+ &threshold))
+ return false;
+ if (func == PGBENCH_GAUSSRAND)
+ *retval = getGaussianRand(thread, arg1, arg2, threshold);
+ else /* exponential */
+ *retval = getExponentialRand(thread, arg1, arg2, threshold);
+ }
+
+ return true;
+ }
+ case PGBENCH_IDEBUG: /* unary functions */
+ {
+ if (!evalInt(thread, st, args->expr, retval))
+ return false;
+
+ fprintf(stderr, "idebug(script=%d,command=%d): "
+ INT64_FORMAT "\n", st->use_file, st->state+1, *retval);
+
+ return true;
+ }
+ case PGBENCH_ABS: /* both an int & double function */
+ {
+ if (!evalInt(thread, st, args->expr, retval))
+ return false;
+
+ if ((*retval) < 0)
+ *retval = - *retval;
+
+ return true;
+ }
+ case PGBENCH_MIN: /* n-ary, at least one argument */
+ case PGBENCH_MAX:
+ {
+ int64 val = -1;
+ bool first = true;
+ while (args != NULL)
+ {
+ int64 arg;
+
+ if (!evalInt(thread, st, args->expr, &arg))
+ return false;
+
+ if (first)
+ val = arg;
+ else if (func == PGBENCH_MIN)
+ val = val < arg? val: arg;
+ else if (func == PGBENCH_MAX)
+ val = val > arg? val: arg;
+
+ args = args->next;
+ first = false;
+ }
+
+ *retval = val;
+ return true;
+ }
+ case PGBENCH_INT: /* eval as double & cast to int */
+ {
+ double arg;
+
+ if (!evalDouble(thread, st, args->expr, &arg))
+ return false;
+
+ *retval = (int64) arg;
+ return true;
+ }
+ default:
+ {
+ double arg;
+
+ if (!evalDouble(thread, st, expr, &arg))
+ return false;
+
+ *retval = (int64) arg;
+ return true;
+ }
+ }
+ }
+
+ default: /* *MUST* be a double function */
+ {
+ double arg;
+
+ if (!evalDouble(thread, st, expr, &arg))
+ return false;
+
+ *retval = (int64) arg;
+ return true;
+ }
}
fprintf(stderr, "bad expression\n");
@@ -1612,7 +1854,7 @@ top:
PgBenchExpr *expr = commands[st->state]->expr;
int64 result;
- if (!evaluateExpr(st, expr, &result))
+ if (!evalInt(thread, st, expr, &result))
{
st->ecnt++;
return true;
diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h
index 42e2aae..af7abcb 100644
--- a/src/bin/pgbench/pgbench.h
+++ b/src/bin/pgbench/pgbench.h
@@ -14,11 +14,30 @@
typedef enum PgBenchExprType
{
ENODE_INTEGER_CONSTANT,
+ ENODE_DOUBLE_CONSTANT,
ENODE_VARIABLE,
- ENODE_OPERATOR
+ ENODE_OPERATOR,
+ ENODE_FUNCTION
} PgBenchExprType;
+typedef enum PgBenchFunction
+{
+ PGBENCH_NONE,
+ PGBENCH_INT,
+ PGBENCH_DOUBLE,
+ PGBENCH_IDEBUG,
+ PGBENCH_DDEBUG,
+ PGBENCH_ABS,
+ PGBENCH_SQRT,
+ PGBENCH_MIN,
+ PGBENCH_MAX,
+ PGBENCH_RANDOM,
+ PGBENCH_GAUSSRAND,
+ PGBENCH_EXPORAND
+} PgBenchFunction;
+
typedef struct PgBenchExpr PgBenchExpr;
+typedef struct PgBenchExprList PgBenchExprList;
struct PgBenchExpr
{
@@ -31,6 +50,10 @@ struct PgBenchExpr
} integer_constant;
struct
{
+ double dval;
+ } double_constant;
+ struct
+ {
char *varname;
} variable;
struct
@@ -39,14 +62,25 @@ struct PgBenchExpr
PgBenchExpr *lexpr;
PgBenchExpr *rexpr;
} operator;
+ struct
+ {
+ PgBenchFunction function;
+ PgBenchExprList *args;
+ } function;
} u;
};
+struct PgBenchExprList {
+ PgBenchExpr *expr;
+ PgBenchExprList *next;
+};
+
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);
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers