Revised patch, with one caveat: It contains copy/pasted code from
variable.c intended to bridge the gap until https://commitfest.postgresql.
org/12/799/  (changing ParseVariableBool to detect invalid boolean-ish
strings) is merged. We may want to pause full-review of this patch pending
resolution of that one. I'm happy to continue with the stop-gap in place.

Changes made:
- \elseif is now \elif
- Invalid boolean values now return an error
- ON_ERROR_STOP is respected in all errors raided by \if, \elsif, \else,
\endif commands.
- Documentation gives a more real-world example of usage.
- Documentation gives a more explicit list of valid boolean values
- Regression tests for out-of-place \endif, \else, and \endif
- Regression test for invalid boolean values
- Removal of debug detritus.

Changes not(yet) made:
- No TAP test for errors respecting ON_ERROR_STOP
- function comments in psqlscan.l follow the style found in other comments
there, which goes counter to global style.


On Tue, Jan 24, 2017 at 3:58 AM, Fabien COELHO <coe...@cri.ensmp.fr> wrote:

>
> I would suggest to assume false on everything else, and/or maybe to ignore
>>> the whole if/endif section in such cases.
>>>
>>
>> +1, it also halves the number of values we have to support later.
>>
>
> After giving it some thought, I revise a little bit my opinion:
>
>
> I think that if the value is evaluated to TRUE or FALSE, then fine. If it
> is anything else, then an error is raised (error message shown), which
> should also stop the script on "ON_ERROR_STOP", and if not the script
> continues with assuming the value was FALSE.
>
> --
> Fabien.
>
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 9915731..20091e5 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -2007,6 +2007,78 @@ hello 10
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><literal>\if</literal> <replaceable 
class="parameter">expr</replaceable></term>
+        <term><literal>\elif</literal> <replaceable 
class="parameter">expr</replaceable></term>
+        <term><literal>\else</literal></term>
+        <term><literal>\endif</literal></term>
+        <listitem>
+        <para>
+        This group of commands implements nestable conditional blocks, like
+        this:
+        </para>
+<programlisting>
+SELECT
+    EXISTS(SELECT 1 FROM customer) as has_customers,
+    EXISTS(SELECT 1 FROM employee) as has_employees
+\gset
+\if :has_users
+    SELECT * FROM customer ORDER BY creation_date LIMIT 5;
+\elif :has_employees
+    \echo 'no customers found'
+    SELECT * FROM employee ORDER BY creation_date LIMIT 5;
+\else
+    \if yes
+        \echo 'No customers or employees'
+    \else
+        \echo 'this should never print'
+    \endif
+\endif
+</programlisting>
+        <para>
+        Conditional blocks must begin with a <command>\if</command> and end
+        with an <command>\endif</command>, and the pairs must be found in
+        the same source file. If an EOF is reached on the main file or an
+        <command>\include</command>-ed file before all 
+        <command>\if</command>-<command>\endif</command> are matched, then
+        psql will raise an error.
+        </para>
+        <para>
+        The <command>\if</command> and <command>\elif</command> commands
+        read the rest of the line and evaluate it as a boolean expression.
+        Currently, expressions are limited to a single unquoted string
+        which is evaluated like other options booleans, so the valid values
+        are any unabiguous case insensitive matches for one of:
+        <literal>true</literal>, <literal>false</literal>, 
<literal>1</literal>,
+        <literal>0</literal>, <literal>on</literal>, <literal>off</literal>,
+        <literal>yes</literal>, <literal>no</literal>.  So 
+        <literal>t</literal>, <literal>T</literal>, and <literal>tR</literal>
+        will all match <literal>true</literal>.
+        </para>
+        <para>
+        Queries within a false branch of a conditional block will not be
+        sent to the server.
+        </para>
+        <para>
+        Non-conditional <command>\</command>-commands within a false branch
+        of a conditional block will not be evaluated for correctness. The
+        command will be ignored along with all remaining input to the end
+        of the line.
+        </para>
+        <para>
+        Expressions on <command>\if</command> and <command>\elif</command>
+        commands within a false branch of a conditional block will not be
+        evaluated.
+        </para>
+        <para>
+        A conditional block can at most one <command>\else</command> command.
+        </para>
+        <para>
+        The <command>\elif</command> command cannot follow the
+        <command>\else</command> command.
+        </para>
+        </listitem>
+      </varlistentry>
 
       <varlistentry>
         <term><literal>\ir</literal> or <literal>\include_relative</literal> 
