3
3
*
4
4
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
5
5
*
6
- * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.96 2005/02/22 04:40:52 momjian Exp $
6
+ * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.97 2005/04/28 13:09:59 momjian Exp $
7
7
*/
8
8
#include "postgres_fe.h"
9
9
#include "common.h"
@@ -941,11 +941,13 @@ PrintQueryResults(PGresult *results)
941
941
bool
942
942
SendQuery (const char * query )
943
943
{
944
- PGresult * results ;
945
- TimevalStruct before ,
946
- after ;
947
- bool OK ;
948
-
944
+ PGresult * results ;
945
+ TimevalStruct before , after ;
946
+ bool OK , on_error_rollback_savepoint = false;
947
+ PGTransactionStatusType transaction_status ;
948
+ static bool on_error_rollback_warning = false;
949
+ const char * rollback_str ;
950
+
949
951
if (!pset .db )
950
952
{
951
953
psql_error ("You are currently not connected to a database.\n" );
@@ -973,7 +975,9 @@ SendQuery(const char *query)
973
975
974
976
SetCancelConn ();
975
977
976
- if (PQtransactionStatus (pset .db ) == PQTRANS_IDLE &&
978
+ transaction_status = PQtransactionStatus (pset .db );
979
+
980
+ if (transaction_status == PQTRANS_IDLE &&
977
981
!GetVariableBool (pset .vars , "AUTOCOMMIT" ) &&
978
982
!command_no_begin (query ))
979
983
{
@@ -987,6 +991,33 @@ SendQuery(const char *query)
987
991
}
988
992
PQclear (results );
989
993
}
994
+ else if (transaction_status == PQTRANS_INTRANS &&
995
+ (rollback_str = GetVariable (pset .vars , "ON_ERROR_ROLLBACK" )) != NULL &&
996
+ /* !off and !interactive is 'on' */
997
+ pg_strcasecmp (rollback_str , "off" ) != 0 &&
998
+ (pset .cur_cmd_interactive ||
999
+ pg_strcasecmp (rollback_str , "interactive" ) != 0 ))
1000
+ {
1001
+ if (on_error_rollback_warning == false && pset .sversion < 80000 )
1002
+ {
1003
+ fprintf (stderr , _ ("The server version (%d) does not support savepoints for ON_ERROR_ROLLBACK.\n" ),
1004
+ pset .sversion );
1005
+ on_error_rollback_warning = true;
1006
+ }
1007
+ else
1008
+ {
1009
+ results = PQexec (pset .db , "SAVEPOINT pg_psql_temporary_savepoint" );
1010
+ if (PQresultStatus (results ) != PGRES_COMMAND_OK )
1011
+ {
1012
+ psql_error ("%s" , PQerrorMessage (pset .db ));
1013
+ PQclear (results );
1014
+ ResetCancelConn ();
1015
+ return false;
1016
+ }
1017
+ PQclear (results );
1018
+ on_error_rollback_savepoint = true;
1019
+ }
1020
+ }
990
1021
991
1022
if (pset .timing )
992
1023
GETTIMEOFDAY (& before );
@@ -1005,6 +1036,41 @@ SendQuery(const char *query)
1005
1036
1006
1037
PQclear (results );
1007
1038
1039
+ /* If we made a temporary savepoint, possibly release/rollback */
1040
+ if (on_error_rollback_savepoint )
1041
+ {
1042
+ transaction_status = PQtransactionStatus (pset .db );
1043
+
1044
+ /* We always rollback on an error */
1045
+ if (transaction_status == PQTRANS_INERROR )
1046
+ results = PQexec (pset .db , "ROLLBACK TO pg_psql_temporary_savepoint" );
1047
+ /* If they are no longer in a transaction, then do nothing */
1048
+ else if (transaction_status != PQTRANS_INTRANS )
1049
+ results = NULL ;
1050
+ else
1051
+ {
1052
+ /*
1053
+ * Do nothing if they are messing with savepoints themselves:
1054
+ * If the user did RELEASE or ROLLBACK, our savepoint is gone.
1055
+ * If they issued a SAVEPOINT, releasing ours would remove theirs.
1056
+ */
1057
+ if (strcmp (PQcmdStatus (results ), "SAVEPOINT" ) == 0 ||
1058
+ strcmp (PQcmdStatus (results ), "RELEASE" ) == 0 ||
1059
+ strcmp (PQcmdStatus (results ), "ROLLBACK" ) == 0 )
1060
+ results = NULL ;
1061
+ else
1062
+ results = PQexec (pset .db , "RELEASE pg_psql_temporary_savepoint" );
1063
+ }
1064
+ if (PQresultStatus (results ) != PGRES_COMMAND_OK )
1065
+ {
1066
+ psql_error ("%s" , PQerrorMessage (pset .db ));
1067
+ PQclear (results );
1068
+ ResetCancelConn ();
1069
+ return false;
1070
+ }
1071
+ PQclear (results );
1072
+ }
1073
+
1008
1074
/* Possible microtiming output */
1009
1075
if (OK && pset .timing )
1010
1076
printf (_ ("Time: %.3f ms\n" ), DIFF_MSEC (& after , & before ));
0 commit comments