Make transactions roll back by default
This commit is contained in:
parent
1c9d482c1d
commit
cc75249620
@ -83,7 +83,6 @@ use std::from_str::FromStr;
|
||||
use std::io::{BufferedStream, IoResult};
|
||||
use std::io::net::ip::Port;
|
||||
use std::mem;
|
||||
use std::task;
|
||||
use std::fmt;
|
||||
|
||||
use error::{InvalidUrl,
|
||||
@ -784,8 +783,10 @@ impl PostgresConnection {
|
||||
/// Returns a `PostgresTransaction` object which should be used instead of
|
||||
/// the connection for the duration of the transaction. The transaction
|
||||
/// is active until the `PostgresTransaction` object falls out of scope.
|
||||
/// A transaction will commit by default unless the task fails or the
|
||||
/// transaction is set to roll back.
|
||||
///
|
||||
/// # Note
|
||||
/// A transaction will roll back by default. Use the `set_commit` method to
|
||||
/// set the transaction to commit.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@ -795,13 +796,10 @@ impl PostgresConnection {
|
||||
/// # let conn = PostgresConnection::connect("", &NoSsl).unwrap();
|
||||
/// let trans = try!(conn.transaction());
|
||||
/// try!(trans.execute("UPDATE foo SET bar = 10", []));
|
||||
/// // ...
|
||||
///
|
||||
/// # let something_bad_happened = true;
|
||||
/// if something_bad_happened {
|
||||
/// trans.set_rollback();
|
||||
/// }
|
||||
///
|
||||
/// drop(trans);
|
||||
/// trans.set_commit();
|
||||
/// try!(trans.finish());
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
@ -815,7 +813,7 @@ impl PostgresConnection {
|
||||
self.conn.borrow_mut().trans_depth += 1;
|
||||
Ok(PostgresTransaction {
|
||||
conn: self,
|
||||
commit: Cell::new(true),
|
||||
commit: Cell::new(false),
|
||||
depth: 1,
|
||||
finished: false,
|
||||
})
|
||||
@ -937,7 +935,7 @@ pub enum SslMode {
|
||||
|
||||
/// Represents a transaction on a database connection.
|
||||
///
|
||||
/// The transaction will commit by default.
|
||||
/// The transaction will roll back by default.
|
||||
pub struct PostgresTransaction<'conn> {
|
||||
conn: &'conn PostgresConnection,
|
||||
commit: Cell<bool>,
|
||||
@ -957,12 +955,11 @@ impl<'conn> Drop for PostgresTransaction<'conn> {
|
||||
impl<'conn> PostgresTransaction<'conn> {
|
||||
fn finish_inner(&mut self) -> PostgresResult<()> {
|
||||
debug_assert!(self.depth == self.conn.conn.borrow().trans_depth);
|
||||
let rollback = task::failing() || !self.commit.get();
|
||||
let query = match (rollback, self.depth != 1) {
|
||||
(true, true) => "ROLLBACK TO sp",
|
||||
(true, false) => "ROLLBACK",
|
||||
(false, true) => "RELEASE sp",
|
||||
(false, false) => "COMMIT",
|
||||
let query = match (self.commit.get(), self.depth != 1) {
|
||||
(false, true) => "ROLLBACK TO sp",
|
||||
(false, false) => "ROLLBACK",
|
||||
(true, true) => "RELEASE sp",
|
||||
(true, false) => "COMMIT",
|
||||
};
|
||||
self.conn.conn.borrow_mut().trans_depth -= 1;
|
||||
self.conn.quick_query(query).map(|_| ())
|
||||
@ -1002,7 +999,7 @@ impl<'conn> PostgresTransaction<'conn> {
|
||||
self.conn.conn.borrow_mut().trans_depth += 1;
|
||||
Ok(PostgresTransaction {
|
||||
conn: self.conn,
|
||||
commit: Cell::new(true),
|
||||
commit: Cell::new(false),
|
||||
depth: self.depth + 1,
|
||||
finished: false,
|
||||
})
|
||||
@ -1023,6 +1020,12 @@ impl<'conn> PostgresTransaction<'conn> {
|
||||
self.commit.set(false);
|
||||
}
|
||||
|
||||
/// A convenience method which consumes and commits a transaction.
|
||||
pub fn commit(self) -> PostgresResult<()> {
|
||||
self.set_commit();
|
||||
self.finish()
|
||||
}
|
||||
|
||||
/// Consumes the transaction, commiting or rolling it back as appropriate.
|
||||
///
|
||||
/// Functionally equivalent to the `Drop` implementation of
|
||||
|
@ -118,6 +118,7 @@ fn test_transaction_commit() {
|
||||
|
||||
let trans = or_fail!(conn.transaction());
|
||||
or_fail!(trans.execute("INSERT INTO foo (id) VALUES ($1)", [&1i32]));
|
||||
trans.set_commit();
|
||||
drop(trans);
|
||||
|
||||
let stmt = or_fail!(conn.prepare("SELECT * FROM foo"));
|
||||
@ -133,6 +134,7 @@ fn test_transaction_commit_finish() {
|
||||
|
||||
let trans = or_fail!(conn.transaction());
|
||||
or_fail!(trans.execute("INSERT INTO foo (id) VALUES ($1)", [&1i32]));
|
||||
trans.set_commit();
|
||||
assert!(trans.finish().is_ok());
|
||||
|
||||
let stmt = or_fail!(conn.prepare("SELECT * FROM foo"));
|
||||
@ -141,6 +143,21 @@ fn test_transaction_commit_finish() {
|
||||
assert_eq!(vec![1i32], result.map(|row| row.get(0u)).collect());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transaction_commit_method() {
|
||||
let conn = or_fail!(PostgresConnection::connect("postgres://postgres@localhost", &NoSsl));
|
||||
or_fail!(conn.execute("CREATE TEMPORARY TABLE foo (id INT PRIMARY KEY)", []));
|
||||
|
||||
let trans = or_fail!(conn.transaction());
|
||||
or_fail!(trans.execute("INSERT INTO foo (id) VALUES ($1)", [&1i32]));
|
||||
assert!(trans.commit().is_ok());
|
||||
|
||||
let stmt = or_fail!(conn.prepare("SELECT * FROM foo"));
|
||||
let result = or_fail!(stmt.query([]));
|
||||
|
||||
assert_eq!(vec![1i32], result.map(|row| row.get(0u)).collect());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transaction_rollback() {
|
||||
let conn = or_fail!(PostgresConnection::connect("postgres://postgres@localhost", &NoSsl));
|
||||
@ -150,7 +167,6 @@ fn test_transaction_rollback() {
|
||||
|
||||
let trans = or_fail!(conn.transaction());
|
||||
or_fail!(trans.execute("INSERT INTO foo (id) VALUES ($1)", [&2i32]));
|
||||
trans.set_rollback();
|
||||
drop(trans);
|
||||
|
||||
let stmt = or_fail!(conn.prepare("SELECT * FROM foo"));
|
||||
@ -168,7 +184,6 @@ fn test_transaction_rollback_finish() {
|
||||
|
||||
let trans = or_fail!(conn.transaction());
|
||||
or_fail!(trans.execute("INSERT INTO foo (id) VALUES ($1)", [&2i32]));
|
||||
trans.set_rollback();
|
||||
assert!(trans.finish().is_ok());
|
||||
|
||||
let stmt = or_fail!(conn.prepare("SELECT * FROM foo"));
|
||||
@ -191,7 +206,6 @@ fn test_nested_transactions() {
|
||||
{
|
||||
let trans2 = or_fail!(trans1.transaction());
|
||||
or_fail!(trans2.execute("INSERT INTO foo (id) VALUES (3)", []));
|
||||
trans2.set_rollback();
|
||||
}
|
||||
|
||||
{
|
||||
@ -201,21 +215,21 @@ fn test_nested_transactions() {
|
||||
{
|
||||
let trans3 = or_fail!(trans2.transaction());
|
||||
or_fail!(trans3.execute("INSERT INTO foo (id) VALUES (5)", []));
|
||||
trans3.set_rollback();
|
||||
}
|
||||
|
||||
{
|
||||
let trans3 = or_fail!(trans2.transaction());
|
||||
or_fail!(trans3.execute("INSERT INTO foo (id) VALUES (6)", []));
|
||||
assert!(trans3.commit().is_ok());
|
||||
}
|
||||
|
||||
assert!(trans2.commit().is_ok());
|
||||
}
|
||||
|
||||
let stmt = or_fail!(trans1.prepare("SELECT * FROM foo ORDER BY id"));
|
||||
let result = or_fail!(stmt.query([]));
|
||||
|
||||
assert_eq!(vec![1i32, 2, 4, 6], result.map(|row| row.get(0u)).collect());
|
||||
|
||||
trans1.set_rollback();
|
||||
}
|
||||
|
||||
let stmt = or_fail!(conn.prepare("SELECT * FROM foo ORDER BY id"));
|
||||
@ -238,7 +252,6 @@ fn test_nested_transactions_finish() {
|
||||
{
|
||||
let trans2 = or_fail!(trans1.transaction());
|
||||
or_fail!(trans2.execute("INSERT INTO foo (id) VALUES (3)", []));
|
||||
trans2.set_rollback();
|
||||
assert!(trans2.finish().is_ok());
|
||||
}
|
||||
|
||||
@ -249,16 +262,17 @@ fn test_nested_transactions_finish() {
|
||||
{
|
||||
let trans3 = or_fail!(trans2.transaction());
|
||||
or_fail!(trans3.execute("INSERT INTO foo (id) VALUES (5)", []));
|
||||
trans3.set_rollback();
|
||||
assert!(trans3.finish().is_ok());
|
||||
}
|
||||
|
||||
{
|
||||
let trans3 = or_fail!(trans2.transaction());
|
||||
or_fail!(trans3.execute("INSERT INTO foo (id) VALUES (6)", []));
|
||||
trans3.set_commit();
|
||||
assert!(trans3.finish().is_ok());
|
||||
}
|
||||
|
||||
trans2.set_commit();
|
||||
assert!(trans2.finish().is_ok());
|
||||
}
|
||||
|
||||
@ -270,7 +284,6 @@ fn test_nested_transactions_finish() {
|
||||
assert_eq!(vec![1i32, 2, 4, 6], result.map(|row| row.get(0u)).collect());
|
||||
}
|
||||
|
||||
trans1.set_rollback();
|
||||
assert!(trans1.finish().is_ok());
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user