[HACKERS] pow support for pgbench
Hi, I've written a small patch to add support for pow() in pgbench. The main reason behind it is that I'm currently using a shell call to do it which takes between 2-10 ms that can be a big percentage of the time taken by the whole transaction. For example (shortened): latency average = 11.718 ms - statement latencies in milliseconds: 2.834 \setshell POWER2 awk 'BEGIN {p=2^ARGV[1]; print p }' :ZOOM_CURRENT 8.846 SELECT ST_AsBinary(ST_Simplify(ST_SnapToGrid("the_geom_webmercator",:SNAP), :SIMPLIFY)) AS geom FROM I've also updated the related docs and added some tests. Please let me know if I'm missing anything. Regards, *Raúl Marín Rodríguez* carto.com From 08a4d519e0c73d0f16acd9e5db9e5b547a884902 Mon Sep 17 00:00:00 2001 From: Raul Marin Date: Fri, 13 Oct 2017 17:42:23 +0200 Subject: [PATCH] Add pow() support to pgbench --- doc/src/sgml/ref/pgbench.sgml| 7 +++ src/bin/pgbench/exprparse.y | 3 +++ src/bin/pgbench/pgbench.c| 9 + src/bin/pgbench/pgbench.h| 3 ++- src/bin/pgbench/t/001_pgbench_with_server.pl | 7 ++- 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml index e509e6c7f62..e12a149c5bb 100644 --- a/doc/src/sgml/ref/pgbench.sgml +++ b/doc/src/sgml/ref/pgbench.sgml @@ -1022,6 +1022,13 @@ pgbench options d sqrt(2.0) 1.414213562 + + pow(x, y) + double if x or y are doubles, else integer + Numeric exponentiation + pow(2.0, 10) + 1024.0/ + diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y index b3a2d9bfd37..4db3b215abf 100644 --- a/src/bin/pgbench/exprparse.y +++ b/src/bin/pgbench/exprparse.y @@ -191,6 +191,9 @@ static const struct { "random_exponential", 3, PGBENCH_RANDOM_EXPONENTIAL }, + { + "pow", 2, PGBENCH_POW + }, /* keep as last array element */ { NULL, 0, 0 diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 5d8a01c72cf..a3aef108f84 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -1346,6 +1346,7 @@ evalFunc(TState *thread, CState *st, case PGBENCH_MUL: case PGBENCH_DIV: case PGBENCH_MOD: + case PGBENCH_POW: { PgBenchValue *lval = &vargs[0], *rval = &vargs[1]; @@ -1381,6 +1382,10 @@ evalFunc(TState *thread, CState *st, setDoubleValue(retval, ld / rd); return true; + case PGBENCH_POW: + setDoubleValue(retval, pow(ld, rd)); + return true; + default: /* cannot get here */ Assert(0); @@ -1442,6 +1447,10 @@ evalFunc(TState *thread, CState *st, return true; + case PGBENCH_POW: + setIntValue(retval, pow(li, ri)); + return true; + default: /* cannot get here */ Assert(0); diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h index fd428af274f..e0132b5fcf6 100644 --- a/src/bin/pgbench/pgbench.h +++ b/src/bin/pgbench/pgbench.h @@ -75,7 +75,8 @@ typedef enum PgBenchFunction PGBENCH_SQRT, PGBENCH_RANDOM, PGBENCH_RANDOM_GAUSSIAN, - PGBENCH_RANDOM_EXPONENTIAL + PGBENCH_RANDOM_EXPONENTIAL, + PGBENCH_POW } PgBenchFunction; typedef struct PgBenchExpr PgBenchExpr; diff --git a/src/bin/pgbench/t/001_pgbench_with_server.pl b/src/bin/pgbench/t/001_pgbench_with_server.pl index 11bc0fecfef..601c7ee0e4d 100644 --- a/src/bin/pgbench/t/001_pgbench_with_server.pl +++ b/src/bin/pgbench/t/001_pgbench_with_server.pl @@ -218,7 +218,9 @@ sub pgbench qr{command=18.: double 18\b}, qr{command=19.: double 19\b}, qr{command=20.: double 20\b}, - qr{command=21.: int 9223372036854775807\b}, ], + qr{command=21.: int 9223372036854775807\b}, + qr{command=23.: int -27\b}, + qr{command=24.: double 1024\b}, ], 'pgbench expressions', { '001_pgbench_expressions' => q{-- integer functions \set i1 debug(random(1, 100)) @@ -248,6 +250,9 @@ sub pgbench \set maxint debug(:minint - 1) -- reset a variable \set i1 0 +--- pow() operator +\set poweri debug(pow(-3,3)) +\set powerd debug(pow(2.0,10)) } }); # backslash commands -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] pow support for pgbench
Sorry about the patch. Attaching it now so it can be considered as submitted. -- *Raúl Marín Rodríguez*carto.com From a6eecfe6637bdb0cbb02a9eda7b88d9c4325bb51 Mon Sep 17 00:00:00 2001 From: Raul Marin Date: Fri, 13 Oct 2017 17:42:23 +0200 Subject: [PATCH] Add pow() support to pgbench --- doc/src/sgml/ref/pgbench.sgml| 7 +++ src/bin/pgbench/exprparse.y | 3 +++ src/bin/pgbench/pgbench.c| 9 + src/bin/pgbench/pgbench.h| 3 ++- src/bin/pgbench/t/001_pgbench_with_server.pl | 5 + 5 files changed, 26 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml index 1f55967e40a..2e913dfcfd6 100644 --- a/doc/src/sgml/ref/pgbench.sgml +++ b/doc/src/sgml/ref/pgbench.sgml @@ -1233,6 +1233,13 @@ pgbench options d sqrt(2.0) 1.414213562 + + pow(x, y) + double if x or y are doubles, else integer + Numeric exponentiation + pow(2.0, 10) + 1024.0/ + diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y index 770be981f06..290bca99d12 100644 --- a/src/bin/pgbench/exprparse.y +++ b/src/bin/pgbench/exprparse.y @@ -334,6 +334,9 @@ static const struct { "!case_end", -2, PGBENCH_CASE }, + { + "pow", 2, PGBENCH_POW + }, /* keep as last array element */ { NULL, 0, 0 diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index add653bf90c..b2bab9b8239 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -1474,6 +1474,7 @@ evalFunc(TState *thread, CState *st, case PGBENCH_NE: case PGBENCH_LE: case PGBENCH_LT: + case PGBENCH_POW: { PgBenchValue *lval = &vargs[0], *rval = &vargs[1]; @@ -1525,6 +1526,10 @@ evalFunc(TState *thread, CState *st, setBoolValue(retval, ld < rd); return true; + case PGBENCH_POW: + setDoubleValue(retval, pow(ld, rd)); + return true; + default: /* cannot get here */ Assert(0); @@ -1602,6 +1607,10 @@ evalFunc(TState *thread, CState *st, return true; + case PGBENCH_POW: + setIntValue(retval, pow(li, ri)); + return true; + default: /* cannot get here */ Assert(0); diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h index e1277a1dde6..9f26af92bf6 100644 --- a/src/bin/pgbench/pgbench.h +++ b/src/bin/pgbench/pgbench.h @@ -94,7 +94,8 @@ typedef enum PgBenchFunction PGBENCH_LE, PGBENCH_LT, PGBENCH_IS, - PGBENCH_CASE + PGBENCH_CASE, + PGBENCH_POW } PgBenchFunction; typedef struct PgBenchExpr PgBenchExpr; diff --git a/src/bin/pgbench/t/001_pgbench_with_server.pl b/src/bin/pgbench/t/001_pgbench_with_server.pl index 8e19bbd3f45..81b7ce4dfcc 100644 --- a/src/bin/pgbench/t/001_pgbench_with_server.pl +++ b/src/bin/pgbench/t/001_pgbench_with_server.pl @@ -237,6 +237,8 @@ sub pgbench qr{command=36.: int 36\b}, qr{command=37.: boolean true\b}, qr{command=38.: boolean true\b}, + qr{command=44.: int -27\b}, + qr{command=45.: double 1024\b}, ], 'pgbench expressions', { '001_pgbench_expressions' => q{-- integer functions @@ -299,6 +301,9 @@ sub pgbench \set v2 5432 \set v3 -54.21E-2 SELECT :v0, :v1, :v2, :v3; +--- pow() operator +\set poweri debug(pow(-3,3)) +\set powerd debug(pow(2.0,10)) } }); =head -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] pow support for pgbench
Hi, both patches seem complementary. I've rebased my changes on top of that patch (v14) in https://git.io/vFtnT and everything seems to be working fine. On Mon, Oct 30, 2017 at 12:36 PM, Michael Paquier wrote: > On Mon, Oct 30, 2017 at 11:07 AM, Alvaro Herrera > wrote: > > Michael Paquier wrote: > > > >> Please add this patch to the upcoming commit fest if you would like to > >> get some feedback: > >> https://commitfest.postgresql.org/15/ > >> > >> I am adding as well Fabien in CC who worked in getting the internal > >> function infrastructure in the shape it is now (waaay better) with > >> commit 86c43f4. > > > > I think Raúl would do well to review this patch by Fabien > > https://www.postgresql.org/message-id/alpine.DEB.2.20. > 1710201835390.15170@lancre > > which adds a few functions and operators. > > Good idea. pow() is not added by Fabien's patch, but an operator for > pow() could be something to add as well. > -- > Michael > -- *Raúl Marín Rodríguez*carto.com
Re: [HACKERS] pow support for pgbench
Hi Fabien, Thanks for the review. I've fixed the documentation and added an ipow function that handles both positive and negative ints, having 0^0 == 1 and 0^(negative) == PG_INT64_MAX since that's what my glibc math.h pow() is returning. On Sat, Nov 4, 2017 at 12:34 PM, Fabien COELHO wrote: > > Hello Raúl, > > Sorry about the patch. Attaching it now so it can be considered as >> submitted. >> > > There is a typo in the XML doc: > > 1024.0/ > > Please check that the documentation compiles. > > I'm at odds with having the integer version rely on a double pow(), even > if it works. I think that there should be a specific integer version which > does use integer operations. From stack overflow, the following is > suggested: > > int ipow(int base, int exp) > { > int result = 1; > while (exp) > { > if (exp & 1) > result *= base; > exp >>= 1; > base *= base; > } > > return result; > } > > The integer version should be when x & y are integers *AND* y >= 0. > > if y is a negative integer, the double version should be used. > > -- > Fabien. -- *Raúl Marín Rodríguez*carto.com From 09105f8108e439834510ee5fb53036473f2977d5 Mon Sep 17 00:00:00 2001 From: Raul Marin Date: Fri, 13 Oct 2017 17:42:23 +0200 Subject: [PATCH] Add pow() support to pgbench --- doc/src/sgml/ref/pgbench.sgml| 7 src/bin/pgbench/exprparse.y | 3 ++ src/bin/pgbench/pgbench.c| 54 src/bin/pgbench/pgbench.h| 3 +- src/bin/pgbench/t/001_pgbench_with_server.pl | 9 + 5 files changed, 75 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml index 1f55967e40a..4e7f75ddf87 100644 --- a/doc/src/sgml/ref/pgbench.sgml +++ b/doc/src/sgml/ref/pgbench.sgml @@ -1233,6 +1233,13 @@ pgbench options d sqrt(2.0) 1.414213562 + + pow(x, y) + double if x or y are doubles, else integer + Numeric exponentiation + pow(2.0, 10) + 1024.0 + diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y index 770be981f06..290bca99d12 100644 --- a/src/bin/pgbench/exprparse.y +++ b/src/bin/pgbench/exprparse.y @@ -334,6 +334,9 @@ static const struct { "!case_end", -2, PGBENCH_CASE }, + { + "pow", 2, PGBENCH_POW + }, /* keep as last array element */ { NULL, 0, 0 diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index add653bf90c..bdf3e97682a 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -739,6 +739,51 @@ getPoissonRand(TState *thread, int64 center) } /* + * pow() for integer values + */ +static int64 +ipow(int64 base, int64 exp) +{ + int64 result; + + if (base == 0) + { + if (exp > 0) + return 0; + else if (exp == 0) + return 1; + return PG_INT64_MAX; + } + + /* + * For exp > 0 calculate normally + * For exp == 0 return 1 * sign of base + * For exp < 0 return 0 except when the base is 1 or -1 + */ + if (exp > 0) + { + result = 1; + while (exp) + { + if (exp & 1) +result *= base; + exp >>= 1; + base *= base; + } + } + else if (exp == 0) + result = (base > 0) - (base < 0); + else + { + result = 1 / base; + if (exp % 2 == 0) + result *= result; + } + + return result; +} + +/* * Initialize the given SimpleStats struct to all zeroes */ static void @@ -1474,6 +1519,7 @@ evalFunc(TState *thread, CState *st, case PGBENCH_NE: case PGBENCH_LE: case PGBENCH_LT: + case PGBENCH_POW: { PgBenchValue *lval = &vargs[0], *rval = &vargs[1]; @@ -1525,6 +1571,10 @@ evalFunc(TState *thread, CState *st, setBoolValue(retval, ld < rd); return true; + case PGBENCH_POW: + setDoubleValue(retval, pow(ld, rd)); + return true; + default: /* cannot get here */ Assert(0); @@ -1602,6 +1652,10 @@ evalFunc(TState *thread, CState *st, return true; + case PGBENCH_POW: + setIntValue(retval, ipow(li, ri)); + return true; + default: /* cannot get here */ Assert(0); diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h index e1277a1dde6..9f26af92bf6 100644 --- a/src/bin/pgbench/pgbench.h +++ b/src/bin/pgbench/pgbench.h @@ -94,7 +94,8 @@ typedef enum PgBenchFunction PGBENCH_LE, PGBENCH_LT, PGBENCH_IS, - PGBENCH_CASE + PGBENCH_CASE, + PGBENCH_POW } PgBenchFunction; typedef struct PgBenchExpr PgBenchExpr; diff --git a/src/bin/pgbench/t/001_pgbench_with_server.pl b/src/bin/pgbench/t/001_pgbench_with_server.pl index 8e19bbd3f45..c5ecd749c40 100644 --- a/src/bin/pgbench/t/001_pgbench_with_server.pl +++ b/src/bin/pgbench/t/001_pgb
Re: [HACKERS] pow support for pgbench
Hi Fabien, Sorry for the confusion, I wasn't aware that SQL pow changed types depending on the input value. I've modified the function to match more closely the behaviour of SQL, except that 0^(negative) returns 'double inf'. Do you think there is any value in raising an error instead? On Mon, Nov 6, 2017 at 2:12 PM, Fabien COELHO wrote: > > Hello Raúl, > > I've fixed the documentation and added an ipow function that handles both >> positive and negative ints, having 0^0 == 1 and 0^(negative) == >> PG_INT64_MAX >> since that's what my glibc math.h pow() is returning. >> > > From the comment: > > * For exp < 0 return 0 except when the base is 1 or -1 > > I think that it should do what POW does in psql, i.e.: > > fabien=# SELECT POW(2, -2); # 0.25 > > that is if exp < 0 the double version should be used, it should > not return 0. > > Basically the idea is that the pgbench client-side version should behave > the same as the SQL version. > > -- > Fabien. -- *Raúl Marín Rodríguez*carto.com From be2fedcae277f7eede621dcda66b15b08372ce63 Mon Sep 17 00:00:00 2001 From: Raul Marin Date: Fri, 13 Oct 2017 17:42:23 +0200 Subject: [PATCH] Add pow() support to pgbench --- doc/src/sgml/ref/pgbench.sgml| 7 +++ src/bin/pgbench/exprparse.y | 3 + src/bin/pgbench/pgbench.c| 84 src/bin/pgbench/pgbench.h| 3 +- src/bin/pgbench/t/001_pgbench_with_server.pl | 13 + 5 files changed, 109 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml index 1f55967e40a..32c94ba0dc1 100644 --- a/doc/src/sgml/ref/pgbench.sgml +++ b/doc/src/sgml/ref/pgbench.sgml @@ -1233,6 +1233,13 @@ pgbench options d sqrt(2.0) 1.414213562 + + pow(x, y) + integer if x and y are integers and y >= 0, else double + Numeric exponentiation + pow(2.0, 10) + 1024.0 + diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y index 770be981f06..290bca99d12 100644 --- a/src/bin/pgbench/exprparse.y +++ b/src/bin/pgbench/exprparse.y @@ -334,6 +334,9 @@ static const struct { "!case_end", -2, PGBENCH_CASE }, + { + "pow", 2, PGBENCH_POW + }, /* keep as last array element */ { NULL, 0, 0 diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index add653bf90c..d565880b6e2 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -739,6 +739,51 @@ getPoissonRand(TState *thread, int64 center) } /* + * pow() for integer values + */ +static int64 +ipow(int64 base, int64 exp) +{ + int64 result; + + if (base == 0) + { + if (exp > 0) + return 0; + else if (exp == 0) + return 1; + return PG_INT64_MAX; + } + + /* + * For exp > 0 calculate normally + * For exp == 0 return 1 * sign of base + * For exp < 0 return 0 except when the base is 1 or -1 + */ + if (exp > 0) + { + result = 1; + while (exp) + { + if (exp & 1) +result *= base; + exp >>= 1; + base *= base; + } + } + else if (exp == 0) + result = (base > 0) - (base < 0); + else + { + result = 1 / base; + if (exp % 2 == 0) + result *= result; + } + + return result; +} + +/* * Initialize the given SimpleStats struct to all zeroes */ static void @@ -1918,6 +1963,45 @@ evalFunc(TState *thread, CState *st, return true; } + case PGBENCH_POW: + { +PgBenchValue *lval = &vargs[0]; +PgBenchValue *rval = &vargs[1]; +double ld, + rd; + +Assert(nargs == 2); + +/* + * If both operands are int and exp >= 0 use + * the ipow() function, else use pow() + */ +if (lval->type == PGBT_INT && + rval->type == PGBT_INT) +{ + + int64 li, +ri; + + if (!coerceToInt(lval, &li) || + !coerceToInt(rval, &ri)) + return false; + + if (ri >= 0) + { + setIntValue(retval, ipow(li, ri)); + return true; + } +} + +if (!coerceToDouble(lval, &ld) || + !coerceToDouble(rval, &rd)) + return false; + +setDoubleValue(retval, pow(ld, rd)); +return true; + } + default: /* cannot get here */ Assert(0); diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h index e1277a1dde6..9f26af92bf6 100644 --- a/src/bin/pgbench/pgbench.h +++ b/src/bin/pgbench/pgbench.h @@ -94,7 +94,8 @@ typedef enum PgBenchFunction PGBENCH_LE, PGBENCH_LT, PGBENCH_IS, - PGBENCH_CASE + PGBENCH_CASE, + PGBENCH_POW } PgBenchFunction; typedef struct PgBenchExpr PgBenchExpr; diff --git a/src/bin/pgbench/t/001_pgbench_with_server.pl b/src/bin/pgbench/t/001_pgbench_with_server.pl index 8e19bbd3f45..2a1bb1216d7 100644 --- a/src/bin/pgbench/t/001_pgbench_with_server.pl +++ b/src/bi
Re: [HACKERS] pow support for pgbench
Hi, Indeed, this is quite strange... I don't want to go too deep into it, but you get stuff like this: Select pow(2.0, -3)::text = pow(2, -3)::text; ?column? -- f (1 row) - you can simplify the ipow function by removing handling of y<0 case, >maybe add an assert to be sure to avoid it. I agree, done. - you should add more symmetry and simplify the evaluation: Done too. Add a test case to show what happens on NULL arguments, hopefully the > result is NULL. Done and it does. Thanks again for the review. On Mon, Nov 6, 2017 at 4:14 PM, Fabien COELHO wrote: > > Hello, > > Sorry for the confusion, I wasn't aware that SQL pow changed types >> depending on the input value. >> > > Indeed, this is quite strange... > > fabien=# SELECT i, POW(2, i) FROM generate_series(-2, 2) AS i; >-2 | 0.25 >-1 | 0.5 > 0 | 1 > 1 | 2 > 2 | 4 > > I've modified the function to match more closely the behaviour of SQL, >> except that 0^(negative) returns 'double inf'. Do you think there is any >> value in raising an error instead? >> > > fabien=# SELECT POW(0,-1); > ERROR: zero raised to a negative power is undefined > > H... I'm fine with double inf, because exception in pgbench means the > end of the script, which is not desirable for benchmarking purposes. > > I think that: > > - you can simplify the ipow function by removing handling of y<0 case, >maybe add an assert to be sure to avoid it. > > - you should add more symmetry and simplify the evaluation: > >if (int & int) >{ > i1, i2 = ...; > if (i2 >= 0) > setIntValue(retval, ipow(i1, i2)); > else > // conversion is done by C, no need to coerce again > setDoubleValue(retval, pow(i1, i2)); >} >else > { > d1, d2 = ...; > setDoubleValue(retval, pow(d1, d2)); >} > > Add a test case to show what happens on NULL arguments, hopefully the > result is NULL. > > -- > Fabien. > -- *Raúl Marín Rodríguez *carto.com From 47f6ec396d3bc11c39066dbd4b31e75b76102094 Mon Sep 17 00:00:00 2001 From: Raul Marin Date: Fri, 13 Oct 2017 17:42:23 +0200 Subject: [PATCH] Add pow() support to pgbench --- doc/src/sgml/ref/pgbench.sgml| 7 src/bin/pgbench/exprparse.y | 3 ++ src/bin/pgbench/pgbench.c| 62 src/bin/pgbench/pgbench.h| 3 +- src/bin/pgbench/t/001_pgbench_with_server.pl | 15 +++ 5 files changed, 89 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml index 1f55967e40a..32c94ba0dc1 100644 --- a/doc/src/sgml/ref/pgbench.sgml +++ b/doc/src/sgml/ref/pgbench.sgml @@ -1233,6 +1233,13 @@ pgbench options d sqrt(2.0) 1.414213562 + + pow(x, y) + integer if x and y are integers and y >= 0, else double + Numeric exponentiation + pow(2.0, 10) + 1024.0 + diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y index 770be981f06..290bca99d12 100644 --- a/src/bin/pgbench/exprparse.y +++ b/src/bin/pgbench/exprparse.y @@ -334,6 +334,9 @@ static const struct { "!case_end", -2, PGBENCH_CASE }, + { + "pow", 2, PGBENCH_POW + }, /* keep as last array element */ { NULL, 0, 0 diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index add653bf90c..3781e75721d 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -739,6 +739,27 @@ getPoissonRand(TState *thread, int64 center) } /* + * pow() for integer values with exp >= 0. Matches SQL pow() behaviour + */ +static int64 +ipow(int64 base, int64 exp) +{ + int64 result = 1; + + Assert(exp >= 0); + + while (exp) + { + if (exp & 1) + result *= base; + exp >>= 1; + base *= base; + } + + return result; +} + +/* * Initialize the given SimpleStats struct to all zeroes */ static void @@ -1918,6 +1939,47 @@ evalFunc(TState *thread, CState *st, return true; } + case PGBENCH_POW: + { +PgBenchValue *lval = &vargs[0]; +PgBenchValue *rval = &vargs[1]; + +Assert(nargs == 2); + +/* + * If both operands are int and exp >= 0 use + * the ipow() function, else use pow() + */ +if (lval->type == PGBT_INT && + rval->type == PGBT_INT) +{ + + int64 li, +ri; + + if (!coerceToInt(lval, &li) || + !coerceToInt(rval, &ri)) + return false; + + if (ri >= 0) + setIntValue(retval, ipow(li, ri)); + else + setDoubleValue(retval, pow(li, ri)); +} +else +{ + double ld, +rd; + + if (!coerceToDouble(lval, &ld)