On Tue, Aug 26, 2014 at 4:55 AM, Heikki Linnakangas
<[email protected]> wrote:
> On 08/25/2014 10:48 PM, Heikki Linnakangas wrote:
>>
>> On 08/25/2014 09:22 PM, Fujii Masao wrote:
>>>
>>> On Tue, Aug 26, 2014 at 1:34 AM, Heikki Linnakangas
>>> <[email protected]> wrote:
>>>>
>>>> I agree that refactoring this would be nice in the long-term, and I also
>>>> agree that it's probably OK as it is in the short-term. I don't like the
>>>> name PSQLexecInternal, though. PSQLexec is used for "internal" commands
>>>> anyway. In fact it's backwards, because PSQLexecInternal is used for
>>>> non-internal queries, given by \watch, while PSQLexec is used for
>>>> internal
>>>> commands.
>>>
>>>
>>> Agreed. So what about PSQLexecCommon (inspired by
>>> the relation between LWLockAcquireCommon and LWLockAcquire)?
>>> Or any better name?
>>
>>
>> Actually, perhaps it would be better to just copy-paste PSQLexec, and
>> modify the copy to suite \watch's needs. (PSQLexecWatch?
>> SendWatchQuery?). PSQLexec doesn't do much, and there isn't very much
>> overlap between what \watch wants and what other PSQLexec callers want.
>> \watch wants timing output, others don't. \watch doesn't want
>> transaction handling.
Agreed. Attached is the revised version of the patch. I implemented
PSQLexecWatch() which sends the query, prints the results and outputs
the query execution time (if \timing is enabled).
This patch was marked as ready for committer, but since I revised
the code very much, I marked this as needs review again.
>> Do we want --echo-hidden to print the \watch'd
>> query? Not sure..
Per document, --echo-hidden prints the actual queries generated by
backslash command. But \watch doesn't handle backslash commands.
So I think that PSQLexecWatch doesn't need to handle --echo-hidden.
> BTW, I just noticed that none of the callers of PSQLexec pass
> "start_xact=true". So that part of the function is dead code. We might want
> to remove it, and replace with a comment noting that PSQLexec never starts a
> new transaction block, even in autocommit-off mode. (I know you're hacking
> on this, so I didnn't want to joggle your elbow by doing it right now)
Good catch. So I will remove start_xact code later.
Regards,
--
Fujii Masao
*** a/src/bin/psql/command.c
--- b/src/bin/psql/command.c
***************
*** 2687,2693 **** do_watch(PQExpBuffer query_buf, long sleep)
for (;;)
{
! PGresult *res;
time_t timer;
long i;
--- 2687,2693 ----
for (;;)
{
! int res;
time_t timer;
long i;
***************
*** 2701,2759 **** do_watch(PQExpBuffer query_buf, long sleep)
myopt.title = title;
/*
! * Run the query. We use PSQLexec, which is kind of cheating, but
! * SendQuery doesn't let us suppress autocommit behavior.
*/
! res = PSQLexec(query_buf->data, false);
!
! /* PSQLexec handles failure results and returns NULL */
! if (res == NULL)
! break;
/*
! * 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)
! {
! PQclear(res);
break;
! }
!
! switch (PQresultStatus(res))
! {
! case PGRES_TUPLES_OK:
! printQuery(res, &myopt, pset.queryFout, pset.logfile);
! break;
!
! case PGRES_COMMAND_OK:
! fprintf(pset.queryFout, "%s\n%s\n\n", title, PQcmdStatus(res));
! break;
!
! case PGRES_EMPTY_QUERY:
! psql_error(_("\\watch cannot be used with an empty query\n"));
! PQclear(res);
! return false;
!
! case PGRES_COPY_OUT:
! case PGRES_COPY_IN:
! case PGRES_COPY_BOTH:
! psql_error(_("\\watch cannot be used with COPY\n"));
! PQclear(res);
! return false;
!
! default:
! /* other cases should have been handled by PSQLexec */
! psql_error(_("unexpected result status for \\watch\n"));
! PQclear(res);
! return false;
! }
!
! PQclear(res);
!
! fflush(pset.queryFout);
/*
* Set up cancellation of 'watch' via SIGINT. We redo this each time
--- 2701,2720 ----
myopt.title = title;
/*
! * Run the query and print out the results. We use PSQLexecWatch,
! * which is kind of cheating, but SendQuery doesn't let us suppress
! * autocommit behavior.
*/
! res = PSQLexecWatch(query_buf->data, &myopt);
/*
! * PSQLexecWatch handles the case where we can no longer
! * repeat the query, and returns 0 or -1.
*/
! if (res == 0)
break;
! if (res == -1)
! return false;
/*
* Set up cancellation of 'watch' via SIGINT. We redo this each time
*** a/src/bin/psql/common.c
--- b/src/bin/psql/common.c
***************
*** 497,502 **** PSQLexec(const char *query, bool start_xact)
--- 497,598 ----
}
+ /*
+ * PSQLexecWatch
+ *
+ * This function is used for \watch command to send the query to
+ * the server and print out the results.
+ *
+ * Returns 1 if the query executed successfully, 0 if it cannot be repeated,
+ * e.g., because of the interrupt, -1 on error.
+ */
+ int
+ PSQLexecWatch(const char *query, const printQueryOpt *opt)
+ {
+ PGresult *res;
+ double elapsed_msec = 0;
+ instr_time before;
+ instr_time after;
+
+ if (!pset.db)
+ {
+ psql_error("You are currently not connected to a database.\n");
+ return 0;
+ }
+
+ SetCancelConn();
+
+ if (pset.timing)
+ INSTR_TIME_SET_CURRENT(before);
+
+ res = PQexec(pset.db, query);
+
+ ResetCancelConn();
+
+ if (!AcceptResult(res))
+ {
+ PQclear(res);
+ return 0;
+ }
+
+ if (pset.timing)
+ {
+ INSTR_TIME_SET_CURRENT(after);
+ INSTR_TIME_SUBTRACT(after, before);
+ elapsed_msec = INSTR_TIME_GET_MILLISEC(after);
+ }
+
+ /*
+ * If SIGINT is sent while the query is processing, the interrupt
+ * will be consumed. 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)
+ {
+ PQclear(res);
+ return 0;
+ }
+
+ switch (PQresultStatus(res))
+ {
+ case PGRES_TUPLES_OK:
+ printQuery(res, opt, pset.queryFout, pset.logfile);
+ break;
+
+ case PGRES_COMMAND_OK:
+ fprintf(pset.queryFout, "%s\n%s\n\n", opt->title, PQcmdStatus(res));
+ break;
+
+ case PGRES_EMPTY_QUERY:
+ psql_error(_("\\watch cannot be used with an empty query\n"));
+ PQclear(res);
+ return -1;
+
+ case PGRES_COPY_OUT:
+ case PGRES_COPY_IN:
+ case PGRES_COPY_BOTH:
+ psql_error(_("\\watch cannot be used with COPY\n"));
+ PQclear(res);
+ return -1;
+
+ default:
+ psql_error(_("unexpected result status for \\watch\n"));
+ PQclear(res);
+ return -1;
+ }
+
+ PQclear(res);
+
+ fflush(pset.queryFout);
+
+ /* Possible microtiming output */
+ if (pset.timing)
+ printf(_("Time: %.3f ms\n"), elapsed_msec);
+
+ return 1;
+ }
+
/*
* PrintNotifications: check for asynchronous notifications, and print them out
*** a/src/bin/psql/common.h
--- b/src/bin/psql/common.h
***************
*** 12,17 ****
--- 12,19 ----
#include <setjmp.h>
#include "libpq-fe.h"
+ #include "print.h"
+
#define atooid(x) ((Oid) strtoul((x), NULL, 10))
extern bool setQFout(const char *fname);
***************
*** 37,42 **** extern void SetCancelConn(void);
--- 39,45 ----
extern void ResetCancelConn(void);
extern PGresult *PSQLexec(const char *query, bool start_xact);
+ extern int PSQLexecWatch(const char *query, const printQueryOpt *opt);
extern bool SendQuery(const char *query);
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers