Index: doc/src/sgml/ref/psql-ref.sgml =================================================================== RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/ref/psql-ref.sgml,v retrieving revision 1.122 diff -u -r1.122 psql-ref.sgml --- doc/src/sgml/ref/psql-ref.sgml 20 Sep 2004 18:51:17 -0000 1.122 +++ doc/src/sgml/ref/psql-ref.sgml 23 Sep 2004 19:51:36 -0000 @@ -2021,6 +2021,32 @@ + IMPLICIT_SAVEPOINTS + + + When on (default is off) a savepoint is created + before each interactive SQL command executed in psql. If + the command results in an error, psql will rollback to + the created savepoint. It thereby protects the user from a rollback of + the whole transaction. This option has no effect on none-interactive + mode, i.e. when commands are read from a file from stdin or + using \i. A SQL script cannot react to an error and the + behaviour would have unexpected results. + + + + + Savepoints have a rather high cost in the current implementation of + PostgreSQL (shared memory). Also keep in mind that + locks are held in transactions until commit. For those two reasons + you should not make transactions longer then neccessary in + interactive mode. + + + + + + LASTOID Index: src/bin/psql/command.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/bin/psql/command.c,v retrieving revision 1.125 diff -u -r1.125 command.c --- src/bin/psql/command.c 29 Aug 2004 05:06:54 -0000 1.125 +++ src/bin/psql/command.c 23 Sep 2004 19:51:36 -0000 @@ -1261,6 +1261,7 @@ FILE *fd; int result; char *oldfilename; + bool impl_savepoints_state; if (!filename) return false; @@ -1274,11 +1275,19 @@ return false; } + /* + * Disable implicit savepoints during processing commands from files. + */ + impl_savepoints_state = pset.impl_savepoints_disabled; + pset.impl_savepoints_disabled = true; + oldfilename = pset.inputfile; pset.inputfile = filename; result = MainLoop(fd); fclose(fd); pset.inputfile = oldfilename; + + pset.impl_savepoints_disabled = impl_savepoints_state; return result; } Index: src/bin/psql/common.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/bin/psql/common.c,v retrieving revision 1.91 diff -u -r1.91 common.c --- src/bin/psql/common.c 20 Sep 2004 18:51:19 -0000 1.91 +++ src/bin/psql/common.c 23 Sep 2004 19:51:36 -0000 @@ -61,7 +61,6 @@ extern bool prompt_state; - static bool command_no_begin(const char *query); @@ -865,6 +864,7 @@ TimevalStruct before, after; bool OK; + bool implicit_savepoint = false; if (!pset.db) { @@ -908,6 +908,26 @@ 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.impl_savepoints_disabled && + !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 savepoint, 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; } Index: src/bin/psql/startup.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/bin/psql/startup.c,v retrieving revision 1.100 diff -u -r1.100 startup.c --- src/bin/psql/startup.c 13 Sep 2004 23:07:12 -0000 1.100 +++ src/bin/psql/startup.c 23 Sep 2004 19:51:36 -0000 @@ -146,6 +146,10 @@ SetVariable(pset.vars, "VERBOSITY", "default"); pset.verbosity = PQERRORS_DEFAULT; + /* Default values for implicit savepoints */ + SetVariable(pset.vars, "IMPLICIT_SAVEPOINTS", "off"); + pset.impl_savepoints_disabled = false; + pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout))); /* This is obsolete and should be removed sometime. */