From b00e55628955546efa3e9aa1109cffd75d1626fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20H=C5=AFla?= Date: Sun, 4 Apr 2021 22:35:32 +0200 Subject: [PATCH] Connection::transtaction() call can be nested --- src/Dibi/Connection.php | 20 +++++++++++--- tests/dibi/Connection.transactions.phpt | 35 +++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/Dibi/Connection.php b/src/Dibi/Connection.php index 16a5241..3e54a39 100644 --- a/src/Dibi/Connection.php +++ b/src/Dibi/Connection.php @@ -40,6 +40,8 @@ class Connection implements IConnection /** @var HashMap Substitutes for identifiers */ private $substitutes; + private $transactionDepth = 0; + /** * Connection options: (see driver-specific options too) @@ -407,14 +409,26 @@ class Connection implements IConnection */ public function transaction(callable $callback) { - $this->begin(); + if ($this->transactionDepth === 0) { + $this->begin(); + } + + $this->transactionDepth++; try { $res = $callback($this); } catch (\Throwable $e) { - $this->rollback(); + $this->transactionDepth--; + if ($this->transactionDepth === 0) { + $this->rollback(); + } throw $e; } - $this->commit(); + + $this->transactionDepth--; + if ($this->transactionDepth === 0) { + $this->commit(); + } + return $res; } diff --git a/tests/dibi/Connection.transactions.phpt b/tests/dibi/Connection.transactions.phpt index a4953d9..b24f8e0 100644 --- a/tests/dibi/Connection.transactions.phpt +++ b/tests/dibi/Connection.transactions.phpt @@ -73,3 +73,38 @@ test('transaction() success', function () use ($conn) { }); Assert::same(5, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle()); }); + + +test('nested transaction() call fail', function () use ($conn) { + Assert::exception(function () use ($conn) { + $conn->transaction(function (Dibi\Connection $connection) { + $connection->query('INSERT INTO [products]', [ + 'title' => 'Test product', + ]); + + $connection->transaction(function (Dibi\Connection $connection2) { + $connection2->query('INSERT INTO [products]', [ + 'title' => 'Test product', + ]); + throw new Exception('my exception'); + }); + }); + }, \Throwable::class, 'my exception'); + Assert::same(5, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle()); +}); + + +test('nested transaction() call success', function () use ($conn) { + $conn->transaction(function (Dibi\Connection $connection) { + $connection->query('INSERT INTO [products]', [ + 'title' => 'Test product', + ]); + + $connection->transaction(function (Dibi\Connection $connection2) { + $connection2->query('INSERT INTO [products]', [ + 'title' => 'Test product', + ]); + }); + }); + Assert::same(7, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle()); +});