Tom pointed out a problem with our current error handling with
autocommit off:

	SET autocommit TO off;
	lkjasdfasdf;
	SELECT 1;
	COMMIT;

In our current code, SELECT is considred to be in a new transaction. 
This patch fixes that by making the SELECT be part of the aborted
transaction.  Basically we didn't have proper autocommit handling in the
abort function.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Index: src/backend/access/transam/xact.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/access/transam/xact.c,v
retrieving revision 1.143
diff -c -c -r1.143 xact.c
*** src/backend/access/transam/xact.c	14 Mar 2003 22:40:31 -0000	1.143
--- src/backend/access/transam/xact.c	19 Mar 2003 20:13:09 -0000
***************
*** 1341,1347 ****
  			 */
  		case TBLOCK_DEFAULT:
  			AbortTransaction();
! 			CleanupTransaction();
  			break;
  
  			/*
--- 1341,1350 ----
  			 */
  		case TBLOCK_DEFAULT:
  			AbortTransaction();
! 			if (autocommit)
! 				CleanupTransaction();
! 			else
! 				s->blockState = TBLOCK_ABORT;
  			break;
  
  			/*
Wed, 19 Mar 2003 15:24:39 -0500 (EST)
Bruce Momjian <pgman@candle.pha.pa.us>
Fix for error in autocommit off
Bruce Momjian <pgman@candle.pha.pa.us> writes:
>   			 */
>   		case TBLOCK_DEFAULT:
>   			AbortTransaction();
> ! 			if (autocommit)
> ! 				CleanupTransaction();
> ! 			else
> ! 				s->blockState = TBLOCK_ABORT;
>   			break;
  
You forgot suppressChain...

			regards, tom lane

Thu, 20 Mar 2003 00:52:07 -0500
Tom Lane <tgl@sss.pgh.pa.us>
Re: Fix for error in autocommit off 
I wasn't sure how to handle it.  Is the attached patch correct?

---------------------------------------------------------------------------

Tom Lane wrote:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> >   			 */
> >   		case TBLOCK_DEFAULT:
> >   			AbortTransaction();
> > ! 			if (autocommit)
> > ! 				CleanupTransaction();
> > ! 			else
> > ! 				s->blockState = TBLOCK_ABORT;
> >   			break;
>   
> You forgot suppressChain...
> 
> 			regards, tom lane
> 
> ---------------------------(end of broadcast)---------------------------
> TIP 6: Have you searched our list archives?
> 
> http://archives.postgresql.org
> 

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Index: src/bin/psql/common.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/bin/psql/common.c,v
retrieving revision 1.58
diff -c -c -r1.58 common.c
*** src/bin/psql/common.c	20 Mar 2003 04:49:18 -0000	1.58
--- src/bin/psql/common.c	20 Mar 2003 05:57:19 -0000
***************
*** 34,39 ****
--- 34,58 ----
  #include "print.h"
  #include "mainloop.h"
  
+ 
+ /* Workarounds for Windows */
+ /* Probably to be moved up the source tree in the future, perhaps to be replaced by
+  * more specific checks like configure-style HAVE_GETTIMEOFDAY macros.
+  */
+ #ifndef WIN32
+ 
+ typedef struct timeval TimevalStruct;
+ #define GETTIMEOFDAY(T) gettimeofday(T, NULL)
+ #define DIFF_MSEC(T, U) ((((T)->tv_sec - (U)->tv_sec) * 1000000.0 + (T)->tv_usec - (U)->tv_usec) / 1000.0)
+ 
+ #else
+ 
+ typedef struct _timeb TimevalStruct;
+ #define GETTIMEOFDAY(T) _ftime(&T)
+ #define DIFF_MSEC(T, U) ((((T)->time - (U)->time) * 1000.0 + (T)->millitm - (U)->millitm))
+ 
+ #endif
+ 
  extern bool prompt_state;
  
  /*
***************
*** 110,119 ****
  
  	/* Direct signals */
  #ifndef WIN32
