Here is a simple patch which adds a bunch of operators (bitwise: & | ^ ~, comparisons: =/== <>/!= < <= > >=, logical: and/&& or/|| xor/^^ not/!) and functions (exp ln if) to pgbench. I've tried to be pg's SQL compatible where appropriate.

Also attached is a simple test script.

Here is a sightly updated version.

--
Fabien.
diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml
index f3afedb..ea319f6 100644
--- a/doc/src/sgml/ref/pgbench.sgml
+++ b/doc/src/sgml/ref/pgbench.sgml
@@ -821,9 +821,17 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
       The expression may contain integer constants such as <literal>5432</>,
       double constants such as <literal>3.14159</>,
       references to variables <literal>:</><replaceable>variablename</>,
-      unary operators (<literal>+</>, <literal>-</>) and binary operators
-      (<literal>+</>, <literal>-</>, <literal>*</>, <literal>/</>,
-      <literal>%</>) with their usual precedence and associativity,
+      arithmetic operators (unary: <literal>+</>, <literal>-</>; binary:
+      <literal>+</>, <literal>-</>, <literal>*</>, <literal>/</>, <literal>%</>),
+      bitwise operators (unary: <literal>~</>; binary: <literal>&amp;</>,
+      <literal>|</>, <literal>#</>/<literal>^</>, <literal>&lt;&lt;</>,
+      <literal>&gt;&gt;</>)
+      comparisons (<literal>=</>/<literal>==</>, <literal>&lt;&gt;</>/<literal>!=</>,
+      <literal>&lt;=</>, <literal>&lt;</>, <literal>&gt;=</>, <literal>&gt;</>),
+      logical operators (unary: <literal>not</>/<literal>!</>;
+      binary: <literal>and</>/<literal>&amp;&amp;</>,
+      <literal>or</>/<literal>||</>, <literal>xor</>/<literal>^^</>),
+      with their usual precedence and associativity,
       <link linkend="pgbench-builtin-functions">function calls</>, and
       parentheses.
      </para>
@@ -955,6 +963,13 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
        <entry><literal>5432.0</></>
       </row>
       <row>
+       <entry><literal><function>exp(<replaceable>x</>)</></></>
+       <entry>double</>
+       <entry>exponential</>
+       <entry><literal>exp(1.0)</></>
+       <entry><literal>2.718281828459045</></>
+      </row>
+      <row>
        <entry><literal><function>greatest(<replaceable>a</> [, <replaceable>...</> ] )</></></>
        <entry>double if any <replaceable>a</> is double, else integer</>
        <entry>largest value among arguments</>
@@ -962,6 +977,13 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
        <entry><literal>5</></>
       </row>
       <row>
+       <entry><literal><function>if(<replaceable>c</>,<replaceable>e1</>,<replaceable>e2</>)</></></>
+       <entry>same as <replaceable>e*</></>
+       <entry>if <replaceable>c</> is not zero then <replaceable>e1</> else <replaceable>e2</></>
+       <entry><literal>if(0,1.0,2.0)</></>
+       <entry><literal>2.0</></>
+      </row>
+      <row>
        <entry><literal><function>int(<replaceable>x</>)</></></>
        <entry>integer</>
        <entry>cast to int</>
@@ -976,6 +998,13 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
        <entry><literal>2.1</></>
       </row>
       <row>
+       <entry><literal><function>ln(<replaceable>x</>)</></></>
+       <entry>double</>
+       <entry>natural logarithm</>
+       <entry><literal>ln(2.718281828459045)</></>
+       <entry><literal>1.0</></>
+      </row>
+      <row>
        <entry><literal><function>pi()</></></>
        <entry>double</>
        <entry>value of the constant PI</>
diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y
index 0cc665b..233de9c 100644
--- a/src/bin/pgbench/exprparse.y
+++ b/src/bin/pgbench/exprparse.y
@@ -52,8 +52,22 @@ static PgBenchExpr *make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *
 %type <str> VARIABLE FUNCTION
 
 %token INTEGER_CONST DOUBLE_CONST VARIABLE FUNCTION
+%token AND_OP OR_OP XOR_OP NE_OP LE_OP GE_OP LS_OP RS_OP
 
 /* Precedence: lowest to highest */
