psql: Fix \watch when using interval values less than 1ms
authorMichael Paquier <michael@paquier.xyz>
Mon, 14 Oct 2024 03:28:01 +0000 (12:28 +0900)
committerMichael Paquier <michael@paquier.xyz>
Mon, 14 Oct 2024 03:28:01 +0000 (12:28 +0900)
Attempting to use an interval of time less than 1ms would cause \watch
to hang.  This was confusing, so let's change the logic so as an
interval lower than 1ms behaves the same as 0.

Comments are added to mention that the internals of do_watch() had
better rely on "sleep_ms", the interval value in milliseconds.  While on
it, this commit adds a test to check the behavior of interval values
less than 1ms.

\watch hanging for interval values less than 1ms existed before
6f9ee74d45aa, that has changed the code to support an interval value of
0.

Reported-by: Heikki Linnakangas
Author: Andrey M. Borodin, Michael Paquier
Discussion: https://postgr.es/m/88445e0e-3156-4b9d-afae-9a1a7b1631f6@iki.fi
Backpatch-through: 16

src/bin/psql/command.c
src/bin/psql/t/001_basic.pl

index d0ae44232651184c1ef40b2b06ae8f35e7263077..d0ee47b517dee3d3abadc8f7c40a1defd2b2126b 100644 (file)
@@ -5142,6 +5142,10 @@ do_shell(const char *command)
  *
  * We break this out of exec_command to avoid having to plaster "volatile"
  * onto a bunch of exec_command's variables to silence stupider compilers.
+ *
+ * "sleep" is the amount of time to sleep during each loop, measured in
+ * seconds.  The internals of this function should use "sleep_ms" for
+ * precise sleep time calculations.
  */
 static bool
 do_watch(PQExpBuffer query_buf, double sleep, int iter)
@@ -5267,10 +5271,10 @@ do_watch(PQExpBuffer query_buf, double sleep, int iter)
 
        if (user_title)
            snprintf(title, title_len, _("%s\t%s (every %gs)\n"),
-                    user_title, timebuf, sleep);
+                    user_title, timebuf, sleep_ms / 1000.0);
        else
            snprintf(title, title_len, _("%s (every %gs)\n"),
-                    timebuf, sleep);
+                    timebuf, sleep_ms / 1000.0);
        myopt.title = title;
 
        /* Run the query and print out the result */
@@ -5290,7 +5294,8 @@ do_watch(PQExpBuffer query_buf, double sleep, int iter)
        if (pagerpipe && ferror(pagerpipe))
            break;
 
-       if (sleep == 0)
+       /* Tight loop, no wait needed */
+       if (sleep_ms == 0)
            continue;
 
 #ifdef WIN32
index 9ac27db212046f9e7627539e570c4410b6eb9364..3599cc1ef09b8761ed1c8af82ce03302b947515d 100644 (file)
@@ -352,8 +352,14 @@ psql_like(
 
 # Check \watch
 # Note: the interval value is parsed with locale-aware strtod()
-psql_like($node, sprintf('SELECT 1 \watch c=3 i=%g', 0.01),
-   qr/1\n1\n1/, '\watch with 3 iterations');
+psql_like(
+   $node, sprintf('SELECT 1 \watch c=3 i=%g', 0.01),
+   qr/1\n1\n1/, '\watch with 3 iterations, interval of 0.01');
+
+# Sub-millisecond wait works, equivalent to 0.
+psql_like(
+   $node, sprintf('SELECT 1 \watch c=3 i=%g', 0.0001),
+   qr/1\n1\n1/, '\watch with 3 iterations, interval of 0.0001');
 
 # Check \watch errors
 psql_fails_like(