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.

Patch v2 is a rebase.

--
Fabien.
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 <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 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 <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
 
@@ -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

Reply via email to