! 	if (pset.queryFoutPipe)
! 		pqsignal(SIGPIPE, SIG_IGN);
! 	else
! 		pqsignal(SIGPIPE, SIG_DFL);
  #endif
  
  	return status;
--- 129,135 ----
  
  	/* Direct signals */
  #ifndef WIN32
! 	pqsignal(SIGPIPE, pset.queryFoutPipe ? SIG_IGN : SIG_DFL);
  #endif
  
  	return status;
***************
*** 165,172 ****
   * so. We use write() to print to stdout because it's better to use simple
   * facilities in a signal handler.
   */
! PGconn	   *cancelConn;
! volatile bool cancel_pressed;
  
  #ifndef WIN32
  
--- 181,190 ----
   * so. We use write() to print to stdout because it's better to use simple
   * facilities in a signal handler.
   */
! static PGconn	   *volatile cancelConn = NULL;
! 
! volatile bool cancel_pressed = false;
! 
  
  #ifndef WIN32
  
***************
*** 198,203 ****
--- 216,357 ----
  #endif   /* not WIN32 */
  
  
+ 
+ /* ConnectionUp
+  *
+  * Returns whether our backend connection is still there.
+  */
+ static bool 
+ ConnectionUp()
+ {
+ 	return PQstatus(pset.db) != CONNECTION_BAD;
+ }
+ 
+ 
+ 
+ /* CheckConnection
+  *
+  * Verify that we still have a good connection to the backend, and if not,
+  * see if it can be restored.
+  *
+  * Returns true if either the connection was still there, or it could be
+  * restored successfully; false otherwise.  If, however, there was no
+  * connection and the session is non-interactive, this will exit the program
+  * with a code of EXIT_BADCONN.
+  */
+ static bool
+ CheckConnection()
+ {
+ 	bool OK;
+ 	
+ 	OK = ConnectionUp();
+ 	if (!OK)
+ 	{
+ 		if (!pset.cur_cmd_interactive)
+ 		{
+ 			psql_error("connection to server was lost\n");
+ 			exit(EXIT_BADCONN);
+ 		}
+ 
+ 		fputs(gettext("The connection to the server was lost. Attempting reset: "), stderr);
+ 		PQreset(pset.db);
+ 		OK = ConnectionUp();
+ 		if (!OK)
+ 		{
+ 			fputs(gettext("Failed.\n"), stderr);
+ 			PQfinish(pset.db);
+ 			pset.db = NULL;
+ 			ResetCancelConn();
+ 			SetVariable(pset.vars, "DBNAME", NULL);
+ 			SetVariable(pset.vars, "HOST", NULL);
+ 			SetVariable(pset.vars, "PORT", NULL);
+ 			SetVariable(pset.vars, "USER", NULL);
+ 			SetVariable(pset.vars, "ENCODING", NULL);
+ 		}
+ 		else
+ 			fputs(gettext("Succeeded.\n"), stderr);
+ 	}
+ 
+ 	return OK;
+ }
+ 
+ 
+ 
+ /*
+  * SetCancelConn
+  *
+  * Set cancelConn to point to the current database connection.
+  */
+ static void SetCancelConn(void)
+ {
+   cancelConn = pset.db;
+ }
+ 
+ 
+ /*
+  * ResetCancelConn
+  *
+  * Set cancelConn to NULL.  I don't know what this means exactly, but it saves
+  * having to export the variable.
+  */
+ void ResetCancelConn(void)
+ {
+   cancelConn = NULL;
+ }
+ 
+ 
+ /*
+  * AcceptResult
+  *
+  * Checks whether a result is valid, giving an error message if necessary;
+  * (re)sets copy_in_state and cancelConn as needed, and ensures that the
+  * connection to the backend is still up.
+  *
+  * Returns true for valid result, false for error state.
+  */
+ static bool
+ AcceptResult(const PGresult *result)
+ {
+ 	bool OK = true;
+ 
+ 	ResetCancelConn();
+ 
+ 	if (!result)
+ 	{
+ 	  OK = false;
+ 	}
+ 	else switch (PQresultStatus(result))
+ 	{
+ 	  case PGRES_COPY_IN:
+ 		 copy_in_state = true;
+ 		 break;
+ 
+ 	  case PGRES_COMMAND_OK:
+ 	  case PGRES_TUPLES_OK:
+ 		 /* Fine, do nothing */
+ 		 break;
+ 
+ 	  case PGRES_COPY_OUT:
+ 		 /* keep cancel connection for copy out state */
+ 		 SetCancelConn();
+ 		 break;
+ 
+ 	  default:
+ 		 OK = false;
+ 		 break;
+ 	}
+ 
+ 	if (!OK) 
+ 	{
+ 		CheckConnection();
+ 		psql_error("%s", PQerrorMessage(pset.db));
+ 	}
+ 
+ 	return OK;
+ }
+ 
+ 
+ 
  /*
   * PSQLexec
   *
***************
*** 239,394 ****
  	while ((newres = PQgetResult(pset.db)) != NULL)
  		PQclear(newres);
  
! 	cancelConn = pset.db;
! 	if (PQsendQuery(pset.db, query))
  	{
! 		while ((newres = PQgetResult(pset.db)) != NULL)
  		{
  			rstatus = PQresultStatus(newres);
! 			if (ignore_command_ok && rstatus == PGRES_COMMAND_OK)
  			{
! 				PQclear(newres);
! 				continue;
! 			}
! 			PQclear(res);
  			res = newres;
! 			if (rstatus != PGRES_COPY_IN &&
! 				rstatus != PGRES_COPY_OUT)
! 				break;
  		}
  	}
! 	rstatus = PQresultStatus(res);
! 	/* keep cancel connection for copy out state */
! 	if (rstatus != PGRES_COPY_OUT)
! 		cancelConn = NULL;
! 	if (rstatus == PGRES_COPY_IN)
! 		copy_in_state = true;
! 
! 	if (res && (rstatus == PGRES_COMMAND_OK ||
! 				rstatus == PGRES_TUPLES_OK ||
! 				rstatus == PGRES_COPY_IN ||
! 				rstatus == PGRES_COPY_OUT))
! 		return res;
! 	else
  	{
- 		psql_error("%s", PQerrorMessage(pset.db));
  		PQclear(res);
! 
! 		if (PQstatus(pset.db) == CONNECTION_BAD)
! 		{
! 			if (!pset.cur_cmd_interactive)
! 			{
! 				psql_error("connection to server was lost\n");
! 				exit(EXIT_BADCONN);
! 			}
! 			fputs(gettext("The connection to the server was lost. Attempting reset: "), stderr);
! 			PQreset(pset.db);
! 			if (PQstatus(pset.db) == CONNECTION_BAD)
! 			{
! 				fputs(gettext("Failed.\n"), stderr);
! 				PQfinish(pset.db);
! 				pset.db = NULL;
! 				SetVariable(pset.vars, "DBNAME", NULL);
! 				SetVariable(pset.vars, "HOST", NULL);
! 				SetVariable(pset.vars, "PORT", NULL);
! 				SetVariable(pset.vars, "USER", NULL);
! 				SetVariable(pset.vars, "ENCODING", NULL);
! 			}
! 			else
! 				fputs(gettext("Succeeded.\n"), stderr);
  		}
  
! 		return NULL;
! 	}
  }
  
  
  
  /*
!  * SendQuery: send the query string to the backend
!  * (and print out results)
!  *
!  * Note: This is the "front door" way to send a query. That is, use it to
!  * send queries actually entered by the user. These queries will be subject to
!  * single step mode.
!  * To send "back door" queries (generated by slash commands, etc.) in a
!  * controlled way, use PSQLexec().
   *
-  * Returns true if the query executed successfully, false otherwise.
   */
