From c204fe1dca1d2949544b3e2b443942e2a0f00c6b Mon Sep 17 00:00:00 2001 From: Simon Podlipsky Date: Fri, 11 Oct 2024 13:56:10 +0200 Subject: [PATCH] Run risky code in finally block (#6543) | Q | A |------------- | ----------- | Type | bug | Fixed issues | https://github.com/doctrine/dbal/pull/4846 #### Summary Let's do the same thing as for ORM in https://github.com/doctrine/orm/pull/11646 This somehow solves issue we tried to resolve in https://github.com/doctrine/dbal/pull/4846 by providing original exception in Previous. --- src/Connection.php | 13 +++++++++---- tests/ConnectionTest.php | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/Connection.php b/src/Connection.php index b9756706061..9ca4d74b024 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -1278,15 +1278,20 @@ public function lastInsertId($name = null) public function transactional(Closure $func) { $this->beginTransaction(); + + $successful = false; + try { $res = $func($this); $this->commit(); - return $res; - } catch (Throwable $e) { - $this->rollBack(); + $successful = true; - throw $e; + return $res; + } finally { + if (! $successful) { + $this->rollBack(); + } } } diff --git a/tests/ConnectionTest.php b/tests/ConnectionTest.php index 0a94a129b45..719647989f9 100644 --- a/tests/ConnectionTest.php +++ b/tests/ConnectionTest.php @@ -1004,6 +1004,27 @@ public function testLegacySchemaManagerFactory(): void $connection = DriverManager::getConnection(['driver' => 'sqlite3', 'memory' => true]); self::assertInstanceOf(SqliteSchemaManager::class, $connection->createSchemaManager()); } + + public function testItPreservesTheOriginalExceptionOnRollbackFailure(): void + { + $connection = new class (['memory' => true], new Driver\SQLite3\Driver()) extends Connection { + public function rollBack(): void + { + throw new Exception('Rollback exception'); + } + }; + + try { + $connection->transactional(static function (): void { + throw new Exception('Original exception'); + }); + self::fail('Exception expected'); + } catch (Exception $e) { + self::assertSame('Rollback exception', $e->getMessage()); + self::assertNotNull($e->getPrevious()); + self::assertSame('Original exception', $e->getPrevious()->getMessage()); + } + } } interface ConnectDispatchEventListener