ne 19. 4. 2020 v 19:27 odesÃlatel Pavel Stehule <pavel.steh...@gmail.com> napsal:
> Hi, > > last week I finished pspg 3.0 https://github.com/okbob/pspg . pspg now > supports pipes, named pipes very well. Today the pspg can be used as pager > for output of \watch command. Sure, psql needs attached patch. > > I propose new psql environment variable PSQL_WATCH_PAGER. When this > variable is not empty, then \watch command starts specified pager, and > redirect output to related pipe. When pipe is closed - by pager, then > \watch cycle is leaved. > > If you want to test proposed feature, you need a pspg with > cb4114f98318344d162a84b895a3b7f8badec241 > commit. > > Then you can set your env > > export PSQL_WATCH_PAGER="pspg --stream" > psql > > SELECT * FROM pg_stat_database; > \watch 1 > > Comments, notes? > > Regards > > Pavel > rebase
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 303e7c3ad8..7ab5aed3fa 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -173,6 +173,7 @@ static char *pset_value_string(const char *param, printQueryOpt *popt); static void checkWin32Codepage(void); #endif +static bool sigpipe_received = false; /*---------- @@ -4749,6 +4750,17 @@ do_shell(const char *command) return true; } +/* + * We want to detect sigpipe to break from watch cycle faster, + * before waiting 1 sec in sleep time, and unsuccess write to + * pipe. + */ +static void +pagerpipe_sigpipe_handler(int signum) +{ + sigpipe_received = true; +} + /* * do_watch -- handler for \watch * @@ -4763,6 +4775,8 @@ do_watch(PQExpBuffer query_buf, double sleep) const char *strftime_fmt; const char *user_title; char *title; + const char *pagerprog = NULL; + FILE *pagerpipe = NULL; int title_len; int res = 0; @@ -4772,6 +4786,21 @@ do_watch(PQExpBuffer query_buf, double sleep) return false; } + pagerprog = getenv("PSQL_WATCH_PAGER"); + if (pagerprog) + { + sigpipe_received = false; + +#ifndef WIN32 + pqsignal(SIGPIPE, pagerpipe_sigpipe_handler); +#endif + + pagerpipe = popen(pagerprog, "w"); + if (!pagerpipe) + /*silently proceed without pager */ + restore_sigpipe_trap(); + } + /* * Choose format for timestamps. We might eventually make this a \pset * option. In the meantime, using a variable for the format suppresses @@ -4783,7 +4812,8 @@ do_watch(PQExpBuffer query_buf, double sleep) * Set up rendering options, in particular, disable the pager, because * nobody wants to be prompted while watching the output of 'watch'. */ - myopt.topt.pager = 0; + if (!pagerpipe) + myopt.topt.pager = 0; /* * If there's a title in the user configuration, make sure we have room @@ -4817,7 +4847,7 @@ do_watch(PQExpBuffer query_buf, double sleep) myopt.title = title; /* Run the query and print out the results */ - res = PSQLexecWatch(query_buf->data, &myopt); + res = PSQLexecWatch(query_buf->data, &myopt, pagerpipe); /* * PSQLexecWatch handles the case where we can no longer repeat the @@ -4826,6 +4856,9 @@ do_watch(PQExpBuffer query_buf, double sleep) if (res <= 0) break; + if (pagerpipe && ferror(pagerpipe)) + break; + /* * Set up cancellation of 'watch' via SIGINT. We redo this each time * through the loop since it's conceivable something inside @@ -4843,14 +4876,27 @@ do_watch(PQExpBuffer query_buf, double sleep) i = sleep_ms; while (i > 0) { - long s = Min(i, 1000L); + long s = Min(i, pagerpipe ? 100L : 1000L); pg_usleep(s * 1000L); if (cancel_pressed) break; + + if (sigpipe_received) + break; + i -= s; } sigint_interrupt_enabled = false; + + if (sigpipe_received) + break; + } + + if (pagerpipe) + { + fclose(pagerpipe); + restore_sigpipe_trap(); } pg_free(title); diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index 6f507104f4..08bb046462 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -592,12 +592,13 @@ PSQLexec(const char *query) * e.g., because of the interrupt, -1 on error. */ int -PSQLexecWatch(const char *query, const printQueryOpt *opt) +PSQLexecWatch(const char *query, const printQueryOpt *opt, FILE *printQueryFout) { PGresult *res; double elapsed_msec = 0; instr_time before; instr_time after; + FILE *fout; if (!pset.db) { @@ -638,14 +639,16 @@ PSQLexecWatch(const char *query, const printQueryOpt *opt) return 0; } + fout = printQueryFout ? printQueryFout : pset.queryFout; + switch (PQresultStatus(res)) { case PGRES_TUPLES_OK: - printQuery(res, opt, pset.queryFout, false, pset.logfile); + printQuery(res, opt, fout, false, pset.logfile); break; case PGRES_COMMAND_OK: - fprintf(pset.queryFout, "%s\n%s\n\n", opt->title, PQcmdStatus(res)); + fprintf(fout, "%s\n%s\n\n", opt->title, PQcmdStatus(res)); break; case PGRES_EMPTY_QUERY: @@ -668,7 +671,7 @@ PSQLexecWatch(const char *query, const printQueryOpt *opt) PQclear(res); - fflush(pset.queryFout); + fflush(fout); /* Possible microtiming output */ if (pset.timing) diff --git a/src/bin/psql/common.h b/src/bin/psql/common.h index 041b2ac068..d8538a4e06 100644 --- a/src/bin/psql/common.h +++ b/src/bin/psql/common.h @@ -29,7 +29,7 @@ extern sigjmp_buf sigint_interrupt_jmp; extern void psql_setup_cancel_handler(void); extern PGresult *PSQLexec(const char *query); -extern int PSQLexecWatch(const char *query, const printQueryOpt *opt); +extern int PSQLexecWatch(const char *query, const printQueryOpt *opt, FILE *printQueryFout); extern bool SendQuery(const char *query); diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index 9ec1c4e810..094b838843 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -347,7 +347,7 @@ helpVariables(unsigned short int pager) * Windows builds currently print one more line than non-Windows builds. * Using the larger number is fine. */ - output = PageOutput(158, pager ? &(pset.popt.topt) : NULL); + output = PageOutput(160, pager ? &(pset.popt.topt) : NULL); fprintf(output, _("List of specially treated variables\n\n")); @@ -503,6 +503,8 @@ helpVariables(unsigned short int pager) " alternative location for the command history file\n")); fprintf(output, _(" PSQL_PAGER, PAGER\n" " name of external pager program\n")); + fprintf(output, _(" PSQL_WATCH_PAGER\n" + " name of external pager program used for watch mode\n")); fprintf(output, _(" PSQLRC\n" " alternative location for the user's .psqlrc file\n")); fprintf(output, _(" SHELL\n"