<replaceable class="parameter">filename</replaceable></term>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 4139b77..feb9ddc 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -49,6 +49,7 @@
 #include "psqlscanslash.h"
 #include "settings.h"
 #include "variables.h"
+#include "fe_utils/psqlscan_int.h"
 
 /*
  * Editable database object types.
@@ -132,7 +133,7 @@ HandleSlashCmds(PsqlScanState scan_state,
                status = PSQL_CMD_ERROR;
        }
 
-       if (status != PSQL_CMD_ERROR)
+       if (status != PSQL_CMD_ERROR && psqlscan_branch_active(scan_state))
        {
                /* eat any remaining arguments after a valid command */
                /* note we suppress evaluation of backticks here */
@@ -194,6 +195,68 @@ read_connect_arg(PsqlScanState scan_state)
        return result;
 }
 
+/*
+ * Read and interpret argument as a boolean expression.
+ * Return true if a boolean value was successfully parsed.
+ */
+static bool
+read_boolean_expression(PsqlScanState scan_state, char *action,
+                                               bool *result)
+{
+       bool    success = false;
+       char    *value = psql_scan_slash_option(scan_state,
+                                                                               
        OT_NORMAL, NULL, false);
+       /*
+        * placeholder code until ParseVariableBool() ads error detection
+        * once that patch is in place, use that instead
+        */
+       if (value)
+       {
+               size_t          len;
+
+               if (value == NULL)
+                       return false;                   /* not set -> assume 
"off" */
+
+               len = strlen(value);
+
+               if ((pg_strncasecmp(value, "true", len) == 0) ||
+                       (pg_strncasecmp(value, "yes", len) == 0) ||
+                       (pg_strncasecmp(value, "on", (len > 2 ? len : 2)) == 0) 
||
+                       (pg_strcasecmp(value, "1") == 0))
+               {
+                       success = true;
+                       *result = true;
+               }
+               else if ((pg_strncasecmp(value, "false", len) == 0) ||
+                                (pg_strncasecmp(value, "no", len) == 0) ||
+                                (pg_strncasecmp(value, "off", (len > 2 ? len : 
2)) == 0) ||
+                                (pg_strcasecmp(value, "0") == 0))
+               {
+                       success = true;
+                       *result = false;
+               }
+               else
+               {
+                       psql_error("\\%s: invalid boolean expression: %s\n",
+                                               action, value);
+               }
+               free(value);
+       }
+       else
+       {
+               psql_error("\\%s: no expression given\n",action);
+       }
+       return success;
+}
+
+static bool
+is_branching_command(const char *cmd)
+{
+       return ((strcmp(cmd, "if") == 0 || \
+                       strcmp(cmd, "elif") == 0 || \
+                       strcmp(cmd, "else") == 0 || \
+                       strcmp(cmd, "endif") == 0));
+}
 
 /*
  * Subroutine to actually try to execute a backslash command.
@@ -207,6 +270,14 @@ exec_command(const char *cmd,
                                                                 * failed */
        backslashResult status = PSQL_CMD_SKIP_LINE;
 
+       if (!psqlscan_branch_active(scan_state) && !is_branching_command(cmd) )
+       {
+               /* Continue with an empty buffer as if the command were never 
read */
+               resetPQExpBuffer(query_buf);
+               psql_scan_reset(scan_state);
+               return status;
+       }
+
        /*
         * \a -- toggle field alignment This makes little sense but we keep it
         * around.
@@ -984,6 +1055,114 @@ exec_command(const char *cmd,
                }
        }
 
+       else if (strcmp(cmd, "if") == 0)
+       {
+               ifState new_if_state = IFSTATE_IGNORED;
+               if (psqlscan_branch_active(scan_state))
+               {
+                       bool if_true = false;
+                       success = read_boolean_expression(scan_state, "if", 
&if_true);
+                       if (success)
+                       {
+                               if (if_true)
+                                       new_if_state = IFSTATE_TRUE;
+                               else
+                                       new_if_state = IFSTATE_FALSE;
+                       }
+               }
+               if (success)
+                       psqlscan_branch_push(scan_state,new_if_state);
+               psql_scan_reset(scan_state);
+       }
+
+       else if (strcmp(cmd, "elif") == 0)
+       {
+               if (psqlscan_branch_empty(scan_state))
+               {
+                       psql_error("encountered un-matched \\elif\n");
+                       success = false;
+               }
+               else
+               {
+                       bool elif_true = false;
+                       switch (psqlscan_branch_get_state(scan_state))
+                       {
+                               case IFSTATE_IGNORED:
+                                       /* inactive branch, do nothing */
+                                       break;
+                               case IFSTATE_TRUE:
+                                       /* just finished true section of active 
branch */
+                                       psqlscan_branch_set_state(scan_state, 
IFSTATE_IGNORED);
+                                       break;
+                               case IFSTATE_FALSE:
+                                       /* determine if this section is true or 
not */
+                                       success = 
read_boolean_expression(scan_state, "elif",
+                                                                               
                                &elif_true);
