[Session] fix PDO transaction aborted under PostgreSQL

This commit is contained in:
Tobias Schultze 2016-06-18 18:41:57 +02:00
parent 86552ea2dc
commit f8eefa0748
2 changed files with 41 additions and 40 deletions

View File

@ -510,8 +510,9 @@ class PdoSessionHandler implements \SessionHandlerInterface
$selectSql = $this->getSelectSql();
$selectStmt = $this->pdo->prepare($selectSql);
$selectStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$selectStmt->execute();
do {
$selectStmt->execute();
$sessionRows = $selectStmt->fetchAll(\PDO::FETCH_NUM);
if ($sessionRows) {
@ -540,17 +541,12 @@ class PdoSessionHandler implements \SessionHandlerInterface
// Catch duplicate key error because other connection created the session already.
// It would only not be the case when the other connection destroyed the session.
if (0 === strpos($e->getCode(), '23')) {
// Retrieve finished session data written by concurrent connection. SELECT
// FOR UPDATE is necessary to avoid deadlock of connection that starts reading
// before we write (transform intention to real lock).
$selectStmt->execute();
$sessionRows = $selectStmt->fetchAll(\PDO::FETCH_NUM);
if ($sessionRows) {
return is_resource($sessionRows[0][0]) ? stream_get_contents($sessionRows[0][0]) : $sessionRows[0][0];
}
return '';
// Retrieve finished session data written by concurrent connection by restarting the loop.
// We have to start a new transaction as a failed query will mark the current transaction as
// aborted in PostgreSQL and disallow further queries within it.
$this->rollback();
$this->beginTransaction();
continue;
}
throw $e;
@ -558,6 +554,7 @@ class PdoSessionHandler implements \SessionHandlerInterface
}
return '';
} while (true);
}
/**

View File

@ -362,4 +362,8 @@ class MockPdo extends \PDO
public function beginTransaction()
{
}
public function rollBack()
{
}
}