pgbench: fix misprocessing of some nested \if constructs.
authorTom Lane
Sun, 15 Dec 2024 19:14:15 +0000 (14:14 -0500)
committerTom Lane
Sun, 15 Dec 2024 19:14:15 +0000 (14:14 -0500)
An \if command appearing within a false (not-to-be-executed) \if
branch was incorrectly treated the same as \elif.  This could allow
statements within the inner \if to be executed when they should
not be.  Also the missing inner \if stack entry would result in an
assertion failure (in assert-enabled builds) when the final \endif
is reached.

Report and patch by Michail Nikolaev.  Back-patch to all
supported branches.

Discussion: https://postgr.es/m/CANtu0oiA1ke=SP6tauhNqkUdv5QFsJtS1p=aOOf_iU+EhyKkjQ@mail.gmail.com

src/bin/pgbench/pgbench.c
src/bin/pgbench/t/001_pgbench_with_server.pl

index 6bccacaf86cee4281d2c69d910a4c2311396ebd1..ed301e120c41242a351a2a18a1581fc98820df28 100644 (file)
@@ -3133,8 +3133,14 @@ advanceConnectionState(TState *thread, CState *st, StatsData *agg)
                        switch (conditional_stack_peek(st->cstack))
                        {
                            case IFSTATE_FALSE:
-                               if (command->meta == META_IF ||
-                                   command->meta == META_ELIF)
+                               if (command->meta == META_IF)
+                               {
+                                   /* nested if in skipped branch - ignore */
+                                   conditional_stack_push(st->cstack,
+                                                          IFSTATE_IGNORED);
+                                   st->command++;
+                               }
+                               else if (command->meta == META_ELIF)
                                {
                                    /* we must evaluate the condition */
                                    st->state = CSTATE_START_COMMAND;
@@ -3153,11 +3159,7 @@ advanceConnectionState(TState *thread, CState *st, StatsData *agg)
                                    conditional_stack_pop(st->cstack);
                                    if (conditional_active(st->cstack))
                                        st->state = CSTATE_START_COMMAND;
-
-                                   /*
-                                    * else state remains in
-                                    * CSTATE_SKIP_COMMAND
-                                    */
+                                   /* else state remains CSTATE_SKIP_COMMAND */
                                    st->command++;
                                }
                                break;
index 13fde757fd7a3fad4f0080e131de495a158f5043..a4a7afd64f5a18e8546d989eee272516ad42a8d0 100644 (file)
@@ -623,6 +623,56 @@ SELECT :v0, :v1, :v2, :v3;
 }
    });
 
+# test nested \if constructs
+$node->pgbench(
+   '--no-vacuum --client=1 --transactions=1',
+   0,
+   [qr{actually processed}],
+   [qr{^$}],
+   'nested ifs',
+   {
+       'pgbench_nested_if' => q(
+           \if false
+               SELECT 1 / 0;
+               \if true
+                   SELECT 1 / 0;
+               \elif true
+                   SELECT 1 / 0;
+               \else
+                   SELECT 1 / 0;
+               \endif
+               SELECT 1 / 0;
+           \elif false
+               \if true
+                   SELECT 1 / 0;
+               \elif true
+                   SELECT 1 / 0;
+               \else
+                   SELECT 1 / 0;
+               \endif
+           \else
+               \if false
+                   SELECT 1 / 0;
+               \elif false
+                   SELECT 1 / 0;
+               \else
+                   SELECT 'correct';
+               \endif
+           \endif
+           \if true
+               SELECT 'correct';
+           \else
+               \if true
+                   SELECT 1 / 0;
+               \elif true
+                   SELECT 1 / 0;
+               \else
+                   SELECT 1 / 0;
+               \endif
+           \endif
+       )
+   });
+
 # random determinism when seeded
 $node->safe_psql('postgres',
    'CREATE UNLOGGED TABLE seeded_random(seed INT8 NOT NULL, rand TEXT NOT NULL, val INTEGER NOT NULL);'