$maxlifetime =
(int) (($this->ttl instanceof \Closure ?
($this->ttl
)() :
$this->ttl
) ?? \
ini_get('session.gc_maxlifetime'
));
try { // We use a single MERGE SQL query when supported by the database.
$mergeStmt =
$this->
getMergeStatement($sessionId,
$data,
$maxlifetime);
if (null !==
$mergeStmt) { $mergeStmt->
execute();
return true;
} $updateStmt =
$this->
getUpdateStatement($sessionId,
$data,
$maxlifetime);
$updateStmt->
execute();
// When MERGE is not supported, like in Postgres < 9.5, we have to use this approach that can result in
// duplicate key errors when the same session is written simultaneously (given the LOCK_NONE behavior).
// We can just catch such an error and re-execute the update. This is similar to a serializable
// transaction with retry logic on serialization failures but without the overhead and without possible
// false positives due to longer gap locking.
if (!
$updateStmt->
rowCount()) { try { $insertStmt =
$this->
getInsertStatement($sessionId,
$data,
$maxlifetime);
$insertStmt->
execute();
}