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=&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, 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

Reply via email to