diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml
index d52d324..5092628 100644
--- a/doc/src/sgml/ref/pgbench.sgml
+++ b/doc/src/sgml/ref/pgbench.sgml
@@ -929,6 +929,8 @@ pgbench options d
integer constants such as 5432,
double constants such as 3.14159,
references to variables :variablename,
+ testing whether a variable exists
+ :{?variablename},
operators
with their usual SQL precedence and associativity,
function calls,
diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y
index 8447e14..2f89142 100644
--- a/src/bin/pgbench/exprparse.y
+++ b/src/bin/pgbench/exprparse.y
@@ -28,6 +28,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);
@@ -59,9 +60,10 @@ static PgBenchExpr *make_case(yyscan_t yyscanner, PgBenchExprList *when_then_lis
%type INTEGER_CONST function
%type DOUBLE_CONST
%type BOOLEAN_CONST
-%type VARIABLE FUNCTION
+%type 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
@@ -140,6 +142,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; }
;
@@ -213,6 +216,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 894571e..e08d268 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -2356,6 +2356,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 6983865..284443e 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 7448a96..f1032f2 100644
--- a/src/bin/pgbench/t/001_pgbench_with_server.pl
+++ b/src/bin/pgbench/t/001_pgbench_with_server.pl
@@ -270,6 +270,8 @@ pgbench(
qr{command=86.: int 86\b},
qr{command=93.: int 93\b},
qr{command=95.: int 0\b},
+ qr{command=96.: boolean false\b}, # var exists
+ qr{command=97.: boolean true\b},
],
'pgbench expressions',
{ '001_pgbench_expressions' => q{-- integer functions
@@ -390,6 +392,9 @@ SELECT :v0, :v1, :v2, :v3;
\endif
-- must be zero if false branches where skipped
\set nope debug(:nope)
+-- test variable existence
+\set no debug(:{?no_such_variable})
+\set yes debug(:{?cs})
} });
# backslash commands