+                                       if (success)
+                                       {
+                                               if (elif_true)
+                                                       
psqlscan_branch_set_state(scan_state, IFSTATE_TRUE);
+                                       }
+                                       break;
+                               case IFSTATE_ELSE_TRUE:
+                               case IFSTATE_ELSE_FALSE:
+                                       psql_error("encountered \\elif after 
\\else\n");
+                                       success = false;
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               psql_scan_reset(scan_state);
+       }
+
+       else if (strcmp(cmd, "else") == 0)
+       {
+               if (psqlscan_branch_empty(scan_state))
+               {
+                       psql_error("encountered un-matched \\else\n");
+                       success = false;
+               }
+               else
+               {
+                       switch (psqlscan_branch_get_state(scan_state))
+                       {
+                               case IFSTATE_TRUE:
+                                       /* just finished true section of active 
branch */
+                               case IFSTATE_IGNORED:
+                                       /* whole branch was inactive */
+                                       psqlscan_branch_set_state(scan_state, 
IFSTATE_ELSE_FALSE);
+                                       break;
+                               case IFSTATE_FALSE:
+                                       /* just finished true section of active 
branch */
+                                       psqlscan_branch_set_state(scan_state, 
IFSTATE_ELSE_TRUE);
+                                       break;
+                               case IFSTATE_ELSE_TRUE:
+                               case IFSTATE_ELSE_FALSE:
+                                       psql_error("encountered \\else after 
\\else\n");
+                                       success = false;
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               psql_scan_reset(scan_state);
+       }
+
+       else if (strcmp(cmd, "endif") == 0)
+       {
+               if (psqlscan_branch_empty(scan_state))
+               {
+                       psql_error("encountered un-matched \\endif\n");
+                       success = false;
+               }
+               else
+               {
+                       psqlscan_branch_end_state(scan_state);
+               }
+               psql_scan_reset(scan_state);
+       }
+
        /* \l is list databases */
        else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0 ||
                         strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0)
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
index bb306a4..7252824 100644
--- a/src/bin/psql/mainloop.c
+++ b/src/bin/psql/mainloop.c
@@ -15,7 +15,7 @@
 #include "settings.h"
 
 #include "mb/pg_wchar.h"
-
+#include "fe_utils/psqlscan_int.h"
 
 /* callback functions for our flex lexer */
 const PsqlScanCallbacks psqlscan_callbacks = {
@@ -23,7 +23,6 @@ const PsqlScanCallbacks psqlscan_callbacks = {
        psql_error
 };
 
-
 /*
  * Main processing loop for reading lines of input
  *     and sending them to the backend.
@@ -51,6 +50,9 @@ MainLoop(FILE *source)
        volatile int count_eof = 0;
        volatile bool die_on_error = false;
 
+       /* only needed at the end to detect unbalanced ifs in scan_state */
+       bool if_endifs_balanced = true;
+
        /* Save the prior command source */
        FILE       *prev_cmd_source;
        bool            prev_cmd_interactive;
@@ -285,21 +287,28 @@ MainLoop(FILE *source)
                        if (scan_result == PSCAN_SEMICOLON ||
                                (scan_result == PSCAN_EOL && pset.singleline))
                        {
-                               /*
-                                * Save query in history.  We use history_buf 
to accumulate
-                                * multi-line queries into a single history 
entry.
-                                */
-                               if (pset.cur_cmd_interactive && 
!line_saved_in_history)
+                               if (psqlscan_branch_active(scan_state))
                                {
-                                       pg_append_history(line, history_buf);
-                                       pg_send_history(history_buf);
-                                       line_saved_in_history = true;
+                                       /*
+                                        * Save query in history.  We use 
history_buf to accumulate
+                                        * multi-line queries into a single 
history entry.
+                                        */
+                                       if (pset.cur_cmd_interactive && 
!line_saved_in_history)
+                                       {
+                                               pg_append_history(line, 
history_buf);
+                                               pg_send_history(history_buf);
+                                               line_saved_in_history = true;
+                                       }
+
+                                       /* execute query */
+                                       success = SendQuery(query_buf->data);
                                }
+                               else
+                                       success = true;
 
-                               /* execute query */
-                               success = SendQuery(query_buf->data);
                                slashCmdStatus = success ? PSQL_CMD_SEND : 
PSQL_CMD_ERROR;
                                pset.stmt_lineno = 1;
+                               slashCmdStatus = success ? PSQL_CMD_SEND : 
PSQL_CMD_ERROR;
 
                                /* transfer query to previous_buf by 
pointer-swapping */
                                {
@@ -358,15 +367,21 @@ MainLoop(FILE *source)
 
                                if (slashCmdStatus == PSQL_CMD_SEND)
                                {
-                                       success = SendQuery(query_buf->data);
-
-                                       /* transfer query to previous_buf by 
pointer-swapping */
+                                       if (psqlscan_branch_active(scan_state))
                                        {
-                                               PQExpBuffer swap_buf = 
previous_buf;
+                                               success = 
SendQuery(query_buf->data);
 
-                                               previous_buf = query_buf;
-                                               query_buf = swap_buf;
+                                               /* transfer query to 
previous_buf by pointer-swapping */
+                                               {
+                                                       PQExpBuffer swap_buf = 
previous_buf;
+
+                                                       previous_buf = 
query_buf;
+                                                       query_buf = swap_buf;
+                                               }
                                        }
+                                       else
+                                               success = true;
+
                                        resetPQExpBuffer(query_buf);
 
                                        /* flush any paren nesting info after 
forced send */
@@ -425,12 +440,17 @@ MainLoop(FILE *source)
        if (query_buf->len > 0 && !pset.cur_cmd_interactive &&
                successResult == EXIT_SUCCESS)
        {
-               /* save query in history */
-               if (pset.cur_cmd_interactive)
-                       pg_send_history(history_buf);
+               if (psqlscan_branch_active(scan_state))
+               {
+                       /* save query in history */
+                       if (pset.cur_cmd_interactive)
+                               pg_send_history(history_buf);
 
-               /* execute query */
-               success = SendQuery(query_buf->data);
+                       /* execute query */
+                       success = SendQuery(query_buf->data);
+               }
+               else
+                       success = true;
 
                if (!success && die_on_error)
                        successResult = EXIT_USER;
@@ -451,11 +471,17 @@ MainLoop(FILE *source)
        destroyPQExpBuffer(previous_buf);
        destroyPQExpBuffer(history_buf);
 
+       if (slashCmdStatus != PSQL_CMD_TERMINATE)
+               if_endifs_balanced = psqlscan_branch_empty(scan_state);
+
        psql_scan_destroy(scan_state);
 
        pset.cur_cmd_source = prev_cmd_source;
        pset.cur_cmd_interactive = prev_cmd_interactive;
        pset.lineno = prev_lineno;
 
+       if (! if_endifs_balanced )
+               psql_error("found EOF before closing \\endif(s)\n");
+
        return successResult;
 }      /* MainLoop() */
diff --git a/src/bin/psql/mainloop.h b/src/bin/psql/mainloop.h
index 228a5e0..47f4c32 100644
--- a/src/bin/psql/mainloop.h
+++ b/src/bin/psql/mainloop.h
@@ -14,4 +14,5 @@ extern const PsqlScanCallbacks psqlscan_callbacks;
 
 extern int     MainLoop(FILE *source);
 
+
 #endif   /* MAINLOOP_H */
diff --git a/src/fe_utils/psqlscan.l b/src/fe_utils/psqlscan.l
index 1b29341..f70841c 100644
--- a/src/fe_utils/psqlscan.l
+++ b/src/fe_utils/psqlscan.l
@@ -904,6 +904,9 @@ psql_scan_create(const PsqlScanCallbacks *callbacks)
 
        psql_scan_reset(state);
 
+       state->branch_stack = NULL;
+       state->branch_block_active = true;
+
        return state;
 }
 
@@ -919,6 +922,13 @@ psql_scan_destroy(PsqlScanState state)
 
        yylex_destroy(state->scanner);
 
+       while (state->branch_stack != NULL)
+       {
+               IfStackElem *p = state->branch_stack;
+               state->branch_stack = state->branch_stack->next;
+               free(p);
+       }
+
        free(state);
 }
 
@@ -1426,3 +1436,103 @@ psqlscan_escape_variable(PsqlScanState state, const 
char *txt, int len,
                psqlscan_emit(state, txt, len);
        }
 }
+
+/*
+ * psqlscan_branch_empty
+ *
+ * True if there are no active \if-structures
+ */
+bool
+psqlscan_branch_empty(PsqlScanState state)
+{
+       return (state->branch_stack == NULL);
+}
+
+/*
+ * psqlscan_branch_active
+ *
+ * True if the current \if-block (if any) is true and queries/commands
+ * should be executed.
+ */
+bool
+psqlscan_branch_active(PsqlScanState state)
+{
+       return state->branch_block_active;
+}
+
+/*
+ * Fetch the current state of the top of the stack
+ */
+ifState
+psqlscan_branch_get_state(PsqlScanState state)
+{
+       if (psqlscan_branch_empty(state))
+               return IFSTATE_NONE;
+       return state->branch_stack->if_state;
+}
+
+/*
+ * psqlscan_branch_update_active
+ *
+ * Scan the branch_stack to determine whether the next statements
+ * can execute or should be skipped. Cache this result in
+ * branch_block_active.
+ */
+static void
+psqlscan_branch_update_active(PsqlScanState state)
+{
+       ifState s = psqlscan_branch_get_state(state);
+       state->branch_block_active  = ( (s == IFSTATE_NONE) ||
+                                                                       (s == 
IFSTATE_TRUE) ||
+                                                                       (s == 
IFSTATE_ELSE_TRUE));
+}
+
+/*
+ * psqlscan_branch_push
+ *
+ * Create a new \if branch.
+ */
+bool
+psqlscan_branch_push(PsqlScanState state, ifState new_state)
+{
+       IfStackElem *p = pg_malloc0(sizeof(IfStackElem));
+       p->if_state = new_state;
+       p->next = state->branch_stack;
+       state->branch_stack = p;
+       psqlscan_branch_update_active(state);
+       return true;
+}
+
+/*
+ * psqlscan_branch_set_state
+ *
+ * Change the state of the topmost branch.
+ * Returns false if there was branch state to set.
+ */
+bool
+psqlscan_branch_set_state(PsqlScanState state, ifState new_state)
+{
+       if (psqlscan_branch_empty(state))
+               return false;
+       state->branch_stack->if_state = new_state;
+       psqlscan_branch_update_active(state);
+       return true;
+}
+
+/*
+ * psqlscan_branch_end_state
+ *
+ * Destroy the topmost branch because and \endif was encountered.
+ * Returns false if there was no branch to end.
+ */
+bool
+psqlscan_branch_end_state(PsqlScanState state)
+{
+       IfStackElem *p = state->branch_stack;
+       if (!p)
+               return false;
+       state->branch_stack = state->branch_stack->next;
+       free(p);
+       psqlscan_branch_update_active(state);
+       return true;
+}
diff --git a/src/include/fe_utils/psqlscan_int.h 
b/src/include/fe_utils/psqlscan_int.h
index 0fddc7a..734e719 100644
--- a/src/include/fe_utils/psqlscan_int.h
+++ b/src/include/fe_utils/psqlscan_int.h
@@ -75,6 +75,30 @@ typedef struct StackElem
        struct StackElem *next;
 } StackElem;
 
+typedef enum _ifState
+{
+       IFSTATE_NONE = 0,       /* Not currently in an \if block */
+       IFSTATE_TRUE,           /* currently in an \if or \elif which is true
+                                                * and all parent branches (if 
any) are true */
+       IFSTATE_FALSE,          /* currently in an \if or \elif which is false
+                                                * but no true branch has yet 
been seen,
+                                                * and all parent branches (if 
any) are true */
+       IFSTATE_IGNORED,        /* currently in an \elif which follows a true 
\if
+                                                * or the whole \if is a child 
of a false parent */
+       IFSTATE_ELSE_TRUE,      /* currently in an \else which is true
+                                                * and all parent branches (if 
any) are true */
+       IFSTATE_ELSE_FALSE      /* currently in an \else which is false or 
ignored */
+} ifState;
+
+/*
+ * The state of nested ifs is stored in a stack.
+ */
+typedef struct IfStackElem
+{
+       ifState         if_state;
+       struct IfStackElem *next;
+} IfStackElem;
+
 /*
  * All working state of the lexer must be stored in PsqlScanStateData
  * between calls.  This allows us to have multiple open lexer operations,
@@ -118,6 +142,12 @@ typedef struct PsqlScanStateData
         * Callback functions provided by the program making use of the lexer.
         */
        const PsqlScanCallbacks *callbacks;
+
+       /*
+        * \if branch state variables
+        */
+       IfStackElem *branch_stack;
+       bool branch_block_active;
 } PsqlScanStateData;
 
 
@@ -141,4 +171,21 @@ extern void psqlscan_escape_variable(PsqlScanState state,
                                                 const char *txt, int len,
                                                 bool as_ident);
 
+/*
+ * branching commands
+ */
+extern bool psqlscan_branch_empty(PsqlScanState state);
+
+extern bool psqlscan_branch_active(PsqlScanState state);
+
+extern ifState psqlscan_branch_get_state(PsqlScanState state);
+
+extern bool psqlscan_branch_push(PsqlScanState state,
+                                                                       ifState 
new_state);
+
+extern bool psqlscan_branch_set_state(PsqlScanState state,
+                                                                       ifState 
new_state);
+
+extern bool psqlscan_branch_end_state(PsqlScanState state);
+
 #endif   /* PSQLSCAN_INT_H */
diff --git a/src/test/regress/expected/psql.out 
b/src/test/regress/expected/psql.out
index 464436a..1dcaa46 100644
--- a/src/test/regress/expected/psql.out
+++ b/src/test/regress/expected/psql.out
@@ -2686,6 +2686,66 @@ deallocate q;
 \pset format aligned
 \pset expanded off
 \pset border 1
+\if true
+       \if 1
+               \if yes
+                       \if on
+                               \echo 'all true'
+all true
+                       \else
+                               \echo 'should not print #1-1'
+                       \endif
+               \else
+                       \echo 'should not print #1-2'
+               \endif
+       \else
+               \echo 'should not print #1-3'
+       \endif
+\else 
+       \echo 'should not print #1-4'
+\endif
+\if false
+       \echo 'should not print #2-1'
+\elif 0
+       \echo 'should not print #2-2'
+\elif no
+       \echo 'should not print #2-3'
+\elif off
+       \echo 'should not print #2-4'
+\else
+       \echo 'all false'
+all false
+\endif
+\if true
+       \echo 'first thing true'
+first thing true
+\else
+       \echo 'should not print #3-1'
+\endif
+\if false
+       \echo 'should not print #4-1'
+\elif true
+       \echo 'second thing true'
+second thing true
+\else
+       \echo 'should not print #5-1'
+\endif
+\endif
+encountered un-matched \endif
+\else
+encountered un-matched \else
+\elif
+encountered un-matched \elif
+\if true
+\else
+\else
+encountered \else after \else
+\endif
+\if false
+\else
+\elif
+encountered \elif after \else
+\endif
 -- SHOW_CONTEXT
 \set SHOW_CONTEXT never
 do $$
diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql
index 900aa7e..4f41894 100644
--- a/src/test/regress/sql/psql.sql
+++ b/src/test/regress/sql/psql.sql
@@ -357,6 +357,66 @@ deallocate q;
 \pset expanded off
 \pset border 1
 
+\if true
+       \if 1
+               \if yes
+                       \if on
+                               \echo 'all true'
+                       \else
+                               \echo 'should not print #1-1'
+                       \endif
+               \else
+                       \echo 'should not print #1-2'
+               \endif
+       \else
+               \echo 'should not print #1-3'
+       \endif
+\else
+       \echo 'should not print #1-4'
+\endif
+
+\if false
+       \echo 'should not print #2-1'
+\elif 0
+       \echo 'should not print #2-2'
+\elif no
+       \echo 'should not print #2-3'
+\elif off
+       \echo 'should not print #2-4'
+\else
+       \echo 'all false'
+\endif
+
+\if true
+       \echo 'first thing true'
+\else
+       \echo 'should not print #3-1'
+\endif
+
+\if false
+       \echo 'should not print #4-1'
+\elif true
+       \echo 'second thing true'
+\else
+       \echo 'should not print #5-1'
+\endif
+
+\endif
+
+\else
+
+\elif
+
+\if true
+\else
+\else
+\endif
+
+\if false
+\else
+\elif
+\endif
+
 -- 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