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 25 Apr 2005 16:26:03 -0000
***************
*** 2050,2055 ****
--- 2050,2070 ----
+
+ rollback
+ psql
+
+ ON_ERROR_ROLLBACK
+
+
+ When in a transaction, wrap every command in a savepoint that is
+ rolled back on error. Thus, errors will not abort an open
+ transaction.
+
+
+
+
+
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 25 Apr 2005 16:26:05 -0000
***************
*** 941,950 ****
bool
SendQuery(const char *query)
{
! PGresult *results;
! TimevalStruct before,
! after;
! bool OK;
if (!pset.db)
{
--- 941,950 ----
bool
SendQuery(const char *query)
{
! PGresult *results;
! TimevalStruct before, after;
! bool OK, on_error_rollback_savepoint = false;
! PGTransactionStatusType transaction_status;
if (!pset.db)
{
***************
*** 973,979 ****
SetCancelConn();
! if (PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
!GetVariableBool(pset.vars, "AUTOCOMMIT") &&
!command_no_begin(query))
{
--- 973,981 ----
SetCancelConn();
! transaction_status = PQtransactionStatus(pset.db);
!
! if (transaction_status == PQTRANS_IDLE &&
!GetVariableBool(pset.vars, "AUTOCOMMIT") &&
!command_no_begin(query))
{
***************
*** 987,992 ****
--- 989,1016 ----
}
PQclear(results);
}
+ else if (transaction_status == PQTRANS_INTRANS &&
+ GetVariableBool(pset.vars, "ON_ERROR_ROLLBACK"))
+ {
+ if (pset.sversion < 80000)
+ {
+ fprintf(stderr, _("The server version (%d) does not support savepoints for ON_ERROR_ROLLBACK.\n"),
+ pset.sversion);
+ }
+ 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 ****
--- 1029,1069 ----
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:
+ * doing otherwise would cause us to remove their savepoint,
+ * or have us rollback our savepoint they have just removed
+ */
+ 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));