On Tue, Aug 26, 2014 at 4:55 AM, Heikki Linnakangas
<hlinnakan...@vmware.com> 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
>>> <hlinnakan...@vmware.com> 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 (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to