Skip to content

Commit 51208fc

Browse files
authored
Fix #19770: Fix yii\mutex\MysqlMutex keyPrefix expression param binding
1 parent f388ca7 commit 51208fc

File tree

3 files changed

+56
-7
lines changed

3 files changed

+56
-7
lines changed

framework/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Yii Framework 2 Change Log
2020
- Bug #19734: PHP 8.1 compatibility fix for `$query->orderBy(null)` (uaoleg)
2121
- Bug #19731: Fix `yii\data\Sort` to generate proper link when multisort is on and attribute has a default sort order set (bizley)
2222
- Bug #19735: Fix `yii\validators\NumberValidator` to use programmable message for the value validation (bizley)
23+
- Bug #19770: Fix `yii\mutex\MysqlMutex` `keyPrefix` expression param binding (kamarton)
2324

2425
2.0.47 November 18, 2022
2526
------------------------

framework/mutex/MysqlMutex.php

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,13 @@ protected function acquireLock($name, $timeout = 0)
6969
{
7070
return $this->db->useMaster(function ($db) use ($name, $timeout) {
7171
/** @var \yii\db\Connection $db */
72-
return (bool) $db->createCommand(
73-
'SELECT GET_LOCK(SUBSTRING(CONCAT(:prefix, :name), 1, 64), :timeout)',
74-
[':name' => $this->hashLockName($name), ':timeout' => $timeout, ':prefix' => $this->keyPrefix]
72+
$nameData = $this->prepareName();
73+
return (bool)$db->createCommand(
74+
'SELECT GET_LOCK(' . $nameData[0] . ', :timeout), :prefix',
75+
array_merge(
76+
[':name' => $this->hashLockName($name), ':timeout' => $timeout, ':prefix' => $this->keyPrefix],
77+
$nameData[1]
78+
)
7579
)->queryScalar();
7680
});
7781
}
@@ -86,13 +90,33 @@ protected function releaseLock($name)
8690
{
8791
return $this->db->useMaster(function ($db) use ($name) {
8892
/** @var \yii\db\Connection $db */
89-
return (bool) $db->createCommand(
90-
'SELECT RELEASE_LOCK(SUBSTRING(CONCAT(:prefix, :name), 1, 64))',
91-
[':name' => $this->hashLockName($name), ':prefix' => $this->keyPrefix]
93+
$nameData = $this->prepareName();
94+
return (bool)$db->createCommand(
95+
'SELECT RELEASE_LOCK(' . $nameData[0] . '), :prefix',
96+
array_merge(
97+
[':name' => $this->hashLockName($name), ':prefix' => $this->keyPrefix],
98+
$nameData[1]
99+
)
92100
)->queryScalar();
93101
});
94102
}
95103

104+
/**
105+
* Prepare lock name
106+
* @return array expression and params
107+
* @since 2.0.48
108+
*/
109+
protected function prepareName()
110+
{
111+
$params = [];
112+
$expression = "SUBSTRING(CONCAT(:prefix, :name), 1, 64)";
113+
if ($this->keyPrefix instanceof Expression) {
114+
$expression = strtr($expression, [':prefix' => $this->keyPrefix->expression]);
115+
$params = $this->keyPrefix->params;
116+
}
117+
return [$expression, $params];
118+
}
119+
96120
/**
97121
* Generate hash for lock name to avoid exceeding lock name length limit.
98122
*
@@ -101,7 +125,8 @@ protected function releaseLock($name)
101125
* @since 2.0.16
102126
* @see https://github.com/yiisoft/yii2/pull/16836
103127
*/
104-
protected function hashLockName($name) {
128+
protected function hashLockName($name)
129+
{
105130
return sha1($name);
106131
}
107132
}

tests/framework/mutex/MysqlMutexTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,27 @@ public function testThatMutexLocksWithKeyPrefixesExpression($mutexName)
8484
$this->assertTrue($mutexOne->release($mutexName));
8585
$this->assertTrue($mutexTwo->release($mutexName));
8686
}
87+
88+
/**
89+
* @dataProvider mutexDataProvider()
90+
*
91+
* @param string $mutexName
92+
*/
93+
public function testThatMutexLocksWithKeyPrefixesExpressionCalculatedValue($mutexName)
94+
{
95+
$mutexOne = $this->createMutex(['keyPrefix' => new Expression('1+1')]);
96+
$mutexTwo = $this->createMutex(['keyPrefix' => new Expression('1*2')]);
97+
98+
$this->assertTrue($mutexOne->acquire($mutexName));
99+
$this->assertFalse($mutexTwo->acquire($mutexName));
100+
$this->assertTrue($mutexOne->release($mutexName));
101+
}
102+
103+
public function testCreateMutex()
104+
{
105+
$mutex = $this->createMutex(['keyPrefix' => new Expression('1+1')]);
106+
$this->assertInstanceOf(MysqlMutex::classname(), $mutex);
107+
$this->assertInstanceOf(Expression::classname(), $mutex->keyPrefix);
108+
$this->assertSame("1+1", $mutex->keyPrefix->expression);
109+
}
87110
}

0 commit comments

Comments
 (0)