diff options
author | Daniel Gustafsson <dgustafsson@postgresql.org> | 2025-03-25 17:53:33 +0100 |
---|---|---|
committer | Daniel Gustafsson <dgustafsson@postgresql.org> | 2025-03-25 17:53:33 +0100 |
commit | 1a759c83278fcdae11ee5da8318b646b9d47129c (patch) | |
tree | 6b61dad74bd7337ac9c950bb5343ee18c3915caa /src | |
parent | a19db082749662a933d0bf72722982b1ee2c4725 (diff) | |
download | postgresql-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.c | 6 | ||||
-rw-r--r-- | src/bin/psql/help.c | 2 | ||||
-rw-r--r-- | src/bin/psql/settings.h | 7 | ||||
-rw-r--r-- | src/bin/psql/startup.c | 18 | ||||
-rw-r--r-- | src/bin/psql/t/001_basic.pl | 24 | ||||
-rw-r--r-- | src/bin/psql/variables.c | 70 | ||||
-rw-r--r-- | src/bin/psql/variables.h | 3 |
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); |