Hello devs,

While investigating moving pgbench expressions to fe_utils so that they can be shared with psql (\if ..., \let ?), I figure out that psql's \if has a syntax to test whether a variable exists, which is not yet available to pgbench.

This patch adds the same syntax to pgbench expression so that they can represent this expression, already accepted by psql's \if.

Note that it is not really that useful for benchmarking, although it does not harm.

--
Fabien.
diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml
index 3dd492c..33d58d5 100644
--- a/doc/src/sgml/ref/pgbench.sgml
+++ b/doc/src/sgml/ref/pgbench.sgml
@@ -909,6 +909,8 @@ pgbench <optional> <replaceable>options</replaceable> </optional> <replaceable>d
       integer constants such as <literal>5432</literal>,
       double constants such as <literal>3.14159</literal>,
       references to variables <literal>:</literal><replaceable>variablename</replaceable>,
+      testing whether a variable exists
+      <literal>:{?</literal><replaceable>variablename</replaceable><literal>}</literal>,
       <link linkend="pgbench-builtin-operators">operators</link>
       with their usual SQL precedence and associativity,
       <link linkend="pgbench-builtin-functions">function calls</link>,
diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y
index e23ca51..ea25b0e 100644
--- a/src/bin/pgbench/exprparse.y
+++ b/src/bin/pgbench/exprparse.y
@@ -24,6 +24,7 @@ static PgBenchExpr *make_boolean_constant(bool bval);
 static PgBenchExpr *make_integer_constant(int64 ival);
 static PgBenchExpr *make_double_constant(double dval);
 static PgBenchExpr *make_variable(char *varname);
+static PgBenchExpr *make_variable_exists(char *varname);
 static PgBenchExpr *make_op(yyscan_t yyscanner, const char *operator,
 		PgBenchExpr *lexpr, PgBenchExpr *rexpr);
 static PgBenchExpr *make_uop(yyscan_t yyscanner, const char *operator, PgBenchExpr *expr);
@@ -55,9 +56,10 @@ static PgBenchExpr *make_case(yyscan_t yyscanner, PgBenchExprList *when_then_lis
 %type <ival> INTEGER_CONST function
 %type <dval> DOUBLE_CONST
 %type <bval> BOOLEAN_CONST
-%type <str> VARIABLE FUNCTION
+%type <str> VARIABLE VAREXISTS FUNCTION
 
-%token NULL_CONST INTEGER_CONST DOUBLE_CONST BOOLEAN_CONST VARIABLE FUNCTION
+%token NULL_CONST INTEGER_CONST DOUBLE_CONST BOOLEAN_CONST
+%token VARIABLE VAREXISTS FUNCTION
 %token AND_OP OR_OP NOT_OP NE_OP LE_OP GE_OP LS_OP RS_OP IS_OP
 %token CASE_KW WHEN_KW THEN_KW ELSE_KW END_KW
 
@@ -136,6 +138,7 @@ expr: '(' expr ')'			{ $$ = $2; }
 	| DOUBLE_CONST			{ $$ = make_double_constant($1); }
 	/* misc */
 	| VARIABLE				{ $$ = make_variable($1); }
+	| VAREXISTS				{ $$ = make_variable_exists($1); }
 	| function '(' elist ')' { $$ = make_func(yyscanner, $1, $3); }
 	| case_control			{ $$ = $1; }
 	;
@@ -209,6 +212,16 @@ make_variable(char *varname)
 
 /* binary operators */
 static PgBenchExpr *
+make_variable_exists(char *varname)
+{
+	PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
+
+	expr->etype = ENODE_VAREXISTS;
+	expr->u.variable.varname = varname;
+	return expr;
+}
+
+static PgBenchExpr *
 make_op(yyscan_t yyscanner, const char *operator,
 		PgBenchExpr *lexpr, PgBenchExpr *rexpr)
 {
diff --git a/src/bin/pgbench/exprscan.l b/src/bin/pgbench/exprscan.l
index 5c1bd88..ff2b586 100644
--- a/src/bin/pgbench/exprscan.l
+++ b/src/bin/pgbench/exprscan.l
@@ -191,6 +191,13 @@ notnull			[Nn][Oo][Tt][Nn][Uu][Ll][Ll]
 					yylval->bval = false;
 					return BOOLEAN_CONST;
 				}
+:\{\?{alnum}+\}	{
+					/* no pg_strndup? */
+					yylval->str = pg_strdup(yytext + 3);
+					/* scratch final '}' */
+					yylval->str[strlen(yylval->str)-1] = '\0';
+					return VAREXISTS;
+				}
 {digit}+		{
 					yylval->ival = strtoint64(yytext);
 					return INTEGER_CONST;
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index d420942..b236116 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -2264,6 +2264,10 @@ evaluateExpr(TState *thread, CState *st, PgBenchExpr *expr, PgBenchValue *retval
 				return true;
 			}
 
+		case ENODE_VAREXISTS:
+				setBoolValue(retval, lookupVariable(st, expr->u.variable.varname) != NULL);
+				return true;
+
 		case ENODE_FUNCTION:
 			return evalFunc(thread, st,
 							expr->u.function.function,
diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h
index 0705ccd..0609802 100644
--- a/src/bin/pgbench/pgbench.h
+++ b/src/bin/pgbench/pgbench.h
@@ -58,6 +58,7 @@ typedef enum PgBenchExprType
 {
 	ENODE_CONSTANT,
 	ENODE_VARIABLE,
+	ENODE_VAREXISTS,
 	ENODE_FUNCTION
 } PgBenchExprType;
 
diff --git a/src/bin/pgbench/t/001_pgbench_with_server.pl b/src/bin/pgbench/t/001_pgbench_with_server.pl
index 99286f6..10c1553 100644
--- a/src/bin/pgbench/t/001_pgbench_with_server.pl
+++ b/src/bin/pgbench/t/001_pgbench_with_server.pl
@@ -259,6 +259,8 @@ pgbench(
 		qr{command=46.: int 46\b},
 		qr{command=47.: boolean true\b},
 		qr{command=48.: boolean true\b},
+		qr{command=58.: boolean false\b}, # var exists
+		qr{command=59.: boolean true\b},
 	],
 	'pgbench expressions',
 	{   '001_pgbench_expressions' => q{-- integer functions
@@ -338,6 +340,9 @@ pgbench(
 \set v2 5432
 \set v3 -54.21E-2
 SELECT :v0, :v1, :v2, :v3;
+-- test variable existence
+\set no debug(:{?no_such_variable})
+\set yes debug(:{?cs})
 } });
 
 # backslash commands

Reply via email to