Merge branch '2.7' into 2.8
* 2.7: fixed CS Fixes for Oracle in PdoSessionHandler
This commit is contained in:
commit
2250ab1228
@ -330,13 +330,7 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$updateStmt = $this->pdo->prepare(
|
$updateStmt = $this->getUpdateStatement($sessionId, $data, $maxlifetime);
|
||||||
"UPDATE $this->table SET $this->dataCol = :data, $this->lifetimeCol = :lifetime, $this->timeCol = :time WHERE $this->idCol = :id"
|
|
||||||
);
|
|
||||||
$updateStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
|
|
||||||
$updateStmt->bindParam(':data', $data, \PDO::PARAM_LOB);
|
|
||||||
$updateStmt->bindParam(':lifetime', $maxlifetime, \PDO::PARAM_INT);
|
|
||||||
$updateStmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
|
||||||
$updateStmt->execute();
|
$updateStmt->execute();
|
||||||
|
|
||||||
// When MERGE is not supported, like in Postgres < 9.5, we have to use this approach that can result in
|
// When MERGE is not supported, like in Postgres < 9.5, we have to use this approach that can result in
|
||||||
@ -346,13 +340,7 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||||||
// false positives due to longer gap locking.
|
// false positives due to longer gap locking.
|
||||||
if (!$updateStmt->rowCount()) {
|
if (!$updateStmt->rowCount()) {
|
||||||
try {
|
try {
|
||||||
$insertStmt = $this->pdo->prepare(
|
$insertStmt = $this->getInsertStatement($sessionId, $data, $maxlifetime);
|
||||||
"INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)"
|
|
||||||
);
|
|
||||||
$insertStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
|
|
||||||
$insertStmt->bindParam(':data', $data, \PDO::PARAM_LOB);
|
|
||||||
$insertStmt->bindParam(':lifetime', $maxlifetime, \PDO::PARAM_INT);
|
|
||||||
$insertStmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
|
||||||
$insertStmt->execute();
|
$insertStmt->execute();
|
||||||
} catch (\PDOException $e) {
|
} catch (\PDOException $e) {
|
||||||
// Handle integrity violation SQLSTATE 23000 (or a subclass like 23505 in Postgres) for duplicate keys
|
// Handle integrity violation SQLSTATE 23000 (or a subclass like 23505 in Postgres) for duplicate keys
|
||||||
@ -521,13 +509,7 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||||||
// Exclusive-reading of non-existent rows does not block, so we need to do an insert to block
|
// Exclusive-reading of non-existent rows does not block, so we need to do an insert to block
|
||||||
// until other connections to the session are committed.
|
// until other connections to the session are committed.
|
||||||
try {
|
try {
|
||||||
$insertStmt = $this->pdo->prepare(
|
$insertStmt = $this->getInsertStatement($sessionId, '', 0);
|
||||||
"INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)"
|
|
||||||
);
|
|
||||||
$insertStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
|
|
||||||
$insertStmt->bindValue(':data', '', \PDO::PARAM_LOB);
|
|
||||||
$insertStmt->bindValue(':lifetime', 0, \PDO::PARAM_INT);
|
|
||||||
$insertStmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
|
||||||
$insertStmt->execute();
|
$insertStmt->execute();
|
||||||
} catch (\PDOException $e) {
|
} catch (\PDOException $e) {
|
||||||
// Catch duplicate key error because other connection created the session already.
|
// Catch duplicate key error because other connection created the session already.
|
||||||
@ -662,6 +644,72 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||||||
return "SELECT $this->dataCol, $this->lifetimeCol, $this->timeCol FROM $this->table WHERE $this->idCol = :id";
|
return "SELECT $this->dataCol, $this->lifetimeCol, $this->timeCol FROM $this->table WHERE $this->idCol = :id";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an insert statement supported by the database for writing session data.
|
||||||
|
*
|
||||||
|
* @param string $sessionId Session ID
|
||||||
|
* @param string $sessionData Encoded session data
|
||||||
|
* @param int $maxlifetime session.gc_maxlifetime
|
||||||
|
*
|
||||||
|
* @return \PDOStatement The insert statement
|
||||||
|
*/
|
||||||
|
private function getInsertStatement($sessionId, $sessionData, $maxlifetime)
|
||||||
|
{
|
||||||
|
switch ($this->driver) {
|
||||||
|
case 'oci':
|
||||||
|
$data = fopen('php://memory', 'r+');
|
||||||
|
fwrite($data, $sessionData);
|
||||||
|
rewind($data);
|
||||||
|
$sql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, EMPTY_BLOB(), :lifetime, :time) RETURNING $this->dataCol into :data";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$data = $sessionData;
|
||||||
|
$sql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $this->pdo->prepare($sql);
|
||||||
|
$stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
|
||||||
|
$stmt->bindParam(':data', $data, \PDO::PARAM_LOB);
|
||||||
|
$stmt->bindParam(':lifetime', $maxlifetime, \PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
||||||
|
|
||||||
|
return $stmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an update statement supported by the database for writing session data.
|
||||||
|
*
|
||||||
|
* @param string $sessionId Session ID
|
||||||
|
* @param string $sessionData Encoded session data
|
||||||
|
* @param int $maxlifetime session.gc_maxlifetime
|
||||||
|
*
|
||||||
|
* @return \PDOStatement The update statement
|
||||||
|
*/
|
||||||
|
private function getUpdateStatement($sessionId, $sessionData, $maxlifetime)
|
||||||
|
{
|
||||||
|
switch ($this->driver) {
|
||||||
|
case 'oci':
|
||||||
|
$data = fopen('php://memory', 'r+');
|
||||||
|
fwrite($data, $sessionData);
|
||||||
|
rewind($data);
|
||||||
|
$sql = "UPDATE $this->table SET $this->dataCol = EMPTY_BLOB(), $this->lifetimeCol = :lifetime, $this->timeCol = :time WHERE $this->idCol = :id RETURNING $this->dataCol into :data";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$data = $sessionData;
|
||||||
|
$sql = "UPDATE $this->table SET $this->dataCol = :data, $this->lifetimeCol = :lifetime, $this->timeCol = :time WHERE $this->idCol = :id";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $this->pdo->prepare($sql);
|
||||||
|
$stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
|
||||||
|
$stmt->bindParam(':data', $data, \PDO::PARAM_LOB);
|
||||||
|
$stmt->bindParam(':lifetime', $maxlifetime, \PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
||||||
|
|
||||||
|
return $stmt;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a merge/upsert (i.e. insert or update) statement when supported by the database for writing session data.
|
* Returns a merge/upsert (i.e. insert or update) statement when supported by the database for writing session data.
|
||||||
*
|
*
|
||||||
@ -673,18 +721,11 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||||||
*/
|
*/
|
||||||
private function getMergeStatement($sessionId, $data, $maxlifetime)
|
private function getMergeStatement($sessionId, $data, $maxlifetime)
|
||||||
{
|
{
|
||||||
$mergeSql = null;
|
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case 'mysql' === $this->driver:
|
case 'mysql' === $this->driver:
|
||||||
$mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ".
|
$mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ".
|
||||||
"ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->lifetimeCol = VALUES($this->lifetimeCol), $this->timeCol = VALUES($this->timeCol)";
|
"ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->lifetimeCol = VALUES($this->lifetimeCol), $this->timeCol = VALUES($this->timeCol)";
|
||||||
break;
|
break;
|
||||||
case 'oci' === $this->driver:
|
|
||||||
// DUAL is Oracle specific dummy table
|
|
||||||
$mergeSql = "MERGE INTO $this->table USING DUAL ON ($this->idCol = ?) ".
|
|
||||||
"WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?) ".
|
|
||||||
"WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?";
|
|
||||||
break;
|
|
||||||
case 'sqlsrv' === $this->driver && version_compare($this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '10', '>='):
|
case 'sqlsrv' === $this->driver && version_compare($this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '10', '>='):
|
||||||
// MERGE is only available since SQL Server 2008 and must be terminated by semicolon
|
// MERGE is only available since SQL Server 2008 and must be terminated by semicolon
|
||||||
// It also requires HOLDLOCK according to http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx
|
// It also requires HOLDLOCK according to http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx
|
||||||
@ -699,12 +740,14 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||||||
$mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ".
|
$mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ".
|
||||||
"ON CONFLICT ($this->idCol) DO UPDATE SET ($this->dataCol, $this->lifetimeCol, $this->timeCol) = (EXCLUDED.$this->dataCol, EXCLUDED.$this->lifetimeCol, EXCLUDED.$this->timeCol)";
|
"ON CONFLICT ($this->idCol) DO UPDATE SET ($this->dataCol, $this->lifetimeCol, $this->timeCol) = (EXCLUDED.$this->dataCol, EXCLUDED.$this->lifetimeCol, EXCLUDED.$this->timeCol)";
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
// MERGE is not supported with LOBs: http://www.oracle.com/technetwork/articles/fuecks-lobs-095315.html
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $mergeSql) {
|
|
||||||
$mergeStmt = $this->pdo->prepare($mergeSql);
|
$mergeStmt = $this->pdo->prepare($mergeSql);
|
||||||
|
|
||||||
if ('sqlsrv' === $this->driver || 'oci' === $this->driver) {
|
if ('sqlsrv' === $this->driver) {
|
||||||
$mergeStmt->bindParam(1, $sessionId, \PDO::PARAM_STR);
|
$mergeStmt->bindParam(1, $sessionId, \PDO::PARAM_STR);
|
||||||
$mergeStmt->bindParam(2, $sessionId, \PDO::PARAM_STR);
|
$mergeStmt->bindParam(2, $sessionId, \PDO::PARAM_STR);
|
||||||
$mergeStmt->bindParam(3, $data, \PDO::PARAM_LOB);
|
$mergeStmt->bindParam(3, $data, \PDO::PARAM_LOB);
|
||||||
@ -722,7 +765,6 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||||||
|
|
||||||
return $mergeStmt;
|
return $mergeStmt;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a PDO instance.
|
* Return a PDO instance.
|
||||||
|
Reference in New Issue
Block a user