+
+/* logical */
+%left	XOR_OP
+%left	OR_OP
+%left	AND_OP
+%right  UNOT
+/* comparison */
+%left	'=' NE_OP
+%left	'<' '>' LE_OP GE_OP
+/* bitwise */
+%left	'^' '|' '&' LS_OP RS_OP
+%right	UINV
+/* arithmetic */
 %left	'+' '-'
 %left	'*' '/' '%'
 %right	UMINUS
@@ -71,11 +85,29 @@ expr: '(' expr ')'			{ $$ = $2; }
 	| '+' expr %prec UMINUS	{ $$ = $2; }
 	| '-' expr %prec UMINUS	{ $$ = make_op(yyscanner, "-",
 										   make_integer_constant(0), $2); }
+	| '~' expr %prec UINV	{ $$ = make_op(yyscanner, "^",
+										   make_integer_constant(-1), $2); }
+	| '!' expr %prec UNOT	{ $$ = make_op(yyscanner, "^^",
+										   make_integer_constant(1), $2); }
 	| expr '+' expr			{ $$ = make_op(yyscanner, "+", $1, $3); }
 	| expr '-' expr			{ $$ = make_op(yyscanner, "-", $1, $3); }
 	| expr '*' expr			{ $$ = make_op(yyscanner, "*", $1, $3); }
 	| expr '/' expr			{ $$ = make_op(yyscanner, "/", $1, $3); }
 	| expr '%' expr			{ $$ = make_op(yyscanner, "%", $1, $3); }
+	| expr '<' expr			{ $$ = make_op(yyscanner, "<", $1, $3); }
+	| expr LE_OP expr		{ $$ = make_op(yyscanner, "<=", $1, $3); }
+	| expr '>' expr			{ $$ = make_op(yyscanner, "<", $3, $1); }
+	| expr GE_OP expr		{ $$ = make_op(yyscanner, "<=", $3, $1); }
+	| expr '=' expr			{ $$ = make_op(yyscanner, "=", $1, $3); }
+	| expr NE_OP expr		{ $$ = make_op(yyscanner, "<>", $1, $3); }
+	| expr '&' expr			{ $$ = make_op(yyscanner, "&", $1, $3); }
+	| expr '|' expr			{ $$ = make_op(yyscanner, "|", $1, $3); }
+	| expr '^' expr			{ $$ = make_op(yyscanner, "^", $1, $3); }
+	| expr LS_OP expr		{ $$ = make_op(yyscanner, "<<", $1, $3); }
+	| expr RS_OP expr		{ $$ = make_op(yyscanner, ">>", $1, $3); }
+	| expr AND_OP expr		{ $$ = make_op(yyscanner, "&&", $1, $3); }
+	| expr OR_OP expr		{ $$ = make_op(yyscanner, "||", $1, $3); }
+	| expr XOR_OP expr		{ $$ = make_op(yyscanner, "^^", $1, $3); }
 	| INTEGER_CONST			{ $$ = make_integer_constant($1); }
 	| DOUBLE_CONST			{ $$ = make_double_constant($1); }
 	| VARIABLE 				{ $$ = make_variable($1); }