! bool
! SendQuery(const char *query)
  {
- 	bool		success = false;
- 	PGresult   *results;
  	PGnotify   *notify;
- #ifndef WIN32
- 	struct timeval before,
- 				after;
- #else
- 	struct _timeb before,
- 				after;
- #endif
  
! 	if (!pset.db)
! 	{
! 		psql_error("You are currently not connected to a database.\n");
! 		return false;
! 	}
! 
! 	if (GetVariableBool(pset.vars, "SINGLESTEP"))
  	{
! 		char		buf[3];
! 
! 		printf(gettext("***(Single step mode: Verify query)*********************************************\n"
! 					   "%s\n"
! 					   "***(press return to proceed or enter x and return to cancel)********************\n"),
! 			   query);
! 		fflush(stdout);
! 		if (fgets(buf, sizeof(buf), stdin) != NULL)
! 			if (buf[0] == 'x')
! 				return false;
! 	}
! 	else
! 	{
! 		const char *var = GetVariable(pset.vars, "ECHO");
! 
! 		if (var && strncmp(var, "queries", strlen(var)) == 0)
! 			puts(query);
  	}
  
- 	cancelConn = pset.db;
- 
- #ifndef WIN32
- 	if (pset.timing)
- 		gettimeofday(&before, NULL);
- 	results = PQexec(pset.db, query);
- 	if (pset.timing)
- 		gettimeofday(&after, NULL);
- #else
- 	if (pset.timing)
- 		_ftime(&before);
- 	results = PQexec(pset.db, query);
- 	if (pset.timing)
- 		_ftime(&after);
- #endif
- 
- 	if (PQresultStatus(results) == PGRES_COPY_IN)
- 		copy_in_state = true;
- 	/* keep cancel connection for copy out state */
- 	if (PQresultStatus(results) != PGRES_COPY_OUT)
- 		cancelConn = NULL;
  
! 	if (results == NULL)
! 	{
! 		fputs(PQerrorMessage(pset.db), pset.queryFout);
! 		success = false;
! 	}
! 	else
! 	{
! 		switch (PQresultStatus(results))
! 		{
! 			case PGRES_TUPLES_OK:
  				/* write output to \g argument, if any */
  				if (pset.gfname)
  				{
--- 393,460 ----
  	while ((newres = PQgetResult(pset.db)) != NULL)
  		PQclear(newres);
  
! 	SetCancelConn();
! 	if (!PQsendQuery(pset.db, query))
  	{
! 	  psql_error("%s", PQerrorMessage(pset.db));
! 	  ResetCancelConn();
! 	  return NULL;
! 	}
! 
! 	rstatus = PGRES_EMPTY_QUERY;
! 
! 	while (rstatus != PGRES_COPY_IN &&
! 			 rstatus != PGRES_COPY_OUT &&
! 			 (newres = PQgetResult(pset.db)))
  		{
  			rstatus = PQresultStatus(newres);
! 		if (!ignore_command_ok || rstatus != PGRES_COMMAND_OK)
  			{
! 		  PGresult *tempRes = res;
  			res = newres;
! 		  newres = tempRes;
  		}
+ 		PQclear(newres);
  	}
! 
! 	if (!AcceptResult(res) && res)
  	{
  		PQclear(res);
! 		res = NULL;
  		}
  
! 	return res;
  }
  
  
  
  /*
!  * PrintNotifications: check for asynchronous notifications, and print them out
   *
   */
! static void
! PrintNotifications(void)
  {
  	PGnotify   *notify;
  
! 	while ((notify = PQnotifies(pset.db)))
  	{
! 		fprintf(pset.queryFout, gettext("Asynchronous NOTIFY '%s' from backend with pid %d received.\n"),
! 				notify->relname, notify->be_pid);
! 		free(notify);
! 		fflush(pset.queryFout);
  	}
+ }
  
  
! /*
!  * PrintQueryTuples: assuming query result is OK, print its tuples
!  *
!  * Returns true if successful, false otherwise.
!  */
! static bool 
! PrintQueryTuples(const PGresult *results)
! {
  				/* write output to \g argument, if any */
  				if (pset.gfname)
  				{
***************
*** 403,410 ****
  					{
  						pset.queryFout = queryFout_copy;
  						pset.queryFoutPipe = queryFoutPipe_copy;
! 						success = false;
! 						break;
  					}
  
  					printQuery(results, &pset.popt, pset.queryFout);
--- 469,475 ----
  					{
  						pset.queryFout = queryFout_copy;
  						pset.queryFoutPipe = queryFoutPipe_copy;
! 			return false;
  					}
  
  					printQuery(results, &pset.popt, pset.queryFout);
***************
*** 417,430 ****
  
  					free(pset.gfname);
  					pset.gfname = NULL;
- 
- 					success = true;
  				}
  				else
  				{
  					printQuery(results, &pset.popt, pset.queryFout);
- 					success = true;
  				}
  				break;
  			case PGRES_EMPTY_QUERY:
  				success = true;
--- 482,519 ----
  
  					free(pset.gfname);
  					pset.gfname = NULL;
  				}
  				else
  				{
  					printQuery(results, &pset.popt, pset.queryFout);
  				}
+ 
+ 	return true;
+ }
+ 
+ 
+ 
+ /*
+  * PrintQueryResults: analyze query results and print them out
+  *
+  * Note: Utility function for use by SendQuery() only.
+  *
+  * Returns true if the query executed successfully, false otherwise.
+  */
+ static bool
+ PrintQueryResults(PGresult *results, 
+ 		const TimevalStruct *before, 
+ 		const TimevalStruct *after)
+ {
+ 	bool	success = false;
+ 
+ 	if (!results) 
+ 	  return false;
+ 
+ 	switch (PQresultStatus(results))
+ 	{
+ 		case PGRES_TUPLES_OK:
+ 			success = PrintQueryTuples(results);
  				break;
  			case PGRES_EMPTY_QUERY:
  				success = true;
***************
*** 453,516 ****
  									   pset.cur_cmd_interactive ? get_prompt(PROMPT_COPY) : NULL);
  				break;
  
! 			case PGRES_NONFATAL_ERROR:
! 			case PGRES_FATAL_ERROR:
! 			case PGRES_BAD_RESPONSE:
! 				success = false;
! 				psql_error("%s", PQerrorMessage(pset.db));
  				break;
  		}
  
  		fflush(pset.queryFout);
  
! 		if (PQstatus(pset.db) == CONNECTION_BAD)
! 		{
! 			if (!pset.cur_cmd_interactive)
  			{
! 				psql_error("connection to server was lost\n");
! 				exit(EXIT_BADCONN);
  			}
! 			fputs(gettext("The connection to the server was lost. Attempting reset: "), stderr);
! 			PQreset(pset.db);
! 			if (PQstatus(pset.db) == CONNECTION_BAD)
  			{
! 				fputs(gettext("Failed.\n"), stderr);
! 				PQfinish(pset.db);
! 				PQclear(results);
! 				pset.db = NULL;
! 				SetVariable(pset.vars, "DBNAME", NULL);
! 				SetVariable(pset.vars, "HOST", NULL);
! 				SetVariable(pset.vars, "PORT", NULL);
! 				SetVariable(pset.vars, "USER", NULL);
! 				SetVariable(pset.vars, "ENCODING", NULL);
  				return false;
  			}
  			else
- 				fputs(gettext("Succeeded.\n"), stderr);
- 		}
- 
- 		/* check for asynchronous notification returns */
- 		while ((notify = PQnotifies(pset.db)) != NULL)
  		{
! 			fprintf(pset.queryFout, gettext("Asynchronous NOTIFY '%s' from backend with pid %d received.\n"),
! 					notify->relname, notify->be_pid);
! 			free(notify);
! 			fflush(pset.queryFout);
! 		}
  
! 		if (results)
! 			PQclear(results);
  	}
  
! 	/* Possible microtiming output */
! 	if (pset.timing && success)
! #ifndef WIN32
! 		printf(gettext("Time: %.2f ms\n"),
! 			   ((after.tv_sec - before.tv_sec) * 1000000.0 + after.tv_usec - before.tv_usec) / 1000.0);
! #else
! 		printf(gettext("Time: %.2f ms\n"),
! 			   ((after.time - before.time) * 1000.0 + after.millitm - before.millitm));
! #endif
  
! 	return success;
  }
