diff --git a/lib/Connection.php b/lib/Connection.php old mode 100644 new mode 100755 index c32311bcb..98495cbde --- a/lib/Connection.php +++ b/lib/Connection.php @@ -77,6 +77,12 @@ abstract class Connection */ static $DEFAULT_PORT = 0; + /** + * Number of nested transactions + * @var int + */ + static protected $transaction_counter = 0; + /** * Retrieve a database connection. * @@ -376,8 +382,14 @@ public function tables() */ public function transaction() { - if (!$this->connection->beginTransaction()) - throw new DatabaseException($this); + // Transaction started already + if (static::$transaction_counter++) { + $this->connection->exec('SAVEPOINT trans'.static::$transaction_counter); + return; + } + + if (!$this->connection->beginTransaction()) + throw new DatabaseException($this); } /** @@ -385,6 +397,11 @@ public function transaction() */ public function commit() { + // Nested transaction simply decrease number + if (--static::$transaction_counter) { + return; + } + if (!$this->connection->commit()) throw new DatabaseException($this); } @@ -394,6 +411,11 @@ public function commit() */ public function rollback() { + if (--static::$transaction_counter) { + $this->connection->exec('ROLLBACK TO trans'.(static::$transaction_counter + 1)); + return true; + } + if (!$this->connection->rollback()) throw new DatabaseException($this); } diff --git a/test/helpers/AdapterTest.php b/test/helpers/AdapterTest.php old mode 100644 new mode 100755 index 97685f6bc..d4a662f0d --- a/test/helpers/AdapterTest.php +++ b/test/helpers/AdapterTest.php @@ -407,5 +407,34 @@ public function test_date_to_string() $datetime = '2009-01-01'; $this->assert_equals($datetime,$this->conn->date_to_string(date_create($datetime))); } + + + public function test_transaction_nested_commit() + { + $original = $this->conn->query_and_fetch_one("select count(*) from authors"); + + $this->conn->transaction(); + $this->conn->query("insert into authors(author_id,name) values(9998,'blahhhhhhhh')"); + // Nested + $this->conn->transaction(); + $this->conn->query("insert into authors(author_id,name) values(9999,'blahhhhhhhh')"); + $this->conn->commit(); + + // Another nested + try { + $this->conn->transaction(); + $this->conn->query("insert into authors(author_id,name) values(9999,'blahhhhhhhh')"); // fails + $this->conn->commit(); + } + catch (Exception $e) + { + $this->conn->rollback(); + } + + // Commit primary transaction + $this->conn->commit(); + + $this->assert_equals($original+2, $this->conn->query_and_fetch_one("select count(*) from authors")); + } } ?>