bug #19101 [Session] fix PDO transaction aborted under PostgreSQL (Tobion)
This PR was merged into the 2.7 branch.
Discussion
----------
[Session] fix PDO transaction aborted under PostgreSQL
| Q | A
| ------------- | ---
| Branch? | 2.7
| Bug fix? | yes
| New feature? | no
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #14641
| License | MIT
| Doc PR |
Fixes the transactional concurrency error handling for PostgreSQL which does not allow to execute further queries in a transaction with an error.
Because of the loop, look at the diff with whitespace ignored to see the difference: https://github.com/symfony/symfony/pull/19101/files?w=1
Commits
-------
f8eefa0
[Session] fix PDO transaction aborted under PostgreSQL
This commit is contained in:
commit
9df08fac89
|
@ -504,8 +504,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) {
|
||||
|
@ -534,17 +535,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;
|
||||
|
@ -552,6 +548,7 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||
}
|
||||
|
||||
return '';
|
||||
} while (true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -362,4 +362,8 @@ class MockPdo extends \PDO
|
|||
public function beginTransaction()
|
||||
{
|
||||
}
|
||||
|
||||
public function rollBack()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
Reference in New Issue