@@ -177,6 +209,12 @@ static const struct
 		"sqrt", 1, PGBENCH_SQRT
 	},
 	{
+		"ln", 1, PGBENCH_LN
+	},
+	{
+		"exp", 1, PGBENCH_EXP
+	},
+	{
 		"int", 1, PGBENCH_INT
 	},
 	{
@@ -191,6 +229,45 @@ static const struct
 	{
 		"random_exponential", 3, PGBENCH_RANDOM_EXPONENTIAL
 	},
+	{
+		"&&", 2, PGBENCH_AND
+	},
+	{
+		"||", 2, PGBENCH_OR
+	},
+	{
+		"^^", 2, PGBENCH_XOR
+	},
+	{
+		"&", 2, PGBENCH_BITAND
+	},
+	{
+		"|", 2, PGBENCH_BITOR
+	},
+	{
+		"^", 2, PGBENCH_BITXOR
+	},
+	{
+		"<<", 2, PGBENCH_LSHIFT
+	},
+	{
+		">>", 2, PGBENCH_RSHIFT
+	},
+	{
+		"=", 2, PGBENCH_EQ
+	},
+	{
+		"<>", 2, PGBENCH_NE
+	},
+	{
+		"<=", 2, PGBENCH_LE
+	},
+	{
+		"<", 2, PGBENCH_LT
+	},
+	{
+		"if", 3, PGBENCH_IF
+	},
 	/* keep as last array element */
 	{
 		NULL, 0, 0
diff --git a/src/bin/pgbench/exprscan.l b/src/bin/pgbench/exprscan.l
index 20891a3..0aef58b 100644
--- a/src/bin/pgbench/exprscan.l
+++ b/src/bin/pgbench/exprscan.l
@@ -113,6 +113,29 @@ newline			[\n]
 "*"				{ return '*'; }
 "/"				{ return '/'; }
 "%"				{ return '%'; }
+"="				{ return '='; }
+"=="			{ return '='; }  /* C version */
+"<>"			{ return NE_OP; }
+"!="			{ return NE_OP; }  /* C version */
+"<="			{ return LE_OP; }
+">="			{ return GE_OP; }
+"<<"			{ return LS_OP; }
+">>"			{ return RS_OP; }
+"<"				{ return '<'; }
+">"				{ return '>'; }
+"|"				{ return '|'; }
+"&"				{ return '&'; }
+"#"				{ return '^'; }
+"^"				{ return '^'; }    /* C version */
+"~"				{ return '~'; }
+"and"			{ return AND_OP; }
+"&&"			{ return AND_OP; } /* C version */
+"or"			{ return OR_OP; }
+"||"			{ return OR_OP; }  /* C version */
+"xor"			{ return XOR_OP; } /* should exist */
+"^^"			{ return XOR_OP; } /* should exist */
+"not" 			{ return '!'; }
+"!" 			{ return '!'; }    /* C version */
 "("				{ return '('; }
 ")"				{ return ')'; }
 ","				{ return ','; }
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index 87fb006..d742e2f 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -1189,6 +1189,19 @@ coerceToDouble(PgBenchValue *pval, double *dval)
 	}
 }
 
+static bool coerceToBool(PgBenchValue *pval)
+{
+	if (pval->type == PGBT_DOUBLE)
+	{
+		return pval->u.dval != 0.0;
+	}
+	else
+	{
+		Assert(pval->type == PGBT_INT);
+		return pval->u.ival != 0;
+	}
+}
+
 /* assign an integer value */
 static void
 setIntValue(PgBenchValue *pv, int64 ival)
