Index: doc/src/sgml/ref/psql-ref.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/ref/psql-ref.sgml,v
retrieving revision 1.134
diff -c -c -r1.134 psql-ref.sgml
*** doc/src/sgml/ref/psql-ref.sgml	14 Mar 2005 06:19:01 -0000	1.134
--- doc/src/sgml/ref/psql-ref.sgml	26 Apr 2005 00:35:48 -0000
***************
*** 2050,2055 ****
--- 2050,2075 ----
        
  
        
+       
+        rollback
+        psql
+       
+         ON_ERROR_ROLLBACK
+         
+         
+         When on>, only in interactive mode, if a statement in
+         a transaction block generates an error, the error is ignored and
+         the transaction continues. When off> (the default), a
+         statement in a transaction block that generates an error aborts
+         the entire transaction. The on_error_rollback-on mode works by
+         issuing an implicit SAVEPONT> for you, just before
+         each command that is in a transaction block, and rolls back to
+         the savepoint on error.
+         
+         
+       
+ 
+       
          ON_ERROR_STOP
          
          
Index: src/bin/psql/common.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/common.c,v
retrieving revision 1.96
diff -c -c -r1.96 common.c
*** src/bin/psql/common.c	22 Feb 2005 04:40:52 -0000	1.96
--- src/bin/psql/common.c	26 Apr 2005 00:35:50 -0000
***************
*** 941,951 ****
  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");
--- 941,952 ----
  bool
  SendQuery(const char *query)
  {
! 	PGresult 	*results;
! 	TimevalStruct before, after;
! 	bool OK, on_error_rollback_savepoint = false;
! 	PGTransactionStatusType transaction_status;
! 	static bool		on_error_rollback_warning = false;
! 	
  	if (!pset.db)
  	{
  		psql_error("You are currently not connected to a database.\n");
***************
*** 973,979 ****
  
  	SetCancelConn();
  
! 	if (PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
  		!GetVariableBool(pset.vars, "AUTOCOMMIT") &&
  		!command_no_begin(query))
  	{
--- 974,982 ----
  
  	SetCancelConn();
  
! 	transaction_status = PQtransactionStatus(pset.db);
! 
! 	if (transaction_status == PQTRANS_IDLE &&
  		!GetVariableBool(pset.vars, "AUTOCOMMIT") &&
  		!command_no_begin(query))
  	{
***************
*** 987,992 ****
--- 990,1019 ----
  		}
  		PQclear(results);
  	}
+ 	else if (transaction_status == PQTRANS_INTRANS &&
+ 			 pset.cur_cmd_interactive &&
+ 			 GetVariableBool(pset.vars, "ON_ERROR_ROLLBACK"))
+ 	{
+ 		if (on_error_rollback_warning == false && pset.sversion < 80000)
+ 		{
+ 			fprintf(stderr, _("The server version (%d) does not support savepoints for ON_ERROR_ROLLBACK.\n"),
+ 				pset.sversion);
+ 			on_error_rollback_warning = true;
+ 		}
+ 		else
+ 		{
+ 			results = PQexec(pset.db, "SAVEPOINT pg_psql_temporary_savepoint");
+ 			if (PQresultStatus(results) != PGRES_COMMAND_OK)
+ 			{
+ 				psql_error("%s", PQerrorMessage(pset.db));
+ 				PQclear(results);
+ 				ResetCancelConn();
+ 				return false;
+ 			}
+ 			PQclear(results);
+ 			on_error_rollback_savepoint = true;
+ 		}
+ 	}
  
  	if (pset.timing)
  		GETTIMEOFDAY(&before);
***************
*** 1005,1010 ****
--- 1032,1072 ----
  
  	PQclear(results);
  
+ 	/* If we made a temporary savepoint, possibly release/rollback */
+ 	if (on_error_rollback_savepoint)
+ 	{
+ 		transaction_status = PQtransactionStatus(pset.db);
+ 
+ 		/* We always rollback on an error */
+ 		if (transaction_status == PQTRANS_INERROR)
+ 			results = PQexec(pset.db, "ROLLBACK TO pg_psql_temporary_savepoint");
+ 		/* If they are no longer in a transaction, then do nothing */
+ 		else if (transaction_status != PQTRANS_INTRANS)
+ 			results = NULL;
+ 		else
+ 		{
+ 			/* 
+ 			 *	Do nothing if they are messing with savepoints themselves:
+ 			 *	If the user did RELEASE or ROLLBACK, our savepoint is gone.
+ 			 *	If they issued a SAVEPOINT, releasing ours would remove theirs.
+ 			 */
+ 			if (strcmp(PQcmdStatus(results), "SAVEPOINT") == 0 ||
+ 				strcmp(PQcmdStatus(results), "RELEASE") == 0 ||
+ 				strcmp(PQcmdStatus(results), "ROLLBACK") ==0)
+ 				results = NULL;
+ 			else
+ 				results = PQexec(pset.db, "RELEASE pg_psql_temporary_savepoint");
+ 		}
+ 		if (PQresultStatus(results) != PGRES_COMMAND_OK)
+ 		{
+ 			psql_error("%s", PQerrorMessage(pset.db));
+ 			PQclear(results);
+ 			ResetCancelConn();
+ 			return false;
+ 		}
+ 		PQclear(results);
+ 	}
+ 
  	/* Possible microtiming output */
  	if (OK && pset.timing)
  		printf(_("Time: %.3f ms\n"), DIFF_MSEC(&after, &before));