--- 542,621 ----
  									   pset.cur_cmd_interactive ? get_prompt(PROMPT_COPY) : NULL);
  				break;
  
! 		default:
  				break;
  		}
  
  		fflush(pset.queryFout);
  
! 	if (!CheckConnection()) return false;
! 
! 	/* Possible microtiming output */
! 	if (pset.timing && success)
! 		printf(gettext("Time: %.2f ms\n"), DIFF_MSEC(after, before));
! 
! 	return success;
! }
! 
! 
! 
! /*
!  * SendQuery: send the query string to the backend
!  * (and print out results)
!  *
!  * Note: This is the "front door" way to send a query. That is, use it to
!  * send queries actually entered by the user. These queries will be subject to
!  * single step mode.
!  * To send "back door" queries (generated by slash commands, etc.) in a
!  * controlled way, use PSQLexec().
!  *
!  * Returns true if the query executed successfully, false otherwise.
!  */
! bool
! SendQuery(const char *query)
! {
! 	PGresult   *results;
! 	TimevalStruct before, after;
! 	bool OK;
! 
! 	if (!pset.db)
  			{
! 		psql_error("You are currently not connected to a database.\n");
! 		return false;
  			}
! 
! 	if (GetVariableBool(pset.vars, "SINGLESTEP"))
  			{
! 		char		buf[3];
! 
! 		printf(gettext("***(Single step mode: Verify query)*********************************************\n"
! 					   "%s\n"
! 					   "***(press return to proceed or enter x and return to cancel)********************\n"),
! 			   query);
! 		fflush(stdout);
! 		if (fgets(buf, sizeof(buf), stdin) != NULL)
! 			if (buf[0] == 'x')
  				return false;
  			}
  			else
  		{
! 		const char *var = GetVariable(pset.vars, "ECHO");
  
! 		if (var && strncmp(var, "queries", strlen(var)) == 0)
! 			puts(query);
  	}
  
! 	SetCancelConn();
  
! 	if (pset.timing)
! 		GETTIMEOFDAY(&before);
! 	results = PQexec(pset.db, query);
! 	if (pset.timing)
! 		GETTIMEOFDAY(&after);
! 
! 	OK = (AcceptResult(results) && PrintQueryResults(results, &before, &after));
! 	PQclear(results);
! 
! 	PrintNotifications();
! 	return OK;
  }
