aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Gustafsson <dgustafsson@postgresql.org>2025-03-25 17:53:33 +0100
committerDaniel Gustafsson <dgustafsson@postgresql.org>2025-03-25 17:53:33 +0100
commit1a759c83278fcdae11ee5da8318b646b9d47129c (patch)
tree6b61dad74bd7337ac9c950bb5343ee18c3915caa /src
parenta19db082749662a933d0bf72722982b1ee2c4725 (diff)
downloadpostgresql-1a759c83278fcdae11ee5da8318b646b9d47129c.tar.gz
postgresql-1a759c83278fcdae11ee5da8318b646b9d47129c.zip
psql: Make default \watch interval configurable
The default interval for \watch to wait between executing queries, when executed without a specified interval, was hardcoded to two seconds. This adds the new variable WATCH_INTERVAL which is used to set the default interval, making it configurable for the user. This makes \watch the first command which has a user configurable default setting. Author: Daniel Gustafsson <daniel@yesql.se> Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi> Reviewed-by: Michael Paquier <michael@paquier.xyz> Reviewed-by: Kirill Reshke <reshkekirill@gmail.com> Reviewed-by: Masahiro Ikeda <ikedamsh@oss.nttdata.com> Reviewed-by: Laurenz Albe <laurenz.albe@cybertec.at> Reviewed-by: Greg Sabino Mullane <htamfids@gmail.com> Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com> Discussion: https://postgr.es/m/B2FD26B4-8F64-4552-A603-5CC3DF1C7103@yesql.se
Diffstat (limited to 'src')
-rw-r--r--src/bin/psql/command.c6
-rw-r--r--src/bin/psql/help.c2
-rw-r--r--src/bin/psql/settings.h7
-rw-r--r--src/bin/psql/startup.c18
-rw-r--r--src/bin/psql/t/001_basic.pl24
-rw-r--r--src/bin/psql/variables.c70
-rw-r--r--src/bin/psql/variables.h3
7 files changed, 128 insertions, 2 deletions
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index bbe337780ff..a8a13c2b88b 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -3278,7 +3278,7 @@ exec_command_watch(PsqlScanState scan_state, bool active_branch,
bool have_sleep = false;
bool have_iter = false;
bool have_min_rows = false;
- double sleep = 2;
+ double sleep = pset.watch_interval;
int iter = 0;
int min_rows = 0;
@@ -3292,7 +3292,9 @@ exec_command_watch(PsqlScanState scan_state, bool active_branch,
/*
* Parse arguments. We allow either an unlabeled interval or
* "name=value", where name is from the set ('i', 'interval', 'c',
- * 'count', 'm', 'min_rows').
+ * 'count', 'm', 'min_rows'). The parsing of interval value should be
+ * kept in sync with ParseVariableDouble which is used for setting the
+ * default interval value.
*/
while (success)
{
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index e47cad24de9..fe96e3e1de9 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -460,6 +460,8 @@ helpVariables(unsigned short int pager)
" VERSION_NAME\n"
" VERSION_NUM\n"
" psql's version (in verbose string, short string, or numeric format)\n");
+ HELP0(" WATCH_INTERVAL\n"
+ " number of seconds \\watch by default waits between executing the query buffer\n");
HELP0("\nDisplay settings:\n");
HELP0("Usage:\n");
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
index 71f553c22ad..fd82303f776 100644
--- a/src/bin/psql/settings.h
+++ b/src/bin/psql/settings.h
@@ -27,6 +27,12 @@
#define DEFAULT_PROMPT2 "%/%R%x%# "
#define DEFAULT_PROMPT3 ">> "
+#define DEFAULT_WATCH_INTERVAL "2"
+/*
+ * Limit the max default setting to a value which should be safe for the
+ * itimer call, yet large enough to cover all realistic usecases.
+ */
+#define DEFAULT_WATCH_INTERVAL_MAX (1000*1000)
/*
* Note: these enums should generally be chosen so that zero corresponds
* to the default behavior.
@@ -166,6 +172,7 @@ typedef struct _psqlSettings
int fetch_count;
int histsize;
int ignoreeof;
+ double watch_interval;
PSQL_ECHO echo;
PSQL_ECHO_HIDDEN echo_hidden;
PSQL_ERROR_ROLLBACK on_error_rollback;
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 5018eedf1e5..249b6aa5169 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -945,6 +945,21 @@ histsize_hook(const char *newval)
}
static char *
+watch_interval_substitute_hook(char *newval)
+{
+ if (newval == NULL)
+ newval = pg_strdup(DEFAULT_WATCH_INTERVAL);
+ return newval;
+}
+
+static bool
+watch_interval_hook(const char *newval)
+{
+ return ParseVariableDouble(newval, "WATCH_INTERVAL", &pset.watch_interval,
+ 0, DEFAULT_WATCH_INTERVAL_MAX);
+}
+
+static char *
ignoreeof_substitute_hook(char *newval)
{
int dummy;
@@ -1270,4 +1285,7 @@ EstablishVariableSpace(void)
SetVariableHooks(pset.vars, "HIDE_TABLEAM",
bool_substitute_hook,
hide_tableam_hook);
+ SetVariableHooks(pset.vars, "WATCH_INTERVAL",
+ watch_interval_substitute_hook,
+ watch_interval_hook);
}
diff --git a/src/bin/psql/t/001_basic.pl b/src/bin/psql/t/001_basic.pl
index dca34ac975a..7192d96049d 100644
--- a/src/bin/psql/t/001_basic.pl
+++ b/src/bin/psql/t/001_basic.pl
@@ -375,6 +375,12 @@ 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');
+# Test zero interval
+psql_like(
+ $node, '\set WATCH_INTERVAL 0
+SELECT 1 \watch c=3',
+ qr/1\n1\n1/, '\watch with 3 iterations, interval of 0');
+
# Check \watch minimum row count
psql_fails_like(
$node,
@@ -426,6 +432,24 @@ psql_fails_like(
qr/iteration count is specified more than once/,
'\watch, iteration count is specified more than once');
+# Check WATCH_INTERVAL
+psql_like(
+ $node,
+ '\echo :WATCH_INTERVAL
+\set WATCH_INTERVAL 0.001
+\echo :WATCH_INTERVAL
+\unset WATCH_INTERVAL
+\echo :WATCH_INTERVAL',
+ qr/^2$
+^0.001$
+^2$/m,
+ 'WATCH_INTERVAL variable is set and updated');
+psql_fails_like(
+ $node,
+ '\set WATCH_INTERVAL 1e500',
+ qr/is out of range/,
+ 'WATCH_INTERVAL variable is out of range');
+
# Test \g output piped into a program.
# The program is perl -pe '' to simply copy the input to the output.
my $g_file = "$tempdir/g_file_1.out";
diff --git a/src/bin/psql/variables.c b/src/bin/psql/variables.c
index 59956028918..5150eb0532b 100644
--- a/src/bin/psql/variables.c
+++ b/src/bin/psql/variables.c
@@ -7,6 +7,8 @@
*/
#include "postgres_fe.h"
+#include <math.h>
+
#include "common.h"
#include "common/logging.h"
#include "variables.h"
@@ -180,6 +182,74 @@ ParseVariableNum(const char *value, const char *name, int *result)
}
/*
+ * Try to interpret "value" as a double value, and if successful store it in
+ * *result. If unsuccessful, *result isn't clobbered. "name" is the variable
+ * which is being assigned, the value of which is only used to produce a good
+ * error message. Pass NULL as the name to suppress the error message. The
+ * value must be within the range [min,max] in order to be considered valid.
+ *
+ * Returns true, with *result containing the interpreted value, if "value" is
+ * syntactically valid, else false (with *result unchanged).
+ */
+bool
+ParseVariableDouble(const char *value, const char *name, double *result, double min, double max)
+{
+ char *end;
+ double dblval;
+
+ /*
+ * Empty-string input has historically been treated differently by strtod
+ * on various platforms, so handle that by specifically checking for it.
+ */
+ if ((value == NULL) || (*value == '\0'))
+ {
+ if (name)
+ pg_log_error("invalid input syntax for \"%s\"", name);
+ return false;
+ }
+
+ errno = 0;
+ dblval = strtod(value, &end);
+ if (errno == 0 && *end == '\0' && end != value)
+ {
+ if (dblval < min)
+ {
+ if (name)
+ pg_log_error("invalid value \"%s\" for \"%s\": must be greater than %.2f",
+ value, name, min);
+ return false;
+ }
+ else if (dblval > max)
+ {
+ if (name)
+ pg_log_error("invalid value \"%s\" for \"%s\": must be less than %.2f",
+ value, name, max);
+ }
+ *result = dblval;
+ return true;
+ }
+
+ /*
+ * Cater for platforms which treat values which aren't zero, but that are
+ * too close to zero to have full precision, by checking for zero or real
+ * out-of-range values.
+ */
+ else if ((errno = ERANGE) &&
+ (dblval == 0.0 || dblval >= HUGE_VAL || dblval <= -HUGE_VAL))
+ {
+ if (name)
+ pg_log_error("\"%s\" is out of range for \"%s\"", value, name);
+ return false;
+ }
+ else
+ {
+ if (name)
+ pg_log_error("invalid value \"%s\" for \"%s\"", value, name);
+ return false;
+ }
+}
+
+/*
* Print values of all variables.
*/
void
diff --git a/src/bin/psql/variables.h b/src/bin/psql/variables.h
index a95bc29f407..df23ccb987d 100644
--- a/src/bin/psql/variables.h
+++ b/src/bin/psql/variables.h
@@ -81,6 +81,9 @@ bool ParseVariableBool(const char *value, const char *name,
bool ParseVariableNum(const char *value, const char *name,
int *result);
+bool ParseVariableDouble(const char *value, const char *name,
+ double *result, double min, double max);
+
void PrintVariables(VariableSpace space);
bool SetVariable(VariableSpace space, const char *name, const char *value);