Any colon prefixed syntax can be made to work because it is enough for the
lexer to detect and handle... so
:{defined varname}
may be an option, although I do not like the space much because it adds some
fuzzyness in the lexer which has to process it. It is probably doable,
though. I like having a "?" because there is a question. Other
suggestions somehow in line with your proposal could be
:{?varname}
:{varname?}
what do you think?
Here is a version with the :{?varname} syntax.
--
Fabien.
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index c592eda..58f8e9a 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -781,6 +781,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
+ to test whether a variable is defined. It is substituted by
+ TRUE or FALSE.
+ Escaping the colon with a backslash protects it from substitution.
</para>
<para>
@@ -3813,6 +3817,12 @@ testdb=> <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, thus is
+ 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 db7a1b9..9a53cb3 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 27689d7..4375142a 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 c70ff29..e9b3517 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 4aaf4c1..2b2f23b 100644
--- a/src/test/regress/expected/psql.out
+++ b/src/test/regress/expected/psql.out
@@ -2929,6 +2929,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 4a676c3..436dbb8 100644
--- a/src/test/regress/sql/psql.sql
+++ b/src/test/regress/sql/psql.sql
@@ -536,6 +536,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
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers