diff --git a/src/lib/lib.rs b/src/lib/lib.rs index ce785667..1fc9b33d 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -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, @@ -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 diff --git a/src/test/test.rs b/src/test/test.rs index b3f299b7..128f87c8 100644 --- a/src/test/test.rs +++ b/src/test/test.rs @@ -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()); }