summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Dunstan2017-09-21 23:02:23 +0000
committerAndrew Dunstan2017-09-21 23:02:23 +0000
commitd57c7a7c506276597af619bdb8c62fa5b592745a (patch)
tree6cab776216fa74f256164cbbc7859fbe1fb97b02
parent71480501057fee9fa3649b072173ff10e2b842d0 (diff)
Provide a test for variable existence in psql
"\if :{?variable_name}" will be translated to "\if TRUE" if the variable exists and "\if FALSE" otherwise. Thus it will be possible to execute code conditionally on the existence of the variable, regardless of its value. Fabien Coelho, with some review by Robins Tharakan and some light text editing by me. Discussion: https://postgr.es/m/alpine.DEB.2.20.1708260835520.3627@lancre
-rw-r--r--doc/src/sgml/ref/psql-ref.sgml10
-rw-r--r--src/bin/psql/psqlscanslash.l18
-rw-r--r--src/fe_utils/psqlscan.l42
-rw-r--r--src/include/fe_utils/psqlscan_int.h2
-rw-r--r--src/test/regress/expected/psql.out26
-rw-r--r--src/test/regress/sql/psql.sql18
6 files changed, 115 insertions, 1 deletions
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 60bafa8175..e7a3e17c67 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -783,6 +783,10 @@ testdb=>
The forms <literal>:'<replaceable>variable_name</>'</literal> and
<literal>:"<replaceable>variable_name</>"</literal> described there
work as well.
+ The <literal>:{?<replaceable>variable_name</>}</> syntax allows
+ testing whether a variable is defined. It is substituted by
+ TRUE or FALSE.
+ Escaping the colon with a backslash protects it from substitution.
</para>
<para>
@@ -3939,6 +3943,12 @@ testdb=&gt; <userinput>INSERT INTO my_table VALUES (:'content');</userinput>
</para>
<para>
+ The <literal>:{?<replaceable>name</>}</> special syntax returns TRUE
+ or FALSE depending on whether the variable exists or not, and is thus
+ always substituted, unless the colon is backslash-escaped.
+ </para>
+
+ <para>
The colon syntax for variables is standard <acronym>SQL</acronym> for
embedded query languages, such as <application>ECPG</application>.
The colon syntaxes for array slices and type casts are
diff --git a/src/bin/psql/psqlscanslash.l b/src/bin/psql/psqlscanslash.l
index db7a1b9eea..9a53cb3e02 100644
--- a/src/bin/psql/psqlscanslash.l
+++ b/src/bin/psql/psqlscanslash.l
@@ -281,6 +281,10 @@ other .
unquoted_option_chars = 0;
}
+:\{\?{variable_char}+\} {
+ psqlscan_test_variable(cur_state, yytext, yyleng);
+ }
+
:'{variable_char}* {
/* Throw back everything but the colon */
yyless(1);
@@ -295,6 +299,20 @@ other .
ECHO;
}
+:\{\?{variable_char}* {
+ /* Throw back everything but the colon */
+ yyless(1);
+ unquoted_option_chars++;
+ ECHO;
+ }
+
+:\{ {
+ /* Throw back everything but the colon */
+ yyless(1);
+ unquoted_option_chars++;
+ ECHO;
+ }
+
{other} {
unquoted_option_chars++;
ECHO;
diff --git a/src/fe_utils/psqlscan.l b/src/fe_utils/psqlscan.l
index 27689d72da..4375142a00 100644
--- a/src/fe_utils/psqlscan.l
+++ b/src/fe_utils/psqlscan.l
@@ -745,9 +745,13 @@ other .
PQUOTE_SQL_IDENT);
}
+:\{\?{variable_char}+\} {
+ psqlscan_test_variable(cur_state, yytext, yyleng);
+ }
+
/*
* These rules just avoid the need for scanner backup if one of the
- * two rules above fails to match completely.
+ * three rules above fails to match completely.
*/
:'{variable_char}* {
@@ -762,6 +766,17 @@ other .
ECHO;
}
+:\{\?{variable_char}* {
+ /* Throw back everything but the colon */
+ yyless(1);
+ ECHO;
+ }
+:\{ {
+ /* Throw back everything but the colon */
+ yyless(1);
+ ECHO;
+ }
+
/*
* Back to backend-compatible rules.
*/
@@ -1442,3 +1457,28 @@ psqlscan_escape_variable(PsqlScanState state, const char *txt, int len,
psqlscan_emit(state, txt, len);
}
}
+
+void
+psqlscan_test_variable(PsqlScanState state, const char *txt, int len)
+{
+ char *varname;
+ char *value;
+
+ varname = psqlscan_extract_substring(state, txt + 3, len - 4);
+ if (state->callbacks->get_variable)
+ value = state->callbacks->get_variable(varname, PQUOTE_PLAIN,
+ state->cb_passthrough);
+ else
+ value = NULL;
+ free(varname);
+
+ if (value != NULL)
+ {
+ psqlscan_emit(state, "TRUE", 4);
+ free(value);
+ }
+ else
+ {
+ psqlscan_emit(state, "FALSE", 5);
+ }
+}
diff --git a/src/include/fe_utils/psqlscan_int.h b/src/include/fe_utils/psqlscan_int.h
index c70ff29f4e..e9b351756b 100644
--- a/src/include/fe_utils/psqlscan_int.h
+++ b/src/include/fe_utils/psqlscan_int.h
@@ -142,5 +142,7 @@ extern char *psqlscan_extract_substring(PsqlScanState state,
extern void psqlscan_escape_variable(PsqlScanState state,
const char *txt, int len,
PsqlScanQuoteType quote);
+extern void psqlscan_test_variable(PsqlScanState state,
+ const char *txt, int len);
#endif /* PSQLSCAN_INT_H */
diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out
index 836d8510fd..3818cfea7e 100644
--- a/src/test/regress/expected/psql.out
+++ b/src/test/regress/expected/psql.out
@@ -3014,6 +3014,32 @@ bar 'bar' "bar"
\echo 'should print #8-1'
should print #8-1
\endif
+-- :{?...} defined variable test
+\set i 1
+\if :{?i}
+ \echo '#9-1 ok, variable i is defined'
+#9-1 ok, variable i is defined
+\else
+ \echo 'should not print #9-2'
+\endif
+\if :{?no_such_variable}
+ \echo 'should not print #10-1'
+\else
+ \echo '#10-2 ok, variable no_such_variable is not defined'
+#10-2 ok, variable no_such_variable is not defined
+\endif
+SELECT :{?i} AS i_is_defined;
+ i_is_defined
+--------------
+ t
+(1 row)
+
+SELECT NOT :{?no_such_var} AS no_such_var_is_not_defined;
+ no_such_var_is_not_defined
+----------------------------
+ t
+(1 row)
+
-- SHOW_CONTEXT
\set SHOW_CONTEXT never
do $$
diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql
index ddae1bf1e7..b45da9bb8d 100644
--- a/src/test/regress/sql/psql.sql
+++ b/src/test/regress/sql/psql.sql
@@ -572,6 +572,24 @@ select \if false \\ (bogus \else \\ 42 \endif \\ forty_two;
\echo 'should print #8-1'
\endif
+-- :{?...} defined variable test
+\set i 1
+\if :{?i}
+ \echo '#9-1 ok, variable i is defined'
+\else
+ \echo 'should not print #9-2'
+\endif
+
+\if :{?no_such_variable}
+ \echo 'should not print #10-1'
+\else
+ \echo '#10-2 ok, variable no_such_variable is not defined'
+\endif
+
+SELECT :{?i} AS i_is_defined;
+
+SELECT NOT :{?no_such_var} AS no_such_var_is_not_defined;
+
-- SHOW_CONTEXT
\set SHOW_CONTEXT never