From b7d5393a08e5eb66cfcb917c278eea61bd483de6 Mon Sep 17 00:00:00 2001 From: Sergey Makinen Date: Fri, 24 Nov 2017 11:19:34 +0300 Subject: [PATCH] Fixes #15194: Fixed `yii\db\QueryBuilder::insert()` to preserve passed params when building a `INSERT INTO ... SELECT` query for MSSQL, PostgreSQL and SQLite --- framework/CHANGELOG.md | 1 + framework/db/QueryBuilder.php | 2 +- tests/framework/db/QueryBuilderTest.php | 59 ++++++++++++++++++++++++- 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 310bd57f1c..c97c9438c1 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -6,6 +6,7 @@ Yii Framework 2 Change Log - Bug #14276: Fixed I18N format with dotted parameters (developeruz) - Bug #14604: Fixed `yii\validators\CompareValidator` `compareAttribute` does not work if `compareAttribute` form ID has been changed (mikk150) +- Bug #15194: Fixed `yii\db\QueryBuilder::insert()` to preserve passed params when building a `INSERT INTO ... SELECT` query for MSSQL, PostgreSQL and SQLite (sergeymakinen) - Enh #15135: Automatic completion for help in bash and zsh (Valkeru) - Enh #14662: Added support for custom `Content-Type` specification to `yii\web\JsonResponseFormatter` (Kolyunya) - Enh #14568: Refactored migration templates to use `safeUp()` and `safeDown()` methods (Kolyunya) diff --git a/framework/db/QueryBuilder.php b/framework/db/QueryBuilder.php index 46b8a12e73..8f69c47750 100644 --- a/framework/db/QueryBuilder.php +++ b/framework/db/QueryBuilder.php @@ -179,7 +179,7 @@ class QueryBuilder extends \yii\base\BaseObject $placeholders = []; $values = ' DEFAULT VALUES'; if ($columns instanceof \yii\db\Query) { - list($names, $values, $params) = $this->prepareInsertSelectSubQuery($columns, $schema); + list($names, $values, $params) = $this->prepareInsertSelectSubQuery($columns, $schema, $params); } else { foreach ($columns as $name => $value) { $names[] = $schema->quoteColumnName($name); diff --git a/tests/framework/db/QueryBuilderTest.php b/tests/framework/db/QueryBuilderTest.php index a66d0494a2..eb2d02058f 100644 --- a/tests/framework/db/QueryBuilderTest.php +++ b/tests/framework/db/QueryBuilderTest.php @@ -1777,6 +1777,7 @@ abstract class QueryBuilderTest extends DatabaseTestCase 'is_active' => false, 'related_id' => null, ], + [], $this->replaceQuotes('INSERT INTO [[customer]] ([[email]], [[name]], [[address]], [[is_active]], [[related_id]]) VALUES (:qp0, :qp1, :qp2, :qp3, :qp4)'), [ ':qp0' => 'test@example.com', @@ -1792,11 +1793,64 @@ abstract class QueryBuilderTest extends DatabaseTestCase '{{%type}}.[[related_id]]' => null, '[[time]]' => new Expression('now()'), ], + [], 'INSERT INTO {{%type}} ({{%type}}.[[related_id]], [[time]]) VALUES (:qp0, now())', [ ':qp0' => null, ], ], + 'carry passed params' => [ + 'customer', + [ + 'email' => 'test@example.com', + 'name' => 'sergeymakinen', + 'address' => '{{city}}', + 'is_active' => false, + 'related_id' => null, + 'col' => new Expression('CONCAT(:phFoo, :phBar)', [':phFoo' => 'foo']), + ], + [':phBar' => 'bar'], + $this->replaceQuotes('INSERT INTO [[customer]] ([[email]], [[name]], [[address]], [[is_active]], [[related_id]], [[col]]) VALUES (:qp1, :qp2, :qp3, :qp4, :qp5, CONCAT(:phFoo, :phBar))'), + [ + ':phBar' => 'bar', + ':qp1' => 'test@example.com', + ':qp2' => 'sergeymakinen', + ':qp3' => '{{city}}', + ':qp4' => false, + ':qp5' => null, + ':phFoo' => 'foo', + ], + ], + 'carry passed params (query)' => [ + 'customer', + (new Query()) + ->select([ + 'email', + 'name', + 'address', + 'is_active', + 'related_id', + ]) + ->from('customer') + ->where([ + 'email' => 'test@example.com', + 'name' => 'sergeymakinen', + 'address' => '{{city}}', + 'is_active' => false, + 'related_id' => null, + 'col' => new Expression('CONCAT(:phFoo, :phBar)', [':phFoo' => 'foo']), + ]), + [':phBar' => 'bar'], + $this->replaceQuotes('INSERT INTO [[customer]] ([[email]], [[name]], [[address]], [[is_active]], [[related_id]]) SELECT [[email]], [[name]], [[address]], [[is_active]], [[related_id]] FROM [[customer]] WHERE ([[email]]=:qp1) AND ([[name]]=:qp2) AND ([[address]]=:qp3) AND ([[is_active]]=:qp4) AND ([[related_id]] IS NULL) AND ([[col]]=CONCAT(:phFoo, :phBar))'), + [ + ':phBar' => 'bar', + ':qp1' => 'test@example.com', + ':qp2' => 'sergeymakinen', + ':qp3' => '{{city}}', + ':qp4' => false, + ':phFoo' => 'foo', + ], + ], ]; } @@ -1804,12 +1858,13 @@ abstract class QueryBuilderTest extends DatabaseTestCase * @dataProvider insertProvider * @param string $table * @param array $columns + * @param array $params * @param string $expectedSQL * @param array $expectedParams */ - public function testInsert($table, $columns, $expectedSQL, $expectedParams) + public function testInsert($table, $columns, $params, $expectedSQL, $expectedParams) { - $actualParams = []; + $actualParams = $params; $actualSQL = $this->getQueryBuilder()->insert($table, $columns, $actualParams); $this->assertSame($expectedSQL, $actualSQL); $this->assertSame($expectedParams, $actualParams);