Index: src/bin/psql/common.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/bin/psql/common.h,v
retrieving revision 1.22
diff -c -c -r1.22 common.h
*** src/bin/psql/common.h	18 Mar 2003 22:15:44 -0000	1.22
--- src/bin/psql/common.h	20 Mar 2003 05:57:19 -0000
***************
*** 29,34 ****
--- 29,36 ----
  extern volatile bool cancel_pressed;
  extern PGconn *cancelConn;
  
+ extern void ResetCancelConn(void);
+ 
  #ifndef WIN32
  extern void handle_sigint(SIGNAL_ARGS);
  #endif   /* not WIN32 */
Index: src/bin/psql/copy.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/bin/psql/copy.c,v
retrieving revision 1.28
diff -c -c -r1.28 copy.c
*** src/bin/psql/copy.c	19 Oct 2002 00:22:14 -0000	1.28
--- src/bin/psql/copy.c	20 Mar 2003 05:57:19 -0000
***************
*** 446,453 ****
  	char		copybuf[COPYBUFSIZ];
  	int			ret;
  
- 	assert(cancelConn);
- 
  	while (!copydone)
  	{
  		ret = PQgetline(conn, copybuf, COPYBUFSIZ);
--- 446,451 ----
***************
*** 476,482 ****
  	}
  	fflush(copystream);
  	ret = !PQendcopy(conn);
