Skip to content

PdoSessionHandler: fix advisory lock for pgsql #24367

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -580,11 +580,11 @@ private function doAdvisoryLock($sessionId)
return $releaseStmt;
case 'pgsql':
// Obtaining an exclusive session level advisory lock requires an integer key.
// So we convert the HEX representation of the session id to an integer.
// Since integers are signed, we have to skip one hex char to fit in the range.
if (4 === PHP_INT_SIZE) {
$sessionInt1 = hexdec(substr($sessionId, 0, 7));
$sessionInt2 = hexdec(substr($sessionId, 7, 7));
// When session.sid_bits_per_character > 4, the session id can contain non-hex-characters.
// So we cannot just use hexdec().
if (4 === \PHP_INT_SIZE) {
$sessionInt1 = $this->convertStringToInt($sessionId);
$sessionInt2 = $this->convertStringToInt(substr($sessionId, 4, 4));

$stmt = $this->pdo->prepare('SELECT pg_advisory_lock(:key1, :key2)');
$stmt->bindValue(':key1', $sessionInt1, \PDO::PARAM_INT);
Expand All @@ -595,7 +595,7 @@ private function doAdvisoryLock($sessionId)
$releaseStmt->bindValue(':key1', $sessionInt1, \PDO::PARAM_INT);
$releaseStmt->bindValue(':key2', $sessionInt2, \PDO::PARAM_INT);
} else {
$sessionBigInt = hexdec(substr($sessionId, 0, 15));
$sessionBigInt = $this->convertStringToInt($sessionId);

$stmt = $this->pdo->prepare('SELECT pg_advisory_lock(:key)');
$stmt->bindValue(':key', $sessionBigInt, \PDO::PARAM_INT);
Expand All @@ -613,6 +613,27 @@ private function doAdvisoryLock($sessionId)
}
}

/**
* Encodes the first 4 (when PHP_INT_SIZE == 4) or 8 characters of the string as an integer.
*
* Keep in mind, PHP integers are signed.
*
* @param string $string
*
* @return int
*/
private function convertStringToInt($string)
{
if (4 === \PHP_INT_SIZE) {
return (ord($string[3]) << 24) + (ord($string[2]) << 16) + (ord($string[1]) << 8) + ord($string[0]);
}

$int1 = (ord($string[7]) << 24) + (ord($string[6]) << 16) + (ord($string[5]) << 8) + ord($string[4]);
$int2 = (ord($string[3]) << 24) + (ord($string[2]) << 16) + (ord($string[1]) << 8) + ord($string[0]);

return $int2 + ($int1 << 32);
}

/**
* Return a locking or nonlocking SQL query to read session information.
*
Expand Down