8000 [HttpFoundation] Use UPSERT for sessions stored in PgSql >= 9.5 · symfony/symfony@8f4e9de · GitHub
[go: up one dir, main page]

Skip to content

Commit 8f4e9de

Browse files
[HttpFoundation] Use UPSERT for sessions stored in PgSql >= 9.5
1 parent f15b630 commit 8f4e9de

File tree

2 files changed

+16
-10
lines changed

2 files changed

+16
-10
lines changed

src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandler.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public function write($sessionId, $data)
180180
$updateStmt->bindValue(':time', time(), \PDO::PARAM_INT);
181181
$updateStmt->execute();
182182

183-
// When MERGE is not supported, like in Postgres, we have to use this approach that can result in
183+
// When MERGE is not supported, like in Postgres < 9.5, we have to use this approach that can result in
184184
// duplicate key errors when the same session is written simultaneously. We can just catch such an
185185
// error and re-execute the update. This is similar to a serializable transaction with retry logic
186186
// on serialization failures but without the overhead and without possible false positives due to
@@ -224,11 +224,11 @@ private function getMergeSql()
224224
{
225225
$platform = $this->con->getDatabasePlatform()->getName();
226226

227-
switch ($platform) {
228-
case 'mysql':
227+
switch (true) {
228+
case 'mysql' === $platform:
229229
return "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) ".
230230
"ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->timeCol = VALUES($this->timeCol)";
231-
case 'oracle':
231+
case 'oracle' === $platform:
232232
// DUAL is Oracle specific dummy table
233233
return "MERGE INTO $this->table USING DUAL ON ($this->idCol = :id) ".
234234
"WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) ".
@@ -239,8 +239,11 @@ private function getMergeSql()
239239
return "MERGE INTO $this->table WITH (HOLDLOCK) USING (SELECT 1 AS dummy) AS src ON ($this->idCol = :id) ".
240240
"WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) ".
241241
"WHEN MATCHED THEN UPDATE SET $this->dataCol = :data, $this->timeCol = :time;";
242-
case 'sqlite':
242+
case 'sqlite' === $platform:
243243
return "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)";
244+
case 'postgresql' === $platform && version_compare($this->con->getServerVersion(), '9.5.0', ' 8000 >='):
245+
return "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) ".
246+
"ON CONFLICT ($this->idCol) DO UPDATE SET ($this->dataCol, $this->timeCol) = (:data, :time) WHERE $this->idCol = :id";
244247
}
245248
}
246249
}

src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ public function write($sessionId, $data)
347347
$updateStmt->bindValue(':time', time(), \PDO::PARAM_INT);
348348
$updateStmt->execute();
349349

350-
// When MERGE is not supported, like in Postgres, we have to use this approach that can result in
350+
// When MERGE is not supported, like in Postgres < 9.5, we have to use this approach that can result in
351351
// duplicate key errors when the same session is written simultaneously (given the LOCK_NONE behavior).
352352
// We can just catch such an error and re-execute the update. This is similar to a serializable
353353
// transaction with retry logic on serialization failures but without the overhead and without possible
@@ -659,11 +659,11 @@ private function getSelectSql()
659659
*/
660660
private function getMergeSql()
661661
{
662-
switch ($this->driver) {
663-
case 'mysql':
662+
switch (true) {
663+
case 'mysql' === $this->driver:
664664
return "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ".
665665
"ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->lifetimeCol = VALUES($this->lifetimeCol), $this->timeCol = VALUES($this->timeCol)";
666-
case 'oci':
666+
case 'oci' === $this->driver:
667667
// DUAL is Oracle specific dummy table
668668
return "MERGE INTO $this->table USING DUAL ON ($this->idCol = :id) ".
669669
"WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ".
@@ -674,8 +674,11 @@ private function getMergeSql()
674674
return "MERGE INTO $this->table WITH (HOLDLOCK) USING (SELECT 1 AS dummy) AS src ON ($this->idCol = :id) ".
675675
"WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ".
676676
"WHEN MATCHED THEN UPDATE SET $this->dataCol = :data, $this->lifetimeCol = :lifetime, $this->timeCol = :time;";
677-
case 'sqlite':
677+
case 'sqlite' === $this->driver:
678678
return "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)";
679+
case 'pgsql' === $this->driver && version_compare($this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '9.5', '>='):
680+
return "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ".
681+
"ON CONFLICT ($this->idCol) DO UPDATE SET ($this->dataCol, $this->lifetimeCol, $this->timeCol) = (:data, :lifetime, :time) WHERE $this->idCol = :id";
679682
}
680683
}
681684

0 commit comments

Comments
 (0)
0