! 	cancelConn = NULL;
  	return ret;
  }
  
--- 474,480 ----
  	}
  	fflush(copystream);
  	ret = !PQendcopy(conn);
! 	ResetCancelConn();
  	return ret;
  }
  
Index: src/bin/psql/input.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/bin/psql/input.c,v
retrieving revision 1.21
diff -c -c -r1.21 input.c
*** src/bin/psql/input.c	6 Sep 2002 02:33:46 -0000	1.21
--- src/bin/psql/input.c	20 Mar 2003 05:57:19 -0000
***************
*** 20,25 ****
--- 20,34 ----
  #ifdef USE_READLINE
  static bool useReadline;
  static bool useHistory;
+ 
+ enum histcontrol
+ {
+   hctl_none = 0,
+   hctl_ignorespace = 1,
+   hctl_ignoredups = 2,
+   hctl_ignoreboth = hctl_ignorespace | hctl_ignoredups
+ };
+ 
  #endif
  
  #ifdef HAVE_ATEXIT
***************
*** 33,38 ****
--- 42,76 ----
  #define PSQLHISTORY	".psql_history"
  
  
+ #ifdef USE_READLINE
+ static enum histcontrol
+ GetHistControlConfig(void)
+ {
+ 	enum histcontrol HC;
+ 	const char *var;
+ 
+ 	var = GetVariable(pset.vars, "HISTCONTROL");
+ 
+ 	if (!var) 												HC = hctl_none;
+ 	else if 	(strcmp(var, "ignorespace") == 0)	HC = hctl_ignorespace;
+ 	else if 	(strcmp(var, "ignoredups") == 0)		HC = hctl_ignoredups;
+ 	else if	(strcmp(var, "ignoreboth") == 0)		HC = hctl_ignoreboth;
+ 	else														HC = hctl_none;
+ 
+ 	return HC;
+ }
+ #endif
+ 
+ 
+ static char *
+ gets_basic(const char prompt[])
+ {
+ 	fputs(prompt, stdout);
+ 	fflush(stdout);
+ 	return gets_fromFile(stdin);
+ }
+ 
+ 
  /*
   * gets_interactive()
   *
***************
*** 40,84 ****
   * The result is malloced.
   */
  char *
