From 07136aa710cc749d9ccf2f5be7bdcf3c90972662 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Wed, 14 Jul 2021 18:06:41 -0700 Subject: [PATCH] Handle lost connection during commit --- src/Connection.php | 4 ++ src/Driver/PDO/Connection.php | 12 +++++- tests/Functional/TransactionTest.php | 64 ++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 tests/Functional/TransactionTest.php diff --git a/src/Connection.php b/src/Connection.php index afcbc040f87..547e1f7508d 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -1237,6 +1237,8 @@ public function commit(): void try { $connection->commit(); + } catch (Driver\Exception $e) { + throw $this->convertException($e); } finally { $logger->stopQuery(); } @@ -1298,6 +1300,8 @@ public function rollBack(): void try { $connection->rollBack(); + } catch (Driver\Exception $e) { + throw $this->convertException($e); } finally { $this->isRollbackOnly = false; $logger->stopQuery(); diff --git a/src/Driver/PDO/Connection.php b/src/Driver/PDO/Connection.php index e6942c6386a..b8fb1b6e147 100644 --- a/src/Driver/PDO/Connection.php +++ b/src/Driver/PDO/Connection.php @@ -112,12 +112,20 @@ public function beginTransaction(): void public function commit(): void { - $this->connection->commit(); + try { + $this->connection->commit(); + } catch (PDOException $exception) { + throw Exception::new($exception); + } } public function rollBack(): void { - $this->connection->rollBack(); + try { + $this->connection->rollBack(); + } catch (PDOException $exception) { + throw Exception::new($exception); + } } public function getWrappedConnection(): PDO diff --git a/tests/Functional/TransactionTest.php b/tests/Functional/TransactionTest.php new file mode 100644 index 00000000000..929e523e63f --- /dev/null +++ b/tests/Functional/TransactionTest.php @@ -0,0 +1,64 @@ +connection->getDatabasePlatform() instanceof MySQLPlatform) { + return; + } + + self::markTestSkipped('Restricted to MySQL.'); + } + + public function testCommitFailure(): void + { + $this->expectConnectionLoss(static function (Connection $connection): void { + $connection->commit(); + }); + } + + public function testRollbackFailure(): void + { + $this->expectConnectionLoss(static function (Connection $connection): void { + $connection->rollBack(); + }); + } + + private function expectConnectionLoss(callable $scenario): void + { + if (PHP_VERSION_ID < 70413 && $this->connection->getDriver() instanceof PDO\MySQL\Driver) { + self::markTestSkipped('See https://bugs.php.net/bug.php?id=66528.'); + } + + $this->connection->executeStatement('SET SESSION wait_timeout=1'); + $this->connection->beginTransaction(); + + // during the sleep MySQL will close the connection + sleep(2); + + // prevent the PHPUnit error handler from handling the "MySQL server has gone away" warning + $this->iniSet('error_reporting', (string) (E_ALL & ~E_WARNING)); + + $this->expectException(ConnectionLost::class); + $scenario($this->connection); + } +}