@@ -1240,6 +1253,10 @@ evalFunc(TState *thread, CState *st,
 		case PGBENCH_MUL:
 		case PGBENCH_DIV:
 		case PGBENCH_MOD:
+		case PGBENCH_EQ:
+		case PGBENCH_NE:
+		case PGBENCH_LE:
+		case PGBENCH_LT:
 			{
 				PgBenchValue *lval = &vargs[0],
 						   *rval = &vargs[1];
@@ -1275,6 +1292,22 @@ evalFunc(TState *thread, CState *st,
 							setDoubleValue(retval, ld / rd);
 							return true;
 
+						case PGBENCH_EQ:
+							setIntValue(retval, ld == rd);
+							return true;
+
+						case PGBENCH_NE:
+							setIntValue(retval, ld != rd);
+							return true;
+
+						case PGBENCH_LE:
+							setIntValue(retval, ld <= rd);
+							return true;
+
+						case PGBENCH_LT:
+							setIntValue(retval, ld < rd);
+							return true;
+
 						default:
 							/* cannot get here */
 							Assert(0);
@@ -1303,6 +1336,22 @@ evalFunc(TState *thread, CState *st,
 							setIntValue(retval, li * ri);
 							return true;
 
+						case PGBENCH_EQ:
+							setIntValue(retval, li == ri);
+							return true;
+
+						case PGBENCH_NE:
+							setIntValue(retval, li != ri);
+							return true;
+
+						case PGBENCH_LE:
+							setIntValue(retval, li <= ri);
+							return true;
+
+						case PGBENCH_LT:
+							setIntValue(retval, li < ri);
+							return true;
+
 						case PGBENCH_DIV:
 						case PGBENCH_MOD:
 							if (ri == 0)
@@ -1343,7 +1392,57 @@ evalFunc(TState *thread, CState *st,
 				}
 			}
 
-			/* no arguments */
+		/* integer operators */
+		case PGBENCH_BITAND:
+		case PGBENCH_BITOR:
+		case PGBENCH_BITXOR:
+		case PGBENCH_LSHIFT:
+		case PGBENCH_RSHIFT:
+			{
+				int64 li, ri;
+
+				if (!coerceToInt(&vargs[0], &li) || !coerceToInt(&vargs[1], &ri))
+					return false;
+
+				if (func == PGBENCH_BITAND)
+					setIntValue(retval, li & ri);
+				else if (func == PGBENCH_BITOR)
+					setIntValue(retval, li | ri);
+				else if (func == PGBENCH_BITXOR)
+					setIntValue(retval, li ^ ri);
+				else if (func == PGBENCH_LSHIFT)
+					setIntValue(retval, li << ri);
+				else if (func == PGBENCH_RSHIFT)
+					setIntValue(retval, li >> ri);
+				else /* cannot get there */
+					Assert(0);
+
+				return true;
+			}
+
+		/* logical operators */
+		case PGBENCH_AND:
+		case PGBENCH_OR:
+		case PGBENCH_XOR:
+			{
+				bool lb, rb;
+
+				lb = coerceToBool(&vargs[0]);
+				rb = coerceToBool(&vargs[1]);
+
+				if (func == PGBENCH_AND)
+					setIntValue(retval, lb && rb);
+				else if (func == PGBENCH_OR)
+					setIntValue(retval, lb || rb);
+				else if (func == PGBENCH_XOR)
+					setIntValue(retval, lb ^ rb);
+				else /* cannot get there */
+					Assert(0);
+
+				return true;
+			}
+
+		/* no arguments */
 		case PGBENCH_PI:
 			setDoubleValue(retval, M_PI);
 			return true;
@@ -1397,6 +1496,8 @@ evalFunc(TState *thread, CState *st,
 			/* 1 double argument */
 		case PGBENCH_DOUBLE:
 		case PGBENCH_SQRT:
+		case PGBENCH_LN:
+		case PGBENCH_EXP:
 			{
 				double		dval;
 
@@ -1407,6 +1508,11 @@ evalFunc(TState *thread, CState *st,
 
 				if (func == PGBENCH_SQRT)
 					dval = sqrt(dval);
+				else if (func == PGBENCH_LN)
+					dval = log(dval);
+				else if (func == PGBENCH_EXP)
+					dval = exp(dval);
+				/* else is cast: do nothing */
 
 				setDoubleValue(retval, dval);
 				return true;
@@ -1558,6 +1664,12 @@ evalFunc(TState *thread, CState *st,
 				return true;
 			}
 
+		case PGBENCH_IF:
+			/* should it do a lazy evaluation of the branch? */
+			Assert(nargs == 3);
+			*retval = coerceToBool(&vargs[0]) ? vargs[1] : vargs[2];
+			return true;
+
 		default:
 			/* cannot get here */
 			Assert(0);
diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h
index ab0f822..5306c40 100644
--- a/src/bin/pgbench/pgbench.h
+++ b/src/bin/pgbench/pgbench.h
@@ -73,9 +73,24 @@ typedef enum PgBenchFunction
 	PGBENCH_DOUBLE,
 	PGBENCH_PI,
 	PGBENCH_SQRT,
+	PGBENCH_LN,
+	PGBENCH_EXP,
 	PGBENCH_RANDOM,
 	PGBENCH_RANDOM_GAUSSIAN,
-	PGBENCH_RANDOM_EXPONENTIAL
+	PGBENCH_RANDOM_EXPONENTIAL,
+	PGBENCH_AND,
+	PGBENCH_OR,
+	PGBENCH_XOR,
+	PGBENCH_BITAND,
+	PGBENCH_BITOR,
+	PGBENCH_BITXOR,
+	PGBENCH_LSHIFT,
+	PGBENCH_RSHIFT,
+	PGBENCH_EQ,
+	PGBENCH_NE,
+	PGBENCH_LE,
+	PGBENCH_LT,
+	PGBENCH_IF
 } PgBenchFunction;
 
 typedef struct PgBenchExpr PgBenchExpr;

Attachment: functions.sql
Description: application/sql

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to