! gets_interactive(char *prompt)
  {
  	char	   *s;
  
- #ifdef USE_READLINE
- 	const char *var;
  	static char *prev_hist = NULL;
- #endif
  
- #ifdef USE_READLINE
  	if (useReadline)
  		s = readline(prompt);
  	else
  	{
! #endif
! 		fputs(prompt, stdout);
! 		fflush(stdout);
! 		s = gets_fromFile(stdin);
! #ifdef USE_READLINE
! 	}
! #endif
  
! #ifdef USE_READLINE
! 	if (useHistory && s && s[0] != '\0')
  	{
! 		var = GetVariable(pset.vars, "HISTCONTROL");
! 		if (!var || (var
! 					 && !((strcmp(var, "ignorespace") == 0 || strcmp(var, "ignoreboth") == 0) && s[0] == ' ')
! 					 && !((strcmp(var, "ignoredups") == 0 || strcmp(var, "ignoreboth") == 0) && prev_hist && strcmp(s, prev_hist) == 0)
! 					 ))
  		{
  			free(prev_hist);
  			prev_hist = strdup(s);
  			add_history(s);
  		}
  	}
- #endif
  
  	return s;
  }
  
  
--- 78,118 ----
   * The result is malloced.
   */
  char *
! gets_interactive(const char *prompt)
  {
+ #ifdef USE_READLINE
  	char	   *s;
  
  	static char *prev_hist = NULL;
  
  	if (useReadline)
  		s = readline(prompt);
  	else
+ 		s = gets_basic(prompt);
+ 
+ 	if (useHistory && s && s[0])
  	{
! 		enum histcontrol HC;
  
! 		HC = GetHistControlConfig();
! 
! 		if (((HC & hctl_ignorespace) && s[0] == ' ') ||
! 		    ((HC & hctl_ignoredups) && prev_hist && strcmp(s, prev_hist) == 0))
  	{
! 		  /* Ignore this line as far as history is concerned */
! 		}
! 		else
  		{
  			free(prev_hist);
  			prev_hist = strdup(s);
  			add_history(s);
  		}
  	}
  
  	return s;
+ #else
+ 	return gets_basic(prompt);
+ #endif
  }
  
  
