Index: startup.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/bin/psql/startup.c,v retrieving revision 1.100 diff -u -r1.100 startup.c --- startup.c 13 Sep 2004 23:07:12 -0000 1.100 +++ startup.c 21 Sep 2004 12:29:27 -0000 @@ -143,6 +143,7 @@ /* Default values for variables that are used in noninteractive cases */ SetVariableBool(pset.vars, "AUTOCOMMIT"); + SetVariable(pset.vars, "IMPLICIT_SAVEPOINTS", "off"); SetVariable(pset.vars, "VERBOSITY", "default"); pset.verbosity = PQERRORS_DEFAULT; Index: common.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/bin/psql/common.c,v retrieving revision 1.91 diff -u -r1.91 common.c --- common.c 20 Sep 2004 18:51:19 -0000 1.91 +++ common.c 21 Sep 2004 12:29:27 -0000 @@ -865,6 +865,7 @@ TimevalStruct before, after; bool OK; + bool implicit_savepoint = false; if (!pset.db) { @@ -908,6 +909,25 @@ PQclear(results); } + /* + * Implicit savepoints make it possible to only rollback the last statement + * on errors (interactive mode only, backend version >= 8.0). + * + * Note: We assume that the savepoint pg_internal_psql will not be used by a user. + */ + if (PQtransactionStatus(pset.db) == PQTRANS_INTRANS && + PQserverVersion(pset.db) >= 80000 && + GetVariableBool(pset.vars, "IMPLICIT_SAVEPOINTS") && + !pset.notty) + { + /* use PSQLexec instead of PQexec here, so -E prints this query */ + results = PSQLexec("SAVEPOINT pg_internal_psql", false); + if (!results) + return false; + PQclear(results); + implicit_savepoint = true; + } + if (pset.timing) GETTIMEOFDAY(&before); @@ -943,6 +963,26 @@ PrintNotifications(); + /* + * If we have created an implicit savepoints, the query failed, and the + * connection is in transaction aborted state, try to rollback to the + * savepoint set before executing the user query. + * + * Note: we must not release the savepoint if there is no error since that + * would have the side effect of releasing any savepoint created by the user + * in the executed query. + * + * Should we send a message to the user here? + */ + if (!OK + && implicit_savepoint + && PQtransactionStatus(pset.db) == PQTRANS_INERROR) + { + results = PSQLexec("ROLLBACK TO pg_internal_psql", false); + if (results) + PQclear(results); + } + return OK; }