Skip to content

Commit

Permalink
Convert driver exceptions when starting transactions
Browse files Browse the repository at this point in the history
For long-running processes, it's possible that the wrapped connection is
no longer valid and starting a transaction will lead to driver
exceptions.

DBAL Connection wasn't converting these, leaking internal details of the
platform and not providing a consistent API (all other methods would
throw a `ConnectionLost` exception for the scenario above).

This ensures we do have the expected behaviour for this edge-case.

Signed-off-by: Luís Cobucci <lcobucci@gmail.com>
  • Loading branch information
lcobucci committed Feb 25, 2025
1 parent 369ab24 commit 5fa77a9
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 3 deletions.
12 changes: 9 additions & 3 deletions src/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -1026,10 +1026,16 @@ public function beginTransaction(): void

++$this->transactionNestingLevel;

if ($this->transactionNestingLevel === 1) {
$connection->beginTransaction();
} else {
if ($this->transactionNestingLevel !== 1) {
$this->createSavepoint($this->_getNestedTransactionSavePointName());

return;
}

try {
$connection->beginTransaction();
} catch (Driver\Exception $e) {
throw $this->convertException($e);

Check warning on line 1038 in src/Connection.php

View check run for this annotation

Codecov / codecov/patch

src/Connection.php#L1037-L1038

Added lines #L1037 - L1038 were not covered by tests
}
}

Expand Down
29 changes: 29 additions & 0 deletions tests/ConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,35 @@ public function testCommitStartsTransactionInNoAutoCommitMode(): void
self::assertTrue($conn->isTransactionActive());
}

public function testDriverExceptionsAreConvertedDuringBeingTransaction(): void
{
$driverConnectionMock = self::createStub(DriverConnection::class);
$driverConnectionMock
->method('beginTransaction')
->willThrowException(
new Driver\PDO\Exception(
'SQLSTATE[HY000]: General error: 2006 MySQL server has gone away',
'HY000',
2006,
),
);

$mysqlConverter = new Driver\API\MySQL\ExceptionConverter();

$driver = self::createStub(Driver::class);
$driver
->method('getExceptionConverter')
->willReturn($mysqlConverter);
$driver
->method('connect')
->willReturn($driverConnectionMock);

$conn = new Connection([], $driver);

$this->expectException(Exception\ConnectionLost::class);
$conn->beginTransaction();
}

public function testBeginTransactionFailureAfterCommitInNoAutoCommitMode(): void
{
$driverConnectionMock = $this->createMock(DriverConnection::class);
Expand Down

0 comments on commit 5fa77a9

Please sign in to comment.