***************
*** 126,142 ****
  initializeInput(int flags)
  {
  #ifdef USE_READLINE
! 	if (flags == 1)
  	{
  		useReadline = true;
  		initialize_readline();
- 	}
- #endif
- 
- #ifdef USE_READLINE
- 	if (flags == 1)
- 	{
- 		const char *home;
  
  		useHistory = true;
  		SetVariable(pset.vars, "HISTSIZE", "500");
--- 160,171 ----
  initializeInput(int flags)
  {
  #ifdef USE_READLINE
! 	if (flags & 1)
  	{
+ 		const char *home;
+ 
  		useReadline = true;
  		initialize_readline();
  
  		useHistory = true;
  		SetVariable(pset.vars, "HISTSIZE", "500");
***************
*** 172,189 ****
  #ifdef USE_READLINE
  	if (useHistory && fname)
  	{
! 		if (write_history(fname) != 0)
! 		{
! 			psql_error("could not save history to %s: %s\n", fname, strerror(errno));
! 			return false;
! 		}
  		return true;
  	}
- 	else
- 		return false;
- #else
- 	return false;
  #endif
  }
  
  
--- 201,214 ----
  #ifdef USE_READLINE
  	if (useHistory && fname)
  	{
! 		if (write_history(fname) == 0)
  		return true;
+ 
+ 		psql_error("could not save history to %s: %s\n", fname, strerror(errno));
  	}
  #endif
+ 
+ 	return false;
  }
  
  
Index: src/bin/psql/input.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/bin/psql/input.h,v
retrieving revision 1.18
diff -c -c -r1.18 input.h
*** src/bin/psql/input.h	19 Feb 2003 04:04:04 -0000	1.18
--- src/bin/psql/input.h	20 Mar 2003 05:57:19 -0000
***************
*** 32,38 ****
  #endif
  #endif
  
! char	   *gets_interactive(char *prompt);
  char	   *gets_fromFile(FILE *source);
  
  void		initializeInput(int flags);
--- 32,39 ----
  #endif
  #endif
  
! 
! char	   *gets_interactive(const char *prompt);
  char	   *gets_fromFile(FILE *source);
  
  void		initializeInput(int flags);
Index: src/bin/psql/mainloop.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/bin/psql/mainloop.c,v
retrieving revision 1.51
diff -c -c -r1.51 mainloop.c
*** src/bin/psql/mainloop.c	12 Oct 2002 23:09:34 -0000	1.51
--- src/bin/psql/mainloop.c	20 Mar 2003 05:57:20 -0000
***************
*** 92,99 ****
  	/* main loop to get queries and execute them */
  	while (1)
  	{
- #ifndef WIN32
- 
  		/*
  		 * Welcome code for Control-C
  		 */
--- 92,97 ----
***************
*** 113,118 ****
--- 111,117 ----
  			cancel_pressed = false;
  		}
  
+ #ifndef WIN32
  		if (sigsetjmp(main_loop_jmp, 1) != 0)
  		{
  			/* got here with longjmp */
Thu, 20 Mar 2003 01:01:33 -0500 (EST)
Bruce Momjian <pgman@candle.pha.pa.us>
Re: Fix for error in autocommit off
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> I wasn't sure how to handle it.  Is the attached patch correct?

Do I have to wade through a thousand lines of Windows hacks to find out?
suppressChain should force autocommit-on behavior, it's not hard...

			regards, tom lane

Thu, 20 Mar 2003 01:07:04 -0500
Tom Lane <tgl@sss.pgh.pa.us>
Re: Fix for error in autocommit off 

I have suppressChain behaving just like it does in
CommitTransactionCommand().  That should do it.

---------------------------------------------------------------------------

Tom Lane wrote:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > I wasn't sure how to handle it.  Is the attached patch correct?
> 
> Do I have to wade through a thousand lines of Windows hacks to find out?
> suppressChain should force autocommit-on behavior, it's not hard...
> 
> 			regards, tom lane
> 

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Thu, 20 Mar 2003 01:10:31 -0500 (EST)
Bruce Momjian <pgman@candle.pha.pa.us>
Re: Fix for error in autocommit off