Skip to content

Commit 486b156

Browse files
authored
Fix for collisions in placeholders (#446)
* Fix for collisions in placeholders * add new test
1 parent 4c4b45a commit 486b156

3 files changed

Lines changed: 67 additions & 0 deletions

File tree

src/Command/ParamBuilder.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ final class ParamBuilder implements ExpressionBuilderInterface
1818
public function build(ExpressionInterface $expression, array &$params = []): string
1919
{
2020
$placeholder = self::PARAM_PREFIX . count($params);
21+
22+
$additionalCount = 0;
23+
while (isset($params[$placeholder])) {
24+
$placeholder = self::PARAM_PREFIX . count($params) . '_' . $additionalCount;
25+
++$additionalCount;
26+
}
27+
2128
$params[$placeholder] = $expression;
2229
return $placeholder;
2330
}

src/QueryBuilder/QueryBuilder.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,13 @@ public function batchInsert(string $table, array $columns, iterable|Generator $r
131131
public function bindParam(mixed $value, array &$params = []): string
132132
{
133133
$phName = self::PARAM_PREFIX . count($params);
134+
135+
$additionalCount = 0;
136+
while (isset($params[$phName])) {
137+
$phName = self::PARAM_PREFIX . count($params) . '_' . $additionalCount;
138+
++$additionalCount;
139+
}
140+
134141
/** @psalm-var mixed */
135142
$params[$phName] = $value;
136143

tests/AbstractQueryBuilderTest.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Closure;
88
use PHPUnit\Framework\TestCase;
99
use stdClass;
10+
use Yiisoft\Db\Command\Param;
1011
use Yiisoft\Db\Exception\InvalidArgumentException;
1112
use Yiisoft\Db\Exception\NotSupportedException;
1213
use Yiisoft\Db\Expression\Expression;
@@ -1930,4 +1931,56 @@ public function testUpsertExecute(
19301931
$command = $db->createCommand($actualSQL, $actualParams);
19311932
$command->execute();
19321933
}
1934+
1935+
public function testOverrideParameters1()
1936+
{
1937+
$db = $this->getConnection();
1938+
1939+
$params = [':id' => 1, ':pv2' => new Expression('(select type from {{%animal}}) where id=1')];
1940+
$expression = new Expression('id = :id AND type = :pv2', $params);
1941+
1942+
$query = new Query($db);
1943+
$query->select('*')
1944+
->from('{{%animal}}')
1945+
->andWhere($expression)
1946+
->andWhere(['type' => new Param('test1', \PDO::PARAM_STR)])
1947+
;
1948+
1949+
$command = $query->createCommand();
1950+
$this->assertCount(3, $command->getParams());
1951+
$this->assertEquals([':id', ':pv2', ':pv2_0',], array_keys($command->getParams()));
1952+
$this->assertEquals(
1953+
DbHelper::replaceQuotes(
1954+
'SELECT * FROM [[animal]] WHERE (id = 1 AND type = (select type from {{%animal}}) where id=1) AND ([[type]]=\'test1\')',
1955+
$db->getName()
1956+
),
1957+
$command->getRawSql()
1958+
);
1959+
}
1960+
1961+
public function testOverrideParameters2()
1962+
{
1963+
$db = $this->getConnection();
1964+
1965+
$expression = new Expression('id = :qp1', [':qp1' => 1]);
1966+
1967+
$query = new Query($db);
1968+
$query->select('*')
1969+
->from('{{%animal}}')
1970+
->andWhere($expression)
1971+
->andWhere(['type' => 'test2'])
1972+
;
1973+
1974+
$command = $query->createCommand();
1975+
1976+
$this->assertCount(2, $command->getParams());
1977+
$this->assertEquals([':qp1', ':qp1_0',], array_keys($command->getParams()));
1978+
$this->assertEquals(
1979+
DbHelper::replaceQuotes(
1980+
'SELECT * FROM [[animal]] WHERE (id = 1) AND ([[type]]=\'test2\')',
1981+
$db->getName()
1982+
),
1983+
$command->getRawSql()
1984+
);
1985+
}
19331986
}

0 commit comments

Comments
 (0)