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)
|
protected function buildCompositeInCondition($operator, $columns, $values, &$params)
|
||||||
{
|
{
|
||||||
|
$quotedColumns = [];
|
||||||
|
foreach ($columns as $i => $column) {
|
||||||
|
$quotedColumns[$i] = strpos($column, '(') === false ? $this->db->quoteColumnName($column) : $column;
|
||||||
|
}
|
||||||
$vss = [];
|
$vss = [];
|
||||||
foreach ($values as $value) {
|
foreach ($values as $value) {
|
||||||
$vs = [];
|
$vs = [];
|
||||||
foreach ($columns as $column) {
|
foreach ($columns as $i => $column) {
|
||||||
if (isset($value[$column])) {
|
if (isset($value[$column])) {
|
||||||
$phName = self::PARAM_PREFIX . count($params);
|
$phName = self::PARAM_PREFIX . count($params);
|
||||||
$params[$phName] = $value[$column];
|
$params[$phName] = $value[$column];
|
||||||
$vs[] = $phName;
|
$vs[] = $quotedColumns[$i] . ($operator === 'IN' ? ' = ' : ' != ') . $phName;
|
||||||
} else {
|
} else {
|
||||||
$vs[] = 'NULL';
|
$vs[] = $quotedColumns[$i] . ($operator === 'IN' ? ' IS' : ' IS NOT') . ' NULL';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$vss[] = '(' . implode(', ', $vs) . ')';
|
$vss[] = '(' . implode($operator === 'IN' ? ' AND ' : ' OR ', $vs) . ')';
|
||||||
}
|
|
||||||
foreach ($columns as $i => $column) {
|
|
||||||
if (strpos($column, '(') === false) {
|
|
||||||
$columns[$i] = $this->db->quoteColumnName($column);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
return 'INSERT INTO ' . $schema->quoteTableName($table)
|
||||||
. ' (' . implode(', ', $columns) . ') VALUES ' . implode(', ', $values);
|
. ' (' . 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] ],
|
[ ['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] ],
|
[ ['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
|
||||||
[ ['exists', (new Query())->select('id')->from('users')->where(['active' => 1])], 'EXISTS (SELECT `id` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ],
|
[ ['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] ],
|
[ ['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
|
// adjust dbms specific escaping
|
||||||
foreach($conditions as $i => $condition) {
|
foreach($conditions as $i => $condition) {
|
||||||
$conditions[$i][1] = $this->replaceQuotes($condition[1]);
|
$conditions[$i][1] = $this->replaceQuotes($condition[1]);
|
||||||
@ -444,4 +455,17 @@ class QueryBuilderTest extends DatabaseTestCase
|
|||||||
$this->assertEquals($expected, $sql);
|
$this->assertEquals($expected, $sql);
|
||||||
$this->assertEmpty($params);
|
$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