diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 880d3d0b32..66dd6801a0 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -3544,13 +3544,15 @@ testdb=> \setenv LESS -imx4F - \watch [ i[nterval]=seconds ] [ c[ount]=times ] [ seconds ] + \watch [ i[nterval]=seconds ] [ c[ount]=times ] [ zero ] [ seconds ] Repeatedly execute the current query buffer (as \g does) until interrupted, or the query fails, or the execution count limit - (if given) is reached. Wait the specified number of - seconds (default 2) between executions. For backwards compatibility, + (if given) is reached. If the zero + argument is used, execution stops when the query returns zero rows. + Wait the specified number of seconds (default 2) between executions. + For backwards compatibility, seconds can be specified with or without an interval= prefix. Each query result is diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 511debbe81..679365a26e 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, int iter); +static bool do_watch(PQExpBuffer query_buf, double sleep, int iter, bool zero_if_empty); 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, @@ -2773,13 +2773,14 @@ exec_command_watch(PsqlScanState scan_state, bool active_branch, { bool have_sleep = false; bool have_iter = false; + bool zero_if_empty = false; double sleep = 2; int iter = 0; /* - * Parse arguments. We allow either an unlabeled interval or - * "name=value", where name is from the set ('i', 'interval', 'c', - * 'count'). + * Parse arguments. We allow either an unlabeled interval, the + * keyword "zero", or "name=value", where name is from the set ('i', + * 'interval', 'c', 'count'). */ while (success) { @@ -2842,6 +2843,10 @@ exec_command_watch(PsqlScanState scan_state, bool active_branch, success = false; } } + else if (strncmp("zero", opt, strlen("zero")) == 0) + { + zero_if_empty = true; + } else { /* Unlabeled argument: take it as interval */ @@ -2872,7 +2877,7 @@ exec_command_watch(PsqlScanState scan_state, bool active_branch, /* If query_buf is empty, recall and execute previous query */ (void) copy_previous_query(query_buf, previous_buf); - success = do_watch(query_buf, sleep, iter); + success = do_watch(query_buf, sleep, iter, zero_if_empty); } /* Reset the query buffer as though for \r */ @@ -5142,7 +5147,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, int iter) +do_watch(PQExpBuffer query_buf, double sleep, int iter, bool zero_if_empty) { long sleep_ms = (long) (sleep * 1000); printQueryOpt myopt = pset.popt; @@ -5272,7 +5277,7 @@ do_watch(PQExpBuffer query_buf, double sleep, int iter) myopt.title = title; /* Run the query and print out the result */ - res = PSQLexecWatch(query_buf->data, &myopt, pagerpipe); + res = PSQLexecWatch(query_buf->data, &myopt, pagerpipe, zero_if_empty); /* * PSQLexecWatch handles the case where we can no longer repeat the diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index 5973df2e39..4530dbcfc7 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -36,6 +36,7 @@ static int ExecQueryAndProcessResults(const char *query, double *elapsed_msec, bool *svpt_gone_p, bool is_watch, + bool zero_if_empty, const printQueryOpt *opt, FILE *printQueryFout); static bool command_no_begin(const char *query); @@ -632,7 +633,7 @@ PSQLexec(const char *query) * e.g., because of the interrupt, -1 on error. */ int -PSQLexecWatch(const char *query, const printQueryOpt *opt, FILE *printQueryFout) +PSQLexecWatch(const char *query, const printQueryOpt *opt, FILE *printQueryFout, bool zero_if_empty) { bool timing = pset.timing; double elapsed_msec = 0; @@ -646,7 +647,7 @@ PSQLexecWatch(const char *query, const printQueryOpt *opt, FILE *printQueryFout) SetCancelConn(pset.db); - res = ExecQueryAndProcessResults(query, &elapsed_msec, NULL, true, opt, printQueryFout); + res = ExecQueryAndProcessResults(query, &elapsed_msec, NULL, true, zero_if_empty, opt, printQueryFout); ResetCancelConn(); @@ -1134,7 +1135,7 @@ SendQuery(const char *query) pset.crosstab_flag || !is_select_command(query)) { /* Default fetch-it-all-and-print mode */ - OK = (ExecQueryAndProcessResults(query, &elapsed_msec, &svpt_gone, false, NULL, NULL) > 0); + OK = (ExecQueryAndProcessResults(query, &elapsed_msec, &svpt_gone, false, false, NULL, NULL) > 0); } else { @@ -1415,11 +1416,12 @@ DescribeQuery(const char *query, double *elapsed_msec) static int ExecQueryAndProcessResults(const char *query, double *elapsed_msec, bool *svpt_gone_p, - bool is_watch, + bool is_watch, bool zero_if_empty, const printQueryOpt *opt, FILE *printQueryFout) { bool timing = pset.timing; bool success; + bool return_empty = false; instr_time before, after; PGresult *result; @@ -1461,6 +1463,10 @@ ExecQueryAndProcessResults(const char *query, /* first result */ result = PQgetResult(pset.db); + if (zero_if_empty && PQntuples(result) < 1) + { + return_empty = true; + } while (result != NULL) { @@ -1683,7 +1689,7 @@ ExecQueryAndProcessResults(const char *query, if (!CheckConnection()) return -1; - return cancel_pressed ? 0 : success ? 1 : -1; + return (cancel_pressed || return_empty) ? 0 : success ? 1 : -1; } diff --git a/src/bin/psql/common.h b/src/bin/psql/common.h index 812b94a977..36ccb39ac0 100644 --- a/src/bin/psql/common.h +++ b/src/bin/psql/common.h @@ -32,7 +32,7 @@ extern void psql_setup_cancel_handler(void); extern void SetShellResultVariables(int wait_result); extern PGresult *PSQLexec(const char *query); -extern int PSQLexecWatch(const char *query, const printQueryOpt *opt, FILE *printQueryFout); +extern int PSQLexecWatch(const char *query, const printQueryOpt *opt, FILE *printQueryFout, bool zero_if_empty); extern bool SendQuery(const char *query);