PDO's inTransaction()
is returning false while still in a transaction if a database exception is thrown. This is probably specific to using PostgreSQL. e.g.
try {
$pdo->beginTransaction();
$pdo->exec('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE');
// ...
// Cause any PDO exception
// ...
$pdo->commit();
} catch (\Exception $e) {
if ($pdo->inTransaction()) {
// Never gets here
$pdo->rollback();
}
throw $e;
}
The transaction has definitely not ended because if I start another one I get an exception that there is already a transaction in progress. I haven't tested every type of exception, but it's definitely happening for SQLSTATE[40001]: Serialization failure
and primary key violations. Is this expected behavior or is it a bug in PHP?
It seems the only way to know to rollback is to keep a separate variable to know I'm in a transaction, making inTransaction()
useless. I've noticed that some open source frameworks (like Doctrine) and applications (like Drupal) keep their own variable for transaction state. Why can't we rely on the driver or database to tell us if a transaction is in progress?
PHP 5.5.32 and PostgreSQL 9.4. Found a two year old related bug report which was closed in an older version of PHP.