Greg Sabino Mullane wrote:
[ There is text before PGP section. ]
> 
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> 
> Finally had a chance to sit down at look at this afresh, and I'm
> pretty sure I've got all the kinks worked out this time. Apologies
> for not attaching, but my mail system is not working well enough
> at the moment. So, please try to break this patch:
> 
> http://www.gtsm.com/pg/psql_error_recovery.diff

I have modified Greg's patch to fit in better with the existing psql
code.  I changed the command to \set ON_ERROR_ROLLBACK, which seems to
fit better.  Here is an illustration of its use (patch attached):
        
        test=> BEGIN;
        BEGIN
        test=> lkjasdf;
        ERROR:  syntax error at or near "lkjasdf" at character 1
        LINE 1: lkjasdf;
                ^
        test=> SELECT 1;
        ERROR:  current transaction is aborted, commands ignored until end of
        transaction block
        test=> COMMIT;
        ROLLBACK
        test=> \set ON_ERROR_ROLLBACK on
        test=> BEGIN;
        BEGIN
        test=> lkjasdf;
        ERROR:  syntax error at or near "lkjasdf" at character 1
        LINE 1: lkjasdf;
                ^
        test=> SELECT 1;
         ?column?
        ----------
                1
        (1 row)
        
        test=> COMMIT;
        COMMIT

-- 
  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: 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 ----
        </varlistentry>
  
        <varlistentry>
+       <indexterm>
+        <primary>rollback</primary>
+        <secondary>psql</secondary>
+       </indexterm>
+         <term><varname>ON_ERROR_ROLLBACK</varname></term>
+         <listitem>
+         <para>
+         When in a transaction, wrap every command in a savepoint that is
+         rolled back on error. Thus, errors will not abort an open
+         transaction.
+         </para>
+         </listitem>
+       </varlistentry>
+ 
+       <varlistentry>
          <term><varname>ON_ERROR_STOP</varname></term>
          <listitem>
          <para>
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));
---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?

               http://archives.postgresql.org

Reply via email to