Hi,
psql currently accepts NaN as a \watch interval (and as
WATCH_INTERVAL), and accepts an empty interval= argument. It also
accepts finite command intervals above the limit already enforced for
WATCH_INTERVAL. do_watch() converts the supplied double to long
milliseconds, so NaN and sufficiently large values reach an
out-of-range floating-to-integer conversion.
This patch rejects those inputs before the timer conversion, documents
the interval range, and adds TAP regression cases. It is against
master (633dee1bd1b4). I built PostgreSQL with make -j4 and ran make
-C src/bin/psql check: 149 tests passed (tab completion was skipped
because this build used --without-readline). git diff --check also
passed. The change is not platform-specific. AI assistance helped
identify the edge cases; I reviewed the patch and test results.
The patch is inline below so it is available to reviewers without an attachment.
Regards,
R Sri Vishnu
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 4058caf..7a99134 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -3933,6 +3933,7 @@ SELECT 1 \bind \sendpipeline
until interrupted, or the query fails, or the execution count limit
(if given) is reached, or the query no longer returns the
minimum number
of rows. Wait the specified number of seconds (default 2)
between executions.
+ The interval must be a finite number between 0 and 1000000 seconds.
The default wait can be changed with the variable
<xref linkend="app-psql-variables-watch-interval"/>.
For backwards compatibility,
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index e0c4d7a..51d89cb 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -3433,7 +3433,8 @@ exec_command_watch(PsqlScanState scan_state,
bool active_branch,
have_sleep = true;
errno = 0;
sleep = strtod(valptr, &opt_end);
- if (sleep < 0 || *opt_end || errno == ERANGE)
+ if (!(sleep >= 0 && sleep <= DEFAULT_WATCH_INTERVAL_MAX) ||
+ opt_end == valptr || *opt_end || errno == ERANGE)
{
pg_log_error("\\watch: incorrect interval value \"%s\"", valptr);
success = false;
@@ -3499,7 +3500,8 @@ exec_command_watch(PsqlScanState scan_state,
bool active_branch,
have_sleep = true;
errno = 0;
sleep = strtod(opt, &opt_end);
- if (sleep < 0 || *opt_end || errno == ERANGE)
+ if (!(sleep >= 0 && sleep <= DEFAULT_WATCH_INTERVAL_MAX) ||
+ opt_end == opt || *opt_end || errno == ERANGE)
{
pg_log_error("\\watch: incorrect interval value \"%s\"", opt);
success = false;
diff --git a/src/bin/psql/t/001_basic.pl b/src/bin/psql/t/001_basic.pl
index 028df33..ab3ca2a 100644
--- a/src/bin/psql/t/001_basic.pl
+++ b/src/bin/psql/t/001_basic.pl
@@ -424,6 +424,21 @@ psql_fails_like(
'SELECT 1 \watch 10e400',
qr/incorrect interval value "10e400"/,
'\watch, out-of-range interval');
+psql_fails_like(
+ $node,
+ 'SELECT 1 \watch i=NaN',
+ qr/incorrect interval value "NaN"/,
+ '\watch, NaN interval');
+psql_fails_like(
+ $node,
+ 'SELECT 1 \watch i=',
+ qr/incorrect interval value ""/,
+ '\watch, empty interval');
+psql_fails_like(
+ $node,
+ 'SELECT 1 \watch 1000001',
+ qr/incorrect interval value "1000001"/,
+ '\watch, interval above timer limit');
psql_fails_like(
$node,
'SELECT 1 \watch 1 1',
@@ -452,6 +467,11 @@ psql_fails_like(
'\set WATCH_INTERVAL 1e500',
qr/is out of range/,
'WATCH_INTERVAL variable is out of range');
+psql_fails_like(
+ $node,
+ '\set WATCH_INTERVAL NaN',
+ qr/invalid value "NaN" for variable "WATCH_INTERVAL"/,
+ 'WATCH_INTERVAL rejects NaN');
psql_like($node, '\echo :WATCH_INTERVAL',
qr/^2$/m, 'WATCH_INTERVAL variable was not altered');
diff --git a/src/bin/psql/variables.c b/src/bin/psql/variables.c
index 8060f29..a5f2b2c 100644
--- a/src/bin/psql/variables.c
+++ b/src/bin/psql/variables.c
@@ -212,6 +212,12 @@ ParseVariableDouble(const char *value, const char
*name, double *result, double
dblval = strtod(value, &end);
if (errno == 0 && *end == '\0' && end != value)
{
+ if (isnan(dblval))
+ {
+ if (name)
+ pg_log_error("invalid value \"%s\" for variable \"%s\"", value, name);
+ return false;
+ }
if (dblval < min)
{
if (name)