psql-watch-v4.patch
application/octet-stream
Filename: psql-watch-v4.patch
Type: application/octet-stream
Part: 0
Message:
Re: patch to add \watch to psql
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
Series: patch v4
| File | + | − |
|---|---|---|
| src/bin/psql/command.c | 124 | 0 |
| src/bin/psql/help.c | 1 | 0 |
| src/bin/psql/tab-complete.c | 1 | 0 |
*** c/src/bin/psql/command.c
--- w/src/bin/psql/command.c
***************
*** 1433,1438 **** exec_command(const char *cmd,
--- 1433,1562 ----
free(fname);
}
+ /* \watch -- execute a query every N seconds */
+ else if (strcmp(cmd, "watch") == 0)
+ {
+ char *value;
+
+ /* Volatile to prevent clobbering by by longjmp. */
+ volatile PGresult *res = NULL;
+ printQueryOpt myopt = pset.popt;
+ char quoted;
+ long sleep = 2;
+ int i;
+ char title[50];
+ time_t timer;
+
+ const int max_watch_delay = 86400; /* seconds in a day */
+
+ if (!query_buf || query_buf->len <= 0)
+ {
+ psql_error(_("Query buffer is empty, \\watch ignored."));
+
+ goto cleanup;
+ }
+
+ /*
+ * Implement optional specification of time period for re-running the
+ * query.
+ */
+ if ((value = psql_scan_slash_option(scan_state,
+ OT_NORMAL, "ed, false)))
+ {
+ sleep = strtol(value, NULL, 10);
+
+ if (sleep <= 0)
+ sleep = 1;
+ else if (sleep > max_watch_delay)
+ sleep = max_watch_delay;
+
+ free(value);
+ }
+
+ /*
+ * Set up rendering options, in particular, disable the pager, because
+ * nobody wants to be prompted while watching the output of 'watch'.
+ */
+ myopt.nullPrint = NULL;
+ myopt.topt.pager = 0;
+
+ /* Set up cancellation of 'watch' via SIGINT. */
+ if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
+ goto cleanup;
+
+ while (true)
+ {
+ timer = time(NULL);
+
+ if (isatty(fileno(stdin)))
+ printf("%c[0;0H%c[2J", 0x1b, 0x1b);
+
+ snprintf(title, sizeof(title), _("Watch every %lds\t%s"), sleep,
+ asctime(localtime(&timer)));
+ myopt.title = title;
+
+ if (query_buf)
+ res = PSQLexec(query_buf->data, false);
+ else if (!pset.quiet)
+ {
+ psql_error(_("Query buffer is empty."));
+ goto cleanup;
+ }
+
+ /*
+ * If SIGINT is sent while the query is processing, PSQLexec will
+ * consume the interrupt. The user's intention, though, is to
+ * cancel the entire watch process, so detect a sent cancellation
+ * request and exit in this case.
+ */
+ if (cancel_pressed)
+ goto cleanup;
+
+ res = PSQLexec(query_buf->data, false);
+
+ if (res)
+ {
+ ExecStatusType status = PQresultStatus((PGresult *) res);
+
+ switch (status)
+ {
+ case PGRES_TUPLES_OK:
+ printQuery((PGresult *) res, &myopt, pset.queryFout,
+ pset.logfile);
+ break;
+
+ case PGRES_EMPTY_QUERY:
+ psql_error(
+ _("\\watch cannot be used with an empty query\n"));
+ goto cleanup;
+
+ default:
+ break;
+ }
+
+ PQclear((PGresult *) res);
+ res = NULL;
+ }
+
+ /*
+ * Enable 'watch' cancellations and wait a while before running the
+ * query again.
+ */
+ sigint_interrupt_enabled = true;
+ for (i = 0; i < sleep; i++)
+ {
+ pg_usleep(1000000L);
+ if (cancel_pressed)
+ break;
+ }
+ sigint_interrupt_enabled = false;
+ }
+
+ cleanup:
+ if (res)
+ PQclear((PGresult *) res);
+ }
+
/* \x -- set or toggle expanded table representation */
else if (strcmp(cmd, "x") == 0)
{
*** c/src/bin/psql/help.c
--- w/src/bin/psql/help.c
***************
*** 195,200 **** slashUsage(unsigned short int pager)
--- 195,201 ----
fprintf(output, _(" \\ir FILE as \\i, but relative to location of current script\n"));
fprintf(output, _(" \\o [FILE] send all query results to file or |pipe\n"));
fprintf(output, _(" \\qecho [STRING] write string to query output stream (see \\o)\n"));
+ fprintf(output, _(" \\watch [SEC] execute query every SEC seconds\n"));
fprintf(output, "\n");
fprintf(output, _("Informational\n"));
*** c/src/bin/psql/tab-complete.c
--- w/src/bin/psql/tab-complete.c
***************
*** 900,906 **** psql_completion(char *text, int start, int end)
"\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
"\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
"\\set", "\\sf", "\\t", "\\T",
! "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
};
(void) end; /* not used */
--- 900,906 ----
"\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
"\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
"\\set", "\\sf", "\\t", "\\T",
! "\\timing", "\\unset", "\\x", "\\w", "\\watch", "\\z", "\\!", NULL
};
(void) end; /* not used */