Fix #19770: Fix yii\mutex\MysqlMutex keyPrefix expression param binding

This commit is contained in:
Márton Somogyi
2023-02-27 12:45:33 +01:00
committed by GitHub
parent f388ca71b0
commit 51208fcb99
3 changed files with 56 additions and 7 deletions

View File

@ -20,6 +20,7 @@ Yii Framework 2 Change Log
- Bug #19734: PHP 8.1 compatibility fix for `$query->orderBy(null)` (uaoleg) - Bug #19734: PHP 8.1 compatibility fix for `$query->orderBy(null)` (uaoleg)
- Bug #19731: Fix `yii\data\Sort` to generate proper link when multisort is on and attribute has a default sort order set (bizley) - Bug #19731: Fix `yii\data\Sort` to generate proper link when multisort is on and attribute has a default sort order set (bizley)
- Bug #19735: Fix `yii\validators\NumberValidator` to use programmable message for the value validation (bizley) - Bug #19735: Fix `yii\validators\NumberValidator` to use programmable message for the value validation (bizley)
- Bug #19770: Fix `yii\mutex\MysqlMutex` `keyPrefix` expression param binding (kamarton)
2.0.47 November 18, 2022 2.0.47 November 18, 2022
------------------------ ------------------------

View File

@ -69,9 +69,13 @@ class MysqlMutex extends DbMutex
{ {
return $this->db->useMaster(function ($db) use ($name, $timeout) { return $this->db->useMaster(function ($db) use ($name, $timeout) {
/** @var \yii\db\Connection $db */ /** @var \yii\db\Connection $db */
return (bool) $db->createCommand( $nameData = $this->prepareName();
'SELECT GET_LOCK(SUBSTRING(CONCAT(:prefix, :name), 1, 64), :timeout)', return (bool)$db->createCommand(
[':name' => $this->hashLockName($name), ':timeout' => $timeout, ':prefix' => $this->keyPrefix] 'SELECT GET_LOCK(' . $nameData[0] . ', :timeout), :prefix',
array_merge(
[':name' => $this->hashLockName($name), ':timeout' => $timeout, ':prefix' => $this->keyPrefix],
$nameData[1]
)
)->queryScalar(); )->queryScalar();
}); });
} }
@ -86,13 +90,33 @@ class MysqlMutex extends DbMutex
{ {
return $this->db->useMaster(function ($db) use ($name) { return $this->db->useMaster(function ($db) use ($name) {
/** @var \yii\db\Connection $db */ /** @var \yii\db\Connection $db */
return (bool) $db->createCommand( $nameData = $this->prepareName();
'SELECT RELEASE_LOCK(SUBSTRING(CONCAT(:prefix, :name), 1, 64))', return (bool)$db->createCommand(
[':name' => $this->hashLockName($name), ':prefix' => $this->keyPrefix] 'SELECT RELEASE_LOCK(' . $nameData[0] . '), :prefix',
array_merge(
[':name' => $this->hashLockName($name), ':prefix' => $this->keyPrefix],
$nameData[1]
)
)->queryScalar(); )->queryScalar();
}); });
} }
/**
* Prepare lock name
* @return array expression and params
* @since 2.0.48
*/
protected function prepareName()
{
$params = [];
$expression = "SUBSTRING(CONCAT(:prefix, :name), 1, 64)";
if ($this->keyPrefix instanceof Expression) {
$expression = strtr($expression, [':prefix' => $this->keyPrefix->expression]);
$params = $this->keyPrefix->params;
}
return [$expression, $params];
}
/** /**
* Generate hash for lock name to avoid exceeding lock name length limit. * Generate hash for lock name to avoid exceeding lock name length limit.
* *
@ -101,7 +125,8 @@ class MysqlMutex extends DbMutex
* @since 2.0.16 * @since 2.0.16
* @see https://github.com/yiisoft/yii2/pull/16836 * @see https://github.com/yiisoft/yii2/pull/16836
*/ */
protected function hashLockName($name) { protected function hashLockName($name)
{
return sha1($name); return sha1($name);
} }
} }

View File

@ -84,4 +84,27 @@ class MysqlMutexTest extends DatabaseTestCase
$this->assertTrue($mutexOne->release($mutexName)); $this->assertTrue($mutexOne->release($mutexName));
$this->assertTrue($mutexTwo->release($mutexName)); $this->assertTrue($mutexTwo->release($mutexName));
} }
/**
* @dataProvider mutexDataProvider()
*
* @param string $mutexName
*/
public function testThatMutexLocksWithKeyPrefixesExpressionCalculatedValue($mutexName)
{
$mutexOne = $this->createMutex(['keyPrefix' => new Expression('1+1')]);
$mutexTwo = $this->createMutex(['keyPrefix' => new Expression('1*2')]);
$this->assertTrue($mutexOne->acquire($mutexName));
$this->assertFalse($mutexTwo->acquire($mutexName));
$this->assertTrue($mutexOne->release($mutexName));
}
public function testCreateMutex()
{
$mutex = $this->createMutex(['keyPrefix' => new Expression('1+1')]);
$this->assertInstanceOf(MysqlMutex::classname(), $mutex);
$this->assertInstanceOf(Expression::classname(), $mutex->keyPrefix);
$this->assertSame("1+1", $mutex->keyPrefix->expression);
}
} }