From 02d250779d0f9fab118e435b7f206efa543fba42 Mon Sep 17 00:00:00 2001 From: "Andrey M. Borodin" Date: Thu, 16 Feb 2023 15:07:50 -0800 Subject: [PATCH v3 2/2] Add iteration count argument to psql \watch command If the argument is not provided - continue to \watch forever. Authour: Andrey Borodin Reviewed-by: Kyotaro Horiguchi Thread: https://postgr.es/m/CAAhFRxiZ2-n_L1ErMm9AZjgmUK%3DqS6VHb%2B0SaMn8sqqbhF7How%40mail.gmail.com --- doc/src/sgml/ref/psql-ref.sgml | 6 ++++- src/bin/psql/command.c | 37 +++++++++++++++++++++++++----- src/bin/psql/help.c | 2 +- src/test/regress/expected/psql.out | 2 +- src/test/regress/sql/psql.sql | 2 +- 5 files changed, 39 insertions(+), 10 deletions(-) diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index dc6528dc11..546697c78c 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -3548,7 +3548,7 @@ testdb=> \setenv LESS -imx4F - \watch [ seconds ] + \watch [ seconds [ iterations ] ] Repeatedly execute the current query buffer (as \g does) @@ -3561,6 +3561,10 @@ testdb=> \setenv LESS -imx4F If the current query buffer is empty, the most recently sent query is re-executed instead. + + If number of iterations is specified - query will be executed only + given number of times. + diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index e008c5217b..6d94fd1490 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -162,7 +162,7 @@ static bool do_connect(enum trivalue reuse_previous_specification, static bool do_edit(const char *filename_arg, PQExpBuffer query_buf, int lineno, bool discard_on_quit, bool *edited); static bool do_shell(const char *command); -static bool do_watch(PQExpBuffer query_buf, double sleep); +static bool do_watch(PQExpBuffer query_buf, double sleep, int iter); static bool lookup_object_oid(EditableObjectType obj_type, const char *desc, Oid *obj_oid); static bool get_create_object_cmd(EditableObjectType obj_type, Oid oid, @@ -2759,7 +2759,8 @@ exec_command_write(PsqlScanState scan_state, bool active_branch, } /* - * \watch -- execute a query every N seconds + * \watch -- execute a query every N seconds. + * Optionally for M iteration. */ static backslashResult exec_command_watch(PsqlScanState scan_state, bool active_branch, @@ -2772,6 +2773,7 @@ exec_command_watch(PsqlScanState scan_state, bool active_branch, char *opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true); double sleep = 2; + int iter = 0; /* Convert optional sleep-length argument */ if (opt) @@ -2780,18 +2782,35 @@ exec_command_watch(PsqlScanState scan_state, bool active_branch, sleep = strtod(opt, &opt_end); if (sleep <= 0 || *opt_end) { - pg_log_error("Watch period must be positive number, but argument is '%s'", opt); + pg_log_error("Watch period must be positive number, but " + "argument is '%s'", opt); free(opt); resetPQExpBuffer(query_buf); return PSQL_CMD_ERROR; } free(opt); + + /* Check if iteration count is given */ + opt = psql_scan_slash_option(scan_state, + OT_NORMAL, NULL, true); + if (opt) + { + iter = strtol(opt, &opt_end, 10); + if (iter <= 0 || *opt_end) + { + pg_log_error("Watch iteration count must be positive " + "integer, but argument is '%s'", opt); + resetPQExpBuffer(query_buf); + return PSQL_CMD_ERROR; + } + free(opt); + } } /* If query_buf is empty, recall and execute previous query */ (void) copy_previous_query(query_buf, previous_buf); - success = do_watch(query_buf, sleep); + success = do_watch(query_buf, sleep, iter); /* Reset the query buffer as though for \r */ resetPQExpBuffer(query_buf); @@ -5053,7 +5072,7 @@ do_shell(const char *command) * onto a bunch of exec_command's variables to silence stupider compilers. */ static bool -do_watch(PQExpBuffer query_buf, double sleep) +do_watch(PQExpBuffer query_buf, double sleep, int iter) { long sleep_ms = (long) (sleep * 1000); printQueryOpt myopt = pset.popt; @@ -5155,7 +5174,7 @@ do_watch(PQExpBuffer query_buf, double sleep) title_len = (user_title ? strlen(user_title) : 0) + 256; title = pg_malloc(title_len); - for (;;) + for (int i = 1;;) { time_t timer; char timebuf[128]; @@ -5189,6 +5208,12 @@ do_watch(PQExpBuffer query_buf, double sleep) if (pagerpipe && ferror(pagerpipe)) break; + /* If we have iteration count - check that it's not exceeded yet */ + if (iter && (i++ == iter)) + { + break; + } + #ifdef WIN32 /* diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index e45c4aaca5..9561f15a71 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -200,7 +200,7 @@ slashUsage(unsigned short int pager) HELP0(" \\gset [PREFIX] execute query and store result in psql variables\n"); HELP0(" \\gx [(OPTIONS)] [FILE] as \\g, but forces expanded output mode\n"); HELP0(" \\q quit psql\n"); - HELP0(" \\watch [SEC] execute query every SEC seconds\n"); + HELP0(" \\watch [SEC [N]] execute query every SEC seconds N times\n"); HELP0("\n"); HELP0("Help\n"); diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out index 8fc62cebd2..e5d7e4c4f5 100644 --- a/src/test/regress/expected/psql.out +++ b/src/test/regress/expected/psql.out @@ -4536,7 +4536,7 @@ invalid command \lo \timing arg1 \unset arg1 \w arg1 - \watch arg1 + \watch arg1 arg2 \x arg1 -- \else here is eaten as part of OT_FILEPIPE argument \w |/no/such/file \else diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql index 2da9665a19..661847a2f1 100644 --- a/src/test/regress/sql/psql.sql +++ b/src/test/regress/sql/psql.sql @@ -1022,7 +1022,7 @@ select \if false \\ (bogus \else \\ 42 \endif \\ forty_two; \timing arg1 \unset arg1 \w arg1 - \watch arg1 + \watch arg1 arg2 \x arg1 -- \else here is eaten as part of OT_FILEPIPE argument \w |/no/such/file \else -- 2.32.0 (Apple Git-132)