mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-11-27 07:21:09 +08:00
Add psql \set ON_ERROR_ROLLBACK to allow statements in a transaction to
error without affecting the entire transaction. Valid values are "on|interactive|off".
This commit is contained in:
parent
989b55c550
commit
a65b1b738c
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.134 2005/03/14 06:19:01 tgl Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.135 2005/04/28 13:09:59 momjian Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -2049,6 +2049,28 @@ bar
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<indexterm>
|
||||||
|
<primary>rollback</primary>
|
||||||
|
<secondary>psql</secondary>
|
||||||
|
</indexterm>
|
||||||
|
<term><varname>ON_ERROR_ROLLBACK</varname></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
When <literal>on</>, if a statement in a transaction block
|
||||||
|
generates an error, the error is ignored and the transaction
|
||||||
|
continues. When <literal>interactive</>, such errors are only
|
||||||
|
ignored in interactive sessions, and not when reading script
|
||||||
|
files. When <literal>off</> (the default), a statement in a
|
||||||
|
transaction block that generates an error aborts the entire
|
||||||
|
transaction. The on_error_rollback-on mode works by issuing an
|
||||||
|
implicit <command>SAVEPONT</> for you, just before each command
|
||||||
|
that is in a transaction block, and rolls back to the savepoint
|
||||||
|
on error.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>ON_ERROR_STOP</varname></term>
|
<term><varname>ON_ERROR_STOP</varname></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.96 2005/02/22 04:40:52 momjian Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.97 2005/04/28 13:09:59 momjian Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
@ -941,11 +941,13 @@ PrintQueryResults(PGresult *results)
|
|||||||
bool
|
bool
|
||||||
SendQuery(const char *query)
|
SendQuery(const char *query)
|
||||||
{
|
{
|
||||||
PGresult *results;
|
PGresult *results;
|
||||||
TimevalStruct before,
|
TimevalStruct before, after;
|
||||||
after;
|
bool OK, on_error_rollback_savepoint = false;
|
||||||
bool OK;
|
PGTransactionStatusType transaction_status;
|
||||||
|
static bool on_error_rollback_warning = false;
|
||||||
|
const char *rollback_str;
|
||||||
|
|
||||||
if (!pset.db)
|
if (!pset.db)
|
||||||
{
|
{
|
||||||
psql_error("You are currently not connected to a database.\n");
|
psql_error("You are currently not connected to a database.\n");
|
||||||
@ -973,7 +975,9 @@ SendQuery(const char *query)
|
|||||||
|
|
||||||
SetCancelConn();
|
SetCancelConn();
|
||||||
|
|
||||||
if (PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
|
transaction_status = PQtransactionStatus(pset.db);
|
||||||
|
|
||||||
|
if (transaction_status == PQTRANS_IDLE &&
|
||||||
!GetVariableBool(pset.vars, "AUTOCOMMIT") &&
|
!GetVariableBool(pset.vars, "AUTOCOMMIT") &&
|
||||||
!command_no_begin(query))
|
!command_no_begin(query))
|
||||||
{
|
{
|
||||||
@ -987,6 +991,33 @@ SendQuery(const char *query)
|
|||||||
}
|
}
|
||||||
PQclear(results);
|
PQclear(results);
|
||||||
}
|
}
|
||||||
|
else if (transaction_status == PQTRANS_INTRANS &&
|
||||||
|
(rollback_str = GetVariable(pset.vars, "ON_ERROR_ROLLBACK")) != NULL &&
|
||||||
|
/* !off and !interactive is 'on' */
|
||||||
|
pg_strcasecmp(rollback_str, "off") != 0 &&
|
||||||
|
(pset.cur_cmd_interactive ||
|
||||||
|
pg_strcasecmp(rollback_str, "interactive") != 0))
|
||||||
|
{
|
||||||
|
if (on_error_rollback_warning == false && pset.sversion < 80000)
|
||||||
|
{
|
||||||
|
fprintf(stderr, _("The server version (%d) does not support savepoints for ON_ERROR_ROLLBACK.\n"),
|
||||||
|
pset.sversion);
|
||||||
|
on_error_rollback_warning = true;
|
||||||
|
}
|
||||||
|
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)
|
if (pset.timing)
|
||||||
GETTIMEOFDAY(&before);
|
GETTIMEOFDAY(&before);
|
||||||
@ -1005,6 +1036,41 @@ SendQuery(const char *query)
|
|||||||
|
|
||||||
PQclear(results);
|
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:
|
||||||
|
* If the user did RELEASE or ROLLBACK, our savepoint is gone.
|
||||||
|
* If they issued a SAVEPOINT, releasing ours would remove theirs.
|
||||||
|
*/
|
||||||
|
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 */
|
/* Possible microtiming output */
|
||||||
if (OK && pset.timing)
|
if (OK && pset.timing)
|
||||||
printf(_("Time: %.3f ms\n"), DIFF_MSEC(&after, &before));
|
printf(_("Time: %.3f ms\n"), DIFF_MSEC(&after, &before));
|
||||||
|
Loading…
Reference in New Issue
Block a user