mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-02 04:37:42 +08:00
fixes #6792, use a simpler composite in condition implementation on dbs other than pgsql
This commit is contained in:
@ -1134,27 +1134,26 @@ class QueryBuilder extends \yii\base\Object
|
||||
*/
|
||||
protected function buildCompositeInCondition($operator, $columns, $values, &$params)
|
||||
{
|
||||
$quotedColumns = [];
|
||||
foreach ($columns as $i => $column) {
|
||||
$quotedColumns[$i] = strpos($column, '(') === false ? $this->db->quoteColumnName($column) : $column;
|
||||
}
|
||||
$vss = [];
|
||||
foreach ($values as $value) {
|
||||
$vs = [];
|
||||
foreach ($columns as $column) {
|
||||
foreach ($columns as $i => $column) {
|
||||
if (isset($value[$column])) {
|
||||
$phName = self::PARAM_PREFIX . count($params);
|
||||
$params[$phName] = $value[$column];
|
||||
$vs[] = $phName;
|
||||
$vs[] = $quotedColumns[$i] . ($operator === 'IN' ? ' = ' : ' != ') . $phName;
|
||||
} else {
|
||||
$vs[] = 'NULL';
|
||||
$vs[] = $quotedColumns[$i] . ($operator === 'IN' ? ' IS' : ' IS NOT') . ' NULL';
|
||||
}
|
||||
}
|
||||
$vss[] = '(' . implode(', ', $vs) . ')';
|
||||
}
|
||||
foreach ($columns as $i => $column) {
|
||||
if (strpos($column, '(') === false) {
|
||||
$columns[$i] = $this->db->quoteColumnName($column);
|
||||
}
|
||||
$vss[] = '(' . implode($operator === 'IN' ? ' AND ' : ' OR ', $vs) . ')';
|
||||
}
|
||||
|
||||
return '(' . implode(', ', $columns) . ") $operator (" . implode(', ', $vss) . ')';
|
||||
return '(' . implode($operator === 'IN' ? ' OR ' : ' AND ', $vss) . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -204,4 +204,38 @@ class QueryBuilder extends \yii\db\QueryBuilder
|
||||
return 'INSERT INTO ' . $schema->quoteTableName($table)
|
||||
. ' (' . implode(', ', $columns) . ') VALUES ' . implode(', ', $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds SQL for IN condition
|
||||
*
|
||||
* @param string $operator
|
||||
* @param array $columns
|
||||
* @param array $values
|
||||
* @param array $params
|
||||
* @return string SQL
|
||||
*/
|
||||
protected function buildCompositeInCondition($operator, $columns, $values, &$params)
|
||||
{
|
||||
$vss = [];
|
||||
foreach ($values as $value) {
|
||||
$vs = [];
|
||||
foreach ($columns as $column) {
|
||||
if (isset($value[$column])) {
|
||||
$phName = self::PARAM_PREFIX . count($params);
|
||||
$params[$phName] = $value[$column];
|
||||
$vs[] = $phName;
|
||||
} else {
|
||||
$vs[] = 'NULL';
|
||||
}
|
||||
}
|
||||
$vss[] = '(' . implode(', ', $vs) . ')';
|
||||
}
|
||||
foreach ($columns as $i => $column) {
|
||||
if (strpos($column, '(') === false) {
|
||||
$columns[$i] = $this->db->quoteColumnName($column);
|
||||
}
|
||||
}
|
||||
|
||||
return '(' . implode(', ', $columns) . ") $operator (" . implode(', ', $vss) . ')';
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,12 +201,6 @@ class QueryBuilderTest extends DatabaseTestCase
|
||||
[ ['in', 'id', (new Query())->select('id')->from('users')->where(['active' => 1])], '(`id`) IN (SELECT `id` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ],
|
||||
[ ['not in', 'id', (new Query())->select('id')->from('users')->where(['active' => 1])], '(`id`) NOT IN (SELECT `id` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ],
|
||||
|
||||
// composite in
|
||||
[ ['in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '(`id`, `name`) IN ((:qp0, :qp1), (:qp2, :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar'] ],
|
||||
[ ['not in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '(`id`, `name`) NOT IN ((:qp0, :qp1), (:qp2, :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar'] ],
|
||||
[ ['in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], '(`id`, `name`) IN (SELECT `id`, `name` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ],
|
||||
[ ['not in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], '(`id`, `name`) NOT IN (SELECT `id`, `name` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ],
|
||||
|
||||
// exists
|
||||
[ ['exists', (new Query())->select('id')->from('users')->where(['active' => 1])], 'EXISTS (SELECT `id` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ],
|
||||
[ ['not exists', (new Query())->select('id')->from('users')->where(['active' => 1])], 'NOT EXISTS (SELECT `id` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ],
|
||||
@ -228,6 +222,23 @@ class QueryBuilderTest extends DatabaseTestCase
|
||||
|
||||
];
|
||||
|
||||
switch ($this->driverName) {
|
||||
default:
|
||||
$conditions = array_merge($conditions, [
|
||||
[ ['in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '((`id` = :qp0 AND `name` = :qp1) OR (`id` = :qp2 AND `name` = :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar'] ],
|
||||
[ ['not in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '((`id` != :qp0 OR `name` != :qp1) AND (`id` != :qp2 OR `name` != :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar'] ],
|
||||
]);
|
||||
break;
|
||||
case 'pgsql':
|
||||
$conditions = array_merge($conditions, [
|
||||
[ ['in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '(`id`, `name`) IN ((:qp0, :qp1), (:qp2, :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar'] ],
|
||||
[ ['not in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '(`id`, `name`) NOT IN ((:qp0, :qp1), (:qp2, :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar'] ],
|
||||
[ ['in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], '(`id`, `name`) IN (SELECT `id`, `name` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ],
|
||||
[ ['not in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], '(`id`, `name`) NOT IN (SELECT `id`, `name` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ],
|
||||
]);
|
||||
break;
|
||||
}
|
||||
|
||||
// adjust dbms specific escaping
|
||||
foreach($conditions as $i => $condition) {
|
||||
$conditions[$i][1] = $this->replaceQuotes($condition[1]);
|
||||
@ -444,4 +455,17 @@ class QueryBuilderTest extends DatabaseTestCase
|
||||
$this->assertEquals($expected, $sql);
|
||||
$this->assertEmpty($params);
|
||||
}
|
||||
|
||||
public function testCompositeInCondition()
|
||||
{
|
||||
$condition = [
|
||||
'in',
|
||||
['id', 'name'],
|
||||
[
|
||||
['id' => 1, 'name' => 'foo'],
|
||||
['id' => 2, 'name' => 'bar'],
|
||||
],
|
||||
];
|
||||
(new Query())->from('customer')->where($condition)->all($this->getConnection());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user