diff --git a/tests/framework/db/QueryBuilderTest.php b/tests/framework/db/QueryBuilderTest.php index 748b6a81f28..7556987e907 100644 --- a/tests/framework/db/QueryBuilderTest.php +++ b/tests/framework/db/QueryBuilderTest.php @@ -1244,9 +1244,9 @@ public static function conditionProvider(): array ]; } - public function filterConditionProvider() + public static function filterConditionProvider(): array { - $conditions = [ + return [ // like [['like', 'name', []], '', []], [['not like', 'name', []], '', []], @@ -1284,13 +1284,6 @@ public function filterConditionProvider() [['<>', 'a', ''], '', []], [['!=', 'a', ''], '', []], ]; - - // adjust dbms specific escaping - foreach ($conditions as $i => $condition) { - $conditions[$i][1] = $this->replaceQuotes($condition[1]); - } - - return $conditions; } /** @@ -1306,7 +1299,7 @@ public function testBuildFrom($table, $expected): void $this->assertEquals('FROM ' . $this->replaceQuotes($expected), $sql); } - public function buildFromDataProvider() + public static function buildFromDataProvider(): array { return [ ['test t1', '[[test]] [[t1]]'], @@ -1345,7 +1338,7 @@ public function testBuildFilterCondition($condition, $expected, $expectedParams) $this->assertEquals($expectedParams, $params); } - public function primaryKeysProvider() + public static function primaryKeysProvider(): array { $tableName = 'T_constraints_1'; $name = 'CN_pk'; @@ -1380,7 +1373,7 @@ public function testAddDropPrimaryKey($sql, Closure $builder): void $this->assertSame($this->getConnection(false)->quoteSql($sql), $builder($this->getQueryBuilder(false))); } - public function foreignKeysProvider() + public static function foreignKeysProvider(): array { $tableName = 'T_constraints_3'; $name = 'CN_constraints_3'; @@ -1416,7 +1409,7 @@ public function testAddDropForeignKey($sql, Closure $builder): void $this->assertSame($this->getConnection(false)->quoteSql($sql), $builder($this->getQueryBuilder(false))); } - public function indexesProvider() + public static function indexesProvider(): array { $tableName = 'T_constraints_2'; $name1 = 'CN_constraints_2_single'; @@ -1464,7 +1457,7 @@ public function testCreateDropIndex($sql, Closure $builder): void $this->assertSame($this->getConnection(false)->quoteSql($sql), $builder($this->getQueryBuilder(false))); } - public function uniquesProvider() + public static function uniquesProvider(): array { $tableName1 = 'T_constraints_1'; $name1 = 'CN_unique'; @@ -1501,7 +1494,7 @@ public function testAddDropUnique($sql, Closure $builder): void $this->assertSame($this->getConnection(false)->quoteSql($sql), $builder($this->getQueryBuilder(false))); } - public function checksProvider() + public static function checksProvider(): array { $tableName = 'T_constraints_1'; $name = 'CN_check'; @@ -1530,7 +1523,7 @@ public function testAddDropCheck($sql, Closure $builder): void $this->assertSame($this->getConnection(false)->quoteSql($sql), $builder($this->getQueryBuilder(false))); } - public function defaultValuesProvider() + public static function defaultValuesProvider(): array { $tableName = 'T_constraints_1'; $name = 'CN_default'; @@ -1559,11 +1552,17 @@ public function testAddDropDefaultValue($sql, Closure $builder): void $this->assertSame($this->getConnection(false)->quoteSql($sql), $builder($this->getQueryBuilder(false))); } - public function existsParamsProvider() + public static function existsParamsProvider(): array { return [ - ['exists', $this->replaceQuotes('SELECT [[id]] FROM [[TotalExample]] [[t]] WHERE EXISTS (SELECT [[1]] FROM [[Website]] [[w]])')], - ['not exists', $this->replaceQuotes('SELECT [[id]] FROM [[TotalExample]] [[t]] WHERE NOT EXISTS (SELECT [[1]] FROM [[Website]] [[w]])')], + [ + 'exists', + 'SELECT [[id]] FROM [[TotalExample]] [[t]] WHERE EXISTS (SELECT [[1]] FROM [[Website]] [[w]])', + ], + [ + 'not exists', + 'SELECT [[id]] FROM [[TotalExample]] [[t]] WHERE NOT EXISTS (SELECT [[1]] FROM [[Website]] [[w]])', + ], ]; } @@ -1577,16 +1576,14 @@ public function testBuildWhereExists($cond, $expectedQuerySql): void $expectedQueryParams = []; $subQuery = new Query(); - $subQuery->select('1') - ->from('Website w'); + $subQuery->select('1')->from('Website w'); $query = new Query(); - $query->select('id') - ->from('TotalExample t') - ->where([$cond, $subQuery]); + $query->select('id')->from('TotalExample t')->where([$cond, $subQuery]); list($actualQuerySql, $actualQueryParams) = $this->getQueryBuilder()->build($query); - $this->assertEquals($expectedQuerySql, $actualQuerySql); + + $this->assertEquals($this->replaceQuotes($expectedQuerySql), $actualQuerySql); $this->assertEquals($expectedQueryParams, $actualQueryParams); } @@ -1923,7 +1920,7 @@ public function testGroupBy(): void $this->assertEquals([':to' => 4], $params); } - public function insertProvider() + public static function insertProvider(): array { return [ 'regular-values' => [ @@ -1936,7 +1933,7 @@ public function insertProvider() 'related_id' => null, ], [], - $this->replaceQuotes('INSERT INTO [[customer]] ([[email]], [[name]], [[address]], [[is_active]], [[related_id]]) VALUES (:qp0, :qp1, :qp2, :qp3, :qp4)'), + 'INSERT INTO [[customer]] ([[email]], [[name]], [[address]], [[is_active]], [[related_id]]) VALUES (:qp0, :qp1, :qp2, :qp3, :qp4)', [ ':qp0' => 'test@example.com', ':qp1' => 'silverfire', @@ -1956,6 +1953,7 @@ public function insertProvider() [ ':qp0' => null, ], + false, ], 'carry passed params' => [ 'customer', @@ -1968,7 +1966,7 @@ public function insertProvider() '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))'), + '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', @@ -1999,7 +1997,7 @@ public function insertProvider() '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))'), + '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', @@ -2019,11 +2017,17 @@ public function insertProvider() * @param array $params * @param string $expectedSQL * @param array $expectedParams + * @param bool $replaceQuotes */ - public function testInsert($table, $columns, $params, $expectedSQL, $expectedParams): void + public function testInsert($table, $columns, $params, $expectedSQL, $expectedParams, $replaceQuotes = true): void { $actualParams = $params; $actualSQL = $this->getQueryBuilder()->insert($table, $columns, $actualParams); + + if ($replaceQuotes) { + $expectedSQL = $this->replaceQuotes($expectedSQL); + } + $this->assertSame($expectedSQL, $actualSQL); $this->assertSame($expectedParams, $actualParams); } @@ -2036,7 +2040,7 @@ public function testInitFixtures(): void $this->assertInstanceOf('yii\db\QueryBuilder', $this->getQueryBuilder(true, true)); } - public function upsertProvider() + public static function upsertProvider(): array { return [ 'regular values' => [ @@ -2263,50 +2267,53 @@ public function testUpsert($table, $insertColumns, $updateColumns, $expectedSQL, } } - public function batchInsertProvider() + public static function batchInsertProvider(): array { return [ [ 'customer', ['email', 'name', 'address'], [['test@example.com', 'silverfire', 'Kyiv {{city}}, Ukraine']], - $this->replaceQuotes("INSERT INTO [[customer]] ([[email]], [[name]], [[address]]) VALUES ('test@example.com', 'silverfire', 'Kyiv {{city}}, Ukraine')"), + "INSERT INTO [[customer]] ([[email]], [[name]], [[address]]) VALUES ('test@example.com', 'silverfire', 'Kyiv {{city}}, Ukraine')", ], 'escape-danger-chars' => [ 'customer', ['address'], [["SQL-danger chars are escaped: '); --"]], - 'expected' => $this->replaceQuotes("INSERT INTO [[customer]] ([[address]]) VALUES ('SQL-danger chars are escaped: \'); --')"), + 'expected' => "INSERT INTO [[customer]] ([[address]]) VALUES ('SQL-danger chars are escaped: \'); --')", ], [ 'customer', ['address'], [], '', + false, ], [ 'customer', [], [['no columns passed']], - $this->replaceQuotes("INSERT INTO [[customer]] () VALUES ('no columns passed')"), + "INSERT INTO [[customer]] () VALUES ('no columns passed')", ], 'bool-false, bool2-null' => [ 'type', ['bool_col', 'bool_col2'], [[false, null]], - 'expected' => $this->replaceQuotes('INSERT INTO [[type]] ([[bool_col]], [[bool_col2]]) VALUES (0, NULL)'), + 'expected' => 'INSERT INTO [[type]] ([[bool_col]], [[bool_col2]]) VALUES (0, NULL)', ], [ '{{%type}}', ['{{%type}}.[[float_col]]', '[[time]]'], [[null, new Expression('now()')]], 'INSERT INTO {{%type}} ({{%type}}.[[float_col]], [[time]]) VALUES (NULL, now())', + false, ], 'bool-false, time-now()' => [ '{{%type}}', ['{{%type}}.[[bool_col]]', '[[time]]'], [[false, new Expression('now()')]], 'expected' => 'INSERT INTO {{%type}} ({{%type}}.[[bool_col]], [[time]]) VALUES (0, now())', + false, ], ]; } @@ -2317,17 +2324,23 @@ public function batchInsertProvider() * @param array $columns * @param array $value * @param string $expected + * @param bool $replaceQuotes * @throws Exception */ - public function testBatchInsert($table, $columns, $value, $expected): void + public function testBatchInsert($table, $columns, $value, $expected, $replaceQuotes = true): void { $queryBuilder = $this->getQueryBuilder(); $sql = $queryBuilder->batchInsert($table, $columns, $value); + + if ($replaceQuotes) { + $expected = $this->replaceQuotes($expected); + } + $this->assertEquals($expected, $sql); } - public function updateProvider() + public static function updateProvider(): array { return [ [ @@ -2339,7 +2352,7 @@ public function updateProvider() [ 'id' => 100, ], - $this->replaceQuotes('UPDATE [[customer]] SET [[status]]=:qp0, [[updated_at]]=now() WHERE [[id]]=:qp1'), + 'UPDATE [[customer]] SET [[status]]=:qp0, [[updated_at]]=now() WHERE [[id]]=:qp1', [ ':qp0' => 1, ':qp1' => 100, @@ -2360,11 +2373,11 @@ public function testUpdate($table, $columns, $condition, $expectedSQL, $expected { $actualParams = []; $actualSQL = $this->getQueryBuilder()->update($table, $columns, $condition, $actualParams); - $this->assertSame($expectedSQL, $actualSQL); + $this->assertSame($this->replaceQuotes($expectedSQL), $actualSQL); $this->assertSame($expectedParams, $actualParams); } - public function deleteProvider() + public static function deleteProvider(): array { return [ [ @@ -2373,7 +2386,7 @@ public function deleteProvider() 'is_enabled' => false, 'power' => new Expression('WRONG_POWER()'), ], - $this->replaceQuotes('DELETE FROM [[user]] WHERE ([[is_enabled]]=:qp0) AND ([[power]]=WRONG_POWER())'), + 'DELETE FROM [[user]] WHERE ([[is_enabled]]=:qp0) AND ([[power]]=WRONG_POWER())', [ ':qp0' => false, ], @@ -2392,7 +2405,7 @@ public function testDelete($table, $condition, $expectedSQL, $expectedParams): v { $actualParams = []; $actualSQL = $this->getQueryBuilder()->delete($table, $condition, $actualParams); - $this->assertSame($expectedSQL, $actualSQL); + $this->assertSame($this->replaceQuotes($expectedSQL), $actualSQL); $this->assertSame($expectedParams, $actualParams); } @@ -2426,9 +2439,9 @@ public function testCommentTable(): void $this->assertEquals($this->replaceQuotes($expected), $sql); } - public function likeConditionProvider() + public static function likeConditionProvider(): array { - $conditions = [ + return [ // simple like [['like', 'name', 'foo%'], '[[name]] LIKE :qp0', [':qp0' => '%foo\%%']], [['not like', 'name', 'foo%'], '[[name]] NOT LIKE :qp0', [':qp0' => '%foo\%%']], @@ -2470,22 +2483,6 @@ public function likeConditionProvider() // like with expression as columnName [['like', new Expression('name'), 'teststring'], 'name LIKE :qp0', [':qp0' => '%teststring%']], ]; - - // adjust dbms specific escaping - foreach ($conditions as $i => $condition) { - $conditions[$i][1] = $this->replaceQuotes($condition[1]); - if (!empty($this->likeEscapeCharSql)) { - preg_match_all('/(?PLIKE.+?)( AND| OR|$)/', $conditions[$i][1], $matches, PREG_SET_ORDER); - foreach ($matches as $match) { - $conditions[$i][1] = str_replace($match['condition'], $match['condition'] . $this->likeEscapeCharSql, $conditions[$i][1]); - } - } - foreach ($conditions[$i][2] as $name => $value) { - $conditions[$i][2][$name] = strtr($conditions[$i][2][$name], $this->likeParameterReplacements); - } - } - - return $conditions; } /** @@ -2496,8 +2493,28 @@ public function likeConditionProvider() */ public function testBuildLikeCondition($condition, $expected, $expectedParams): void { + $expected = $this->replaceQuotes($expected); + + if (!empty($this->likeEscapeCharSql)) { + preg_match_all( + '/(?PLIKE.+?)( AND| OR|$)/', + $expected, + $matches, + PREG_SET_ORDER, + ); + + foreach ($matches as $match) { + $expected = str_replace($match['condition'], $match['condition'] . $this->likeEscapeCharSql, $expected); + } + } + + foreach ($expectedParams as $name => $value) { + $expectedParams[$name] = strtr($expectedParams[$name], $this->likeParameterReplacements); + } + $query = (new Query())->where($condition); list($sql, $params) = $this->getQueryBuilder()->build($query); + $this->assertEquals('SELECT *' . (empty($expected) ? '' : ' WHERE ' . $this->replaceQuotes($expected)), $sql); $this->assertEquals($expectedParams, $params); } diff --git a/tests/framework/db/cubrid/QueryBuilderTest.php b/tests/framework/db/cubrid/QueryBuilderTest.php index ee0a30476bb..d3ac4e47949 100644 --- a/tests/framework/db/cubrid/QueryBuilderTest.php +++ b/tests/framework/db/cubrid/QueryBuilderTest.php @@ -8,7 +8,9 @@ namespace yiiunit\framework\db\cubrid; +use Closure; use PDO; +use yii\base\NotSupportedException; /** * @group db @@ -35,16 +37,6 @@ public function columnTypes() return array_merge(parent::columnTypes(), []); } - public function checksProvider(): void - { - $this->markTestSkipped('Adding/dropping check constraints is not supported in CUBRID.'); - } - - public function defaultValuesProvider(): void - { - $this->markTestSkipped('Adding/dropping default constraints is not supported in CUBRID.'); - } - public function testResetSequence(): void { $qb = $this->getQueryBuilder(); @@ -69,7 +61,7 @@ public function testCommentColumn(): void parent::testCommentColumn(); } - public function upsertProvider() + public static function upsertProvider(): array { $concreteData = [ 'regular values' => [ @@ -116,4 +108,32 @@ public function upsertProvider() return $newData; } + + /** + * @dataProvider checksProvider + * @param string $sql + */ + public function testAddDropCheck($sql, Closure $builder): void + { + $this->expectException(NotSupportedException::class); + $this->expectExceptionMessageMatches( + '/^.*::(addCheck|dropCheck) is not supported by CUBRID.*$/', + ); + + parent::testAddDropCheck($sql, $builder); + } + + /** + * @dataProvider defaultValuesProvider + * @param string $sql + */ + public function testAddDropDefaultValue($sql, Closure $builder): void + { + $this->expectException(NotSupportedException::class); + $this->expectExceptionMessageMatches( + '/^cubrid does not support (adding|dropping) default value constraints\.$/', + ); + + parent::testAddDropDefaultValue($sql, $builder); + } } diff --git a/tests/framework/db/mssql/QueryBuilderTest.php b/tests/framework/db/mssql/QueryBuilderTest.php index d07bd816b92..3d626dacd58 100644 --- a/tests/framework/db/mssql/QueryBuilderTest.php +++ b/tests/framework/db/mssql/QueryBuilderTest.php @@ -11,7 +11,6 @@ use yii\db\Expression; use yii\db\Query; use yiiunit\data\base\TraversableObject; -use yiiunit\framework\support\DbHelper; /** * @group db @@ -254,7 +253,7 @@ public function columnTypes() return array_merge(parent::columnTypes(), []); } - public function batchInsertProvider() + public static function batchInsertProvider(): array { $data = parent::batchInsertProvider(); @@ -265,7 +264,7 @@ public function batchInsertProvider() return $data; } - public function insertProvider() + public static function insertProvider(): array { return [ 'regular-values' => [ @@ -278,9 +277,9 @@ public function insertProvider() 'related_id' => null, ], [], - $this->replaceQuotes('SET NOCOUNT ON;DECLARE @temporary_inserted TABLE ([id] int , [email] varchar(128) , [name] varchar(128) NULL, [address] text NULL, [status] int NULL, [profile_id] int NULL);' . + 'SET NOCOUNT ON;DECLARE @temporary_inserted TABLE ([id] int , [email] varchar(128) , [name] varchar(128) NULL, [address] text NULL, [status] int NULL, [profile_id] int NULL);' . 'INSERT INTO [customer] ([email], [name], [address], [is_active], [related_id]) OUTPUT INSERTED.[id],INSERTED.[email],INSERTED.[name],INSERTED.[address],INSERTED.[status],INSERTED.[profile_id] INTO @temporary_inserted VALUES (:qp0, :qp1, :qp2, :qp3, :qp4);' . - 'SELECT * FROM @temporary_inserted'), + 'SELECT * FROM @temporary_inserted', [ ':qp0' => 'test@example.com', ':qp1' => 'silverfire', @@ -302,6 +301,7 @@ public function insertProvider() [ ':qp0' => null, ], + false, ], 'carry passed params' => [ 'customer', @@ -314,9 +314,9 @@ public function insertProvider() 'col' => new Expression('CONCAT(:phFoo, :phBar)', [':phFoo' => 'foo']), ], [':phBar' => 'bar'], - $this->replaceQuotes('SET NOCOUNT ON;DECLARE @temporary_inserted TABLE ([id] int , [email] varchar(128) , [name] varchar(128) NULL, [address] text NULL, [status] int NULL, [profile_id] int NULL);' . + 'SET NOCOUNT ON;DECLARE @temporary_inserted TABLE ([id] int , [email] varchar(128) , [name] varchar(128) NULL, [address] text NULL, [status] int NULL, [profile_id] int NULL);' . 'INSERT INTO [customer] ([email], [name], [address], [is_active], [related_id], [col]) OUTPUT INSERTED.[id],INSERTED.[email],INSERTED.[name],INSERTED.[address],INSERTED.[status],INSERTED.[profile_id] INTO @temporary_inserted VALUES (:qp1, :qp2, :qp3, :qp4, :qp5, CONCAT(:phFoo, :phBar));' . - 'SELECT * FROM @temporary_inserted'), + 'SELECT * FROM @temporary_inserted', [ ':phBar' => 'bar', ':qp1' => 'test@example.com', @@ -347,9 +347,9 @@ public function insertProvider() 'col' => new Expression('CONCAT(:phFoo, :phBar)', [':phFoo' => 'foo']), ]), [':phBar' => 'bar'], - $this->replaceQuotes('SET NOCOUNT ON;DECLARE @temporary_inserted TABLE ([id] int , [email] varchar(128) , [name] varchar(128) NULL, [address] text NULL, [status] int NULL, [profile_id] int NULL);' . + 'SET NOCOUNT ON;DECLARE @temporary_inserted TABLE ([id] int , [email] varchar(128) , [name] varchar(128) NULL, [address] text NULL, [status] int NULL, [profile_id] int NULL);' . 'INSERT INTO [customer] ([email], [name], [address], [is_active], [related_id]) OUTPUT INSERTED.[id],INSERTED.[email],INSERTED.[name],INSERTED.[address],INSERTED.[status],INSERTED.[profile_id] INTO @temporary_inserted 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));' . - 'SELECT * FROM @temporary_inserted'), + 'SELECT * FROM @temporary_inserted', [ ':phBar' => 'bar', ':qp1' => 'test@example.com', @@ -375,7 +375,7 @@ public function testResetSequence(): void $this->assertEquals($expected, $sql); } - public function upsertProvider() + public static function upsertProvider(): array { $concreteData = [ 'regular values' => [ @@ -430,7 +430,7 @@ public function upsertProvider() public static function conditionProvider(): array { - $data = array_merge( + return array_merge( parent::conditionProvider(), [ [ @@ -462,28 +462,26 @@ public static function conditionProvider(): array ], //[ ['in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], 'EXISTS (SELECT 1 FROM (SELECT [[id]], [[name]] FROM [[users]] WHERE [[active]]=:qp0) AS a WHERE a.[[id]] = [[id AND a.]]name[[ = ]]name`)', [':qp0' => 1] ], //[ ['not in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], 'NOT EXISTS (SELECT 1 FROM (SELECT [[id]], [[name]] FROM [[users]] WHERE [[active]]=:qp0) AS a WHERE a.[[id]] = [[id]] AND a.[[name = ]]name`)', [':qp0' => 1] ], + 'composite in' => [ + [ + 'in', + ['id', 'name'], + [['id' => 1, 'name' => 'oy']], + ], + '(([id] = :qp0 AND [name] = :qp1))', + [':qp0' => 1, ':qp1' => 'oy'], + ], + 'composite in using array objects' => [ + [ + 'in', + new TraversableObject(['id', 'name']), + new TraversableObject([['id' => 1, 'name' => 'oy'], ['id' => 2, 'name' => 'yo']]) + ], + '(([id] = :qp0 AND [name] = :qp1) OR ([id] = :qp2 AND [name] = :qp3))', + [':qp0' => 1, ':qp1' => 'oy', ':qp2' => 2, ':qp3' => 'yo'], + ], ], ); - $data['composite in'] = [ - ['in', ['id', 'name'], [['id' => 1, 'name' => 'oy']]], - '(([id] = :qp0 AND [name] = :qp1))', - [':qp0' => 1, ':qp1' => 'oy'], - ]; - $data['composite in using array objects'] = [ - ['in', new TraversableObject(['id', 'name']), new TraversableObject([ - ['id' => 1, 'name' => 'oy'], - ['id' => 2, 'name' => 'yo'], - ])], - '(([id] = :qp0 AND [name] = :qp1) OR ([id] = :qp2 AND [name] = :qp3))', - [':qp0' => 1, ':qp1' => 'oy', ':qp2' => 2, ':qp3' => 'yo'], - ]; - - // adjust dbms specific escaping - foreach ($data as $i => $condition) { - $data[$i][1] = DbHelper::replaceQuotes($condition[1], 'sqlsrv'); - } - - return $data; } public function testAlterColumn(): void @@ -845,7 +843,7 @@ public function testDropColumnOnDb(): void $this->assertEquals(null, $schema->getColumn('bar')); } - public function buildFromDataProvider() + public static function buildFromDataProvider(): array { $data = parent::buildFromDataProvider(); $data[] = ['[test]', '[[test]]']; diff --git a/tests/framework/db/mysql/QueryBuilderTest.php b/tests/framework/db/mysql/QueryBuilderTest.php index 73352a808ed..92c22376ae8 100644 --- a/tests/framework/db/mysql/QueryBuilderTest.php +++ b/tests/framework/db/mysql/QueryBuilderTest.php @@ -8,13 +8,14 @@ namespace yiiunit\framework\db\mysql; +use Closure; use PDO; use yii\base\DynamicModel; +use yii\base\NotSupportedException; use yii\db\Expression; use yii\db\JsonExpression; use yii\db\Query; use yii\db\Schema; -use yiiunit\framework\support\DbHelper; /** * @group db @@ -166,7 +167,7 @@ public function columnTimeTypes() return $columns; } - public function primaryKeysProvider() + public static function primaryKeysProvider(): array { $result = parent::primaryKeysProvider(); $result['drop'][0] = 'ALTER TABLE {{T_constraints_1}} DROP PRIMARY KEY'; @@ -175,14 +176,14 @@ public function primaryKeysProvider() return $result; } - public function foreignKeysProvider() + public static function foreignKeysProvider(): array { $result = parent::foreignKeysProvider(); $result['drop'][0] = 'ALTER TABLE {{T_constraints_3}} DROP FOREIGN KEY [[CN_constraints_3]]'; return $result; } - public function indexesProvider() + public static function indexesProvider(): array { $result = parent::indexesProvider(); $result['create'][0] = 'ALTER TABLE {{T_constraints_2}} ADD INDEX [[CN_constraints_2_single]] ([[C_index_1]])'; @@ -192,18 +193,13 @@ public function indexesProvider() return $result; } - public function uniquesProvider() + public static function uniquesProvider(): array { $result = parent::uniquesProvider(); $result['drop'][0] = 'DROP INDEX [[CN_unique]] ON {{T_constraints_1}}'; return $result; } - public function defaultValuesProvider(): void - { - $this->markTestSkipped('Adding/dropping default constraints is not supported in MySQL.'); - } - public function testResetSequence(): void { $qb = $this->getQueryBuilder(); @@ -217,7 +213,7 @@ public function testResetSequence(): void $this->assertEquals($expected, $sql); } - public function upsertProvider() + public static function upsertProvider(): array { $concreteData = [ 'regular values' => [ @@ -266,7 +262,7 @@ public function upsertProvider() public static function conditionProvider(): array { - $data = array_merge( + return array_merge( parent::conditionProvider(), [ [ @@ -365,16 +361,9 @@ public static function conditionProvider(): array ] ], ); - - // adjust dbms specific escaping - foreach ($data as $i => $condition) { - $data[$i][1] = DbHelper::replaceQuotes($condition[1], 'mysql'); - } - - return $data; } - public function updateProvider() + public static function updateProvider(): array { $items = parent::updateProvider(); @@ -386,7 +375,7 @@ public function updateProvider() [ 'id' => 1, ], - $this->replaceQuotes('UPDATE [[profile]] SET [[description]]=:qp0 WHERE [[id]]=:qp1'), + 'UPDATE [[profile]] SET [[description]]=:qp0 WHERE [[id]]=:qp1', [ ':qp0' => '{"abc":"def","0":123,"1":null}', ':qp1' => 1, @@ -461,4 +450,18 @@ public function testDefaultValues(): void $sql = $command->insert('negative_default_values', [])->getRawSql(); $this->assertEquals('INSERT INTO `negative_default_values` (`tinyint_col`) VALUES (DEFAULT)', $sql); } + + /** + * @dataProvider defaultValuesProvider + * @param string $sql + */ + public function testAddDropDefaultValue($sql, Closure $builder): void + { + $this->expectException(NotSupportedException::class); + $this->expectExceptionMessageMatches( + '/^mysql does not support (adding|dropping) default value constraints\.$/', + ); + + parent::testAddDropDefaultValue($sql, $builder); + } } diff --git a/tests/framework/db/oci/QueryBuilderTest.php b/tests/framework/db/oci/QueryBuilderTest.php index c811a064522..ff51a6bbd6f 100644 --- a/tests/framework/db/oci/QueryBuilderTest.php +++ b/tests/framework/db/oci/QueryBuilderTest.php @@ -17,7 +17,6 @@ use yii\db\Query; use yii\helpers\ArrayHelper; use yiiunit\data\base\TraversableObject; -use yiiunit\framework\support\DbHelper; /** * @group db @@ -49,7 +48,7 @@ public function columnTypes() ]); } - public function foreignKeysProvider() + public static function foreignKeysProvider(): array { $tableName = 'T_constraints_3'; $name = 'CN_constraints_3'; @@ -76,22 +75,13 @@ function (QueryBuilder $qb) use ($tableName, $name, $pkTableName) { ]; } - public function indexesProvider() + public static function indexesProvider(): array { $result = parent::indexesProvider(); $result['drop'][0] = 'DROP INDEX [[CN_constraints_2_single]]'; return $result; } - /** - * @dataProvider defaultValuesProvider - * @param string $sql - */ - public function testAddDropDefaultValue($sql, Closure $builder): void - { - $this->markTestSkipped('Adding/dropping default constraints is not supported in Oracle.'); - } - public function testCommentColumn(): void { $qb = $this->getQueryBuilder(); @@ -133,25 +123,9 @@ public function testExecuteResetSequence(): void $this->assertEquals(4, $result); } - public function likeConditionProvider() - { - /* - * Different pdo_oci8 versions may or may not implement PDO::quote(), so - * yii\db\Schema::quoteValue() may or may not quote \. - */ - try { - $encodedBackslash = substr($this->getDb()->quoteValue('\\'), 1, -1); - $this->likeParameterReplacements[$encodedBackslash] = '\\'; - } catch (Exception $e) { - $this->markTestSkipped('Could not execute Connection::quoteValue() method: ' . $e->getMessage()); - } - - return parent::likeConditionProvider(); - } - public static function conditionProvider(): array { - $data = array_merge( + return array_merge( parent::conditionProvider(), [ [ @@ -201,13 +175,6 @@ public static function conditionProvider(): array ], ], ); - - // adjust dbms specific escaping - foreach ($data as $i => $condition) { - $data[$i][1] = DbHelper::replaceQuotes($condition[1], 'oci'); - } - - return $data; } public function conditionProvidertmp() @@ -262,7 +229,7 @@ protected function generateSprintfSeries($pattern, $from, $to) return $items; } - public function upsertProvider() + public static function upsertProvider(): array { $concreteData = [ 'regular values' => [ @@ -322,7 +289,7 @@ public function upsertProvider() return $newData; } - public function batchInsertProvider() + public static function batchInsertProvider(): array { $data = parent::batchInsertProvider(); @@ -368,17 +335,42 @@ public function testInitFixtures(): void */ public function testUpsert($table, $insertColumns, $updateColumns, $expectedSQL, $expectedParams): void { - $actualParams = []; - $actualSQL = $this->getQueryBuilder(true, $this->driverName === 'sqlite')->upsert($table, $insertColumns, $updateColumns, $actualParams); - if (is_string($expectedSQL)) { - $this->assertEqualsWithoutLE($expectedSQL, $actualSQL); - } else { - $this->assertStringContainsString($actualSQL, $expectedSQL); - } - if (ArrayHelper::isAssociative($expectedParams)) { - $this->assertSame($expectedParams, $actualParams); - } else { - $this->assertIsOneOf($actualParams, $expectedParams); + parent::testUpsert($table, $insertColumns, $updateColumns, $expectedSQL, $expectedParams); + } + + /** + * @dataProvider defaultValuesProvider + * @param string $sql + */ + public function testAddDropDefaultValue($sql, Closure $builder): void + { + $this->expectException(NotSupportedException::class); + $this->expectExceptionMessageMatches( + '/^oci does not support (adding|dropping) default value constraints\.$/', + ); + + parent::testAddDropDefaultValue($sql, $builder); + } + + /** + * @dataProvider likeConditionProvider + * @param array $condition + * @param string $expected + * @param array $expectedParams + */ + public function testBuildLikeCondition($condition, $expected, $expectedParams): void + { + /** + * Different pdo_oci8 versions may or may not implement PDO::quote(), so + * yii\db\Schema::quoteValue() may or may not quote \. + */ + try { + $encodedBackslash = substr($this->getDb()->quoteValue('\\\\'), 1, -1); + $this->likeParameterReplacements[$encodedBackslash] = '\\'; + } catch (Exception $e) { + $this->markTestSkipped('Could not execute Connection::quoteValue() method: ' . $e->getMessage()); } + + parent::testBuildLikeCondition($condition, $expected, $expectedParams); } } diff --git a/tests/framework/db/pgsql/QueryBuilderTest.php b/tests/framework/db/pgsql/QueryBuilderTest.php index d4296563209..01bfbe190ca 100644 --- a/tests/framework/db/pgsql/QueryBuilderTest.php +++ b/tests/framework/db/pgsql/QueryBuilderTest.php @@ -8,14 +8,15 @@ namespace yiiunit\framework\db\pgsql; +use Closure; use yii\base\DynamicModel; +use yii\base\NotSupportedException; use yii\db\ArrayExpression; use yii\db\Expression; use yii\db\JsonExpression; use yii\db\Query; use yii\db\Schema; use yiiunit\data\base\TraversableObject; -use yiiunit\framework\support\DbHelper; /** * @group db @@ -70,7 +71,7 @@ public function columnTypes() public static function conditionProvider(): array { - $data = array_merge( + return array_merge( parent::conditionProvider(), [ [ @@ -202,13 +203,6 @@ public static function conditionProvider(): array [['&&', 'id', new ArrayExpression([1])], '"id" && ARRAY[:qp0]', [':qp0' => 1]], ], ); - - // adjust dbms specific escaping - foreach ($data as $i => $condition) { - $data[$i][1] = DbHelper::replaceQuotes($condition[1], 'pgsql'); - } - - return $data; } public function testAlterColumn(): void @@ -260,18 +254,13 @@ public function testAlterColumn(): void $this->assertEquals($expected, $sql); } - public function indexesProvider() + public static function indexesProvider(): array { $result = parent::indexesProvider(); $result['drop'][0] = 'DROP INDEX [[CN_constraints_2_single]]'; return $result; } - public function defaultValuesProvider(): void - { - $this->markTestSkipped('Adding/dropping default constraints is not supported in PostgreSQL.'); - } - public function testCommentColumn(): void { $qb = $this->getQueryBuilder(); @@ -298,7 +287,7 @@ public function testCommentTable(): void $this->assertEquals($this->replaceQuotes($expected), $sql); } - public function batchInsertProvider() + public static function batchInsertProvider(): array { $data = parent::batchInsertProvider(); @@ -343,7 +332,7 @@ public function testResetSequencePostgres12(): void $this->assertEquals($expected, $sql); } - public function upsertProvider() + public static function upsertProvider(): array { $concreteData = [ 'regular values' => [ @@ -443,7 +432,7 @@ public function upsertProvider() return $newData; } - public function updateProvider() + public static function updateProvider(): array { $items = parent::updateProvider(); @@ -455,7 +444,7 @@ public function updateProvider() [ 'id' => 1, ], - $this->replaceQuotes('UPDATE [[profile]] SET [[description]]=:qp0 WHERE [[id]]=:qp1'), + 'UPDATE [[profile]] SET [[description]]=:qp0 WHERE [[id]]=:qp1', [ ':qp0' => '{"abc":"def","0":123,"1":null}', ':qp1' => 1, @@ -489,4 +478,18 @@ public function testDropIndex(): void $sql = $qb->dropIndex('index', '{{%schema.table}}'); $this->assertEquals($expected, $sql); } + + /** + * @dataProvider defaultValuesProvider + * @param string $sql + */ + public function testAddDropDefaultValue($sql, Closure $builder): void + { + $this->expectException(NotSupportedException::class); + $this->expectExceptionMessageMatches( + '/^pgsql does not support (adding|dropping) default value constraints\.$/', + ); + + parent::testAddDropDefaultValue($sql, $builder); + } } diff --git a/tests/framework/db/sqlite/QueryBuilderTest.php b/tests/framework/db/sqlite/QueryBuilderTest.php index 5b12b4f0f96..c42c9be130f 100644 --- a/tests/framework/db/sqlite/QueryBuilderTest.php +++ b/tests/framework/db/sqlite/QueryBuilderTest.php @@ -8,13 +8,14 @@ namespace yiiunit\framework\db\sqlite; +use Closure; use PDO; +use yii\base\NotSupportedException; use yii\db\Expression; use yii\db\Query; use yii\db\Schema; use yii\db\sqlite\QueryBuilder; use yiiunit\data\base\TraversableObject; -use yiiunit\framework\support\DbHelper; /** * @group db @@ -39,7 +40,7 @@ public function columnTypes() public static function conditionProvider(): array { - $data = array_merge( + return array_merge( parent::conditionProvider(), [ [ @@ -71,46 +72,29 @@ public static function conditionProvider(): array ], //[ ['in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], 'EXISTS (SELECT 1 FROM (SELECT [[id]], [[name]] FROM [[users]] WHERE [[active]]=:qp0) AS a WHERE a.[[id]] = [[id AND a.]]name[[ = ]]name`)', [':qp0' => 1] ], //[ ['not in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], 'NOT EXISTS (SELECT 1 FROM (SELECT [[id]], [[name]] FROM [[users]] WHERE [[active]]=:qp0) AS a WHERE a.[[id]] = [[id]] AND a.[[name = ]]name`)', [':qp0' => 1] ], + 'composite in' => [ + [ + 'in', + ['id', 'name'], + [['id' => 1, 'name' => 'oy']], + ], + '(([[id]] = :qp0 AND [[name]] = :qp1))', + [':qp0' => 1, ':qp1' => 'oy'], + ], + 'composite in using array objects' => [ + [ + 'in', + new TraversableObject(['id', 'name']), + new TraversableObject([['id' => 1, 'name' => 'oy'], ['id' => 2, 'name' => 'yo']]), + ], + '(([[id]] = :qp0 AND [[name]] = :qp1) OR ([[id]] = :qp2 AND [[name]] = :qp3))', + [':qp0' => 1, ':qp1' => 'oy', ':qp2' => 2, ':qp3' => 'yo'], + ], ], ); - $data['composite in'] = [ - [ - 'in', - ['id', 'name'], - [['id' => 1, 'name' => 'oy']], - ], - '(([[id]] = :qp0 AND [[name]] = :qp1))', - [':qp0' => 1, ':qp1' => 'oy'], - ]; - $data['composite in using array objects'] = [ - [ - 'in', - new TraversableObject(['id', 'name']), - new TraversableObject([['id' => 1, 'name' => 'oy'], ['id' => 2, 'name' => 'yo']]), - ], - '(([[id]] = :qp0 AND [[name]] = :qp1) OR ([[id]] = :qp2 AND [[name]] = :qp3))', - [':qp0' => 1, ':qp1' => 'oy', ':qp2' => 2, ':qp3' => 'yo'], - ]; - - // adjust dbms specific escaping - foreach ($data as $i => $condition) { - $data[$i][1] = DbHelper::replaceQuotes($condition[1], 'sqlite'); - } - - return $data; - } - - public function primaryKeysProvider(): void - { - $this->markTestSkipped('Adding/dropping primary keys is not supported in SQLite.'); } - public function foreignKeysProvider(): void - { - $this->markTestSkipped('Adding/dropping foreign keys is not supported in SQLite.'); - } - - public function indexesProvider() + public static function indexesProvider(): array { $result = parent::indexesProvider(); $result['drop'][0] = 'DROP INDEX [[CN_constraints_2_single]]'; @@ -129,21 +113,6 @@ function (QueryBuilder $qb) use ($tableName, $indexName, $schemaName) { return $result; } - public function uniquesProvider(): void - { - $this->markTestSkipped('Adding/dropping unique constraints is not supported in SQLite.'); - } - - public function checksProvider(): void - { - $this->markTestSkipped('Adding/dropping check constraints is not supported in SQLite.'); - } - - public function defaultValuesProvider(): void - { - $this->markTestSkipped('Adding/dropping default constraints is not supported in SQLite.'); - } - public function testCommentColumn(): void { $this->markTestSkipped('Comments are not supported in SQLite'); @@ -154,7 +123,7 @@ public function testCommentTable(): void $this->markTestSkipped('Comments are not supported in SQLite'); } - public function batchInsertProvider() + public static function batchInsertProvider(): array { $data = parent::batchInsertProvider(); $data['escape-danger-chars']['expected'] = "INSERT INTO `customer` (`address`) VALUES ('SQL-danger chars are escaped: ''); --')"; @@ -248,7 +217,7 @@ public function testResetSequence(): void $this->assertEquals($expected, $sql); } - public function upsertProvider() + public static function upsertProvider(): array { $concreteData = [ 'regular values' => [ @@ -294,4 +263,74 @@ public function upsertProvider() } return $newData; } + + /** + * @dataProvider primaryKeysProvider + * @param string $sql + */ + public function testAddDropPrimaryKey($sql, Closure $builder): void + { + $this->expectException(NotSupportedException::class); + $this->expectExceptionMessageMatches( + '/^.*::(addPrimaryKey|dropPrimaryKey) is not supported by SQLite\.$/', + ); + + parent::testAddDropPrimaryKey($sql, $builder); + } + + /** + * @dataProvider foreignKeysProvider + * @param string $sql + */ + public function testAddDropForeignKey($sql, Closure $builder): void + { + $this->expectException(NotSupportedException::class); + $this->expectExceptionMessageMatches( + '/^.*::(addForeignKey|dropForeignKey) is not supported by SQLite\.$/', + ); + + parent::testAddDropForeignKey($sql, $builder); + } + + /** + * @dataProvider uniquesProvider + * @param string $sql + */ + public function testAddDropUnique($sql, Closure $builder): void + { + $this->expectException(NotSupportedException::class); + $this->expectExceptionMessageMatches( + '/^.*::(addUnique|dropUnique) is not supported by SQLite\.$/', + ); + + parent::testAddDropUnique($sql, $builder); + } + + /** + * @dataProvider checksProvider + * @param string $sql + */ + public function testAddDropCheck($sql, Closure $builder): void + { + $this->expectException(NotSupportedException::class); + $this->expectExceptionMessageMatches( + '/^.*::(addCheck|dropCheck) is not supported by SQLite\.$/', + ); + + parent::testAddDropCheck($sql, $builder); + } + + /** + * @dataProvider defaultValuesProvider + * @param string $sql + */ + public function testAddDropDefaultValue($sql, Closure $builder): void + { + $this->expectException(NotSupportedException::class); + $this->expectExceptionMessageMatches( + '/^.*::(addDefaultValue|dropDefaultValue) is not supported by SQLite\.$/', + ); + + parent::testAddDropDefaultValue($sql, $builder); + } } diff --git a/tests/framework/support/DbHelper.php b/tests/framework/support/DbHelper.php deleted file mode 100644 index ac06b13753c..00000000000 --- a/tests/framework/support/DbHelper.php +++ /dev/null @@ -1,43 +0,0 @@ -