Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions tests/framework/db/mssql/QueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -855,4 +855,159 @@ public static function buildFromDataProvider(): array

return $data;
}

public function testRenameTable(): void
{
$qb = $this->getQueryBuilder();
$sql = $qb->renameTable('old_table', 'new_table');
$this->assertSame('sp_rename [old_table], [new_table]', $sql);
}

public function testRenameColumn(): void
{
$qb = $this->getQueryBuilder();
$sql = $qb->renameColumn('test_table', 'old_col', 'new_col');
$this->assertSame("sp_rename '[test_table].[old_col]', [new_col], 'COLUMN'", $sql);
}

public function testSelectExists(): void
{
$qb = $this->getQueryBuilder();
$sql = $qb->selectExists('SELECT 1 FROM [customer]');
$this->assertSame('SELECT CASE WHEN EXISTS(SELECT 1 FROM [customer]) THEN 1 ELSE 0 END', $sql);
}

public function testCheckIntegrityEnableForTable(): void
{
$qb = $this->getQueryBuilder(true, true);
$sql = $qb->checkIntegrity(true, '', 'customer');
$this->assertSame('ALTER TABLE [dbo].[customer] CHECK CONSTRAINT ALL; ', $sql);
}

public function testCheckIntegrityDisableForTable(): void
{
$qb = $this->getQueryBuilder(true, true);
$sql = $qb->checkIntegrity(false, '', 'customer');
$this->assertSame('ALTER TABLE [dbo].[customer] NOCHECK CONSTRAINT ALL; ', $sql);
}

public function testCheckIntegrityFiltersOutViews(): void
{
$qb = $this->getQueryBuilder(true, true);
$sql = $qb->checkIntegrity(true);
$this->assertStringContainsString('CHECK CONSTRAINT ALL', $sql);
$this->assertStringContainsString('[dbo].[customer]', $sql);
$this->assertStringNotContainsString('animal_view', $sql);
}

public function testResetSequenceThrowsExceptionForNonExistentTable(): void
{
$qb = $this->getQueryBuilder(true, true);
$this->expectException('yii\base\InvalidArgumentException');
$this->expectExceptionMessage('Table not found: non_existent_table');
$qb->resetSequence('non_existent_table');
}

public function testResetSequenceThrowsExceptionForTableWithoutSequence(): void
{
$qb = $this->getQueryBuilder(true, true);
$this->expectException('yii\base\InvalidArgumentException');
$this->expectExceptionMessage("There is not sequence associated with table 'order_item'.");
$qb->resetSequence('order_item');
}

/**
* @dataProvider oldBuildOrderByAndLimitProvider
*/
public function testOldBuildOrderByAndLimit(string $sql, array $orderBy, $limit, $offset, string $expected): void
{
$qb = $this->getQueryBuilder();
$method = new \ReflectionMethod($qb, 'oldBuildOrderByAndLimit');
if (PHP_VERSION_ID < 80100) {
$method->setAccessible(true);
}
$this->assertSame($expected, $method->invoke($qb, $sql, $orderBy, $limit, $offset));
}

public static function oldBuildOrderByAndLimitProvider(): array
{
return [
'limit and offset' => [
'SELECT [id] FROM [example]',
[],
10,
5,
'SELECT TOP 10 * FROM (SELECT rowNum = ROW_NUMBER() over (ORDER BY (SELECT NULL)), [id] FROM [example]) sub WHERE rowNum > 5',
],
'limit only' => [
'SELECT [id] FROM [example]',
[],
10,
null,
'SELECT TOP 10 * FROM (SELECT rowNum = ROW_NUMBER() over (ORDER BY (SELECT NULL)), [id] FROM [example]) sub',
],
'offset only' => [
'SELECT [id] FROM [example]',
[],
null,
5,
'SELECT * FROM (SELECT rowNum = ROW_NUMBER() over (ORDER BY (SELECT NULL)), [id] FROM [example]) sub WHERE rowNum > 5',
],
'with order by' => [
'SELECT [id] FROM [example]',
['id' => SORT_ASC],
10,
5,
'SELECT TOP 10 * FROM (SELECT rowNum = ROW_NUMBER() over (ORDER BY [id]), [id] FROM [example]) sub WHERE rowNum > 5',
],
'expression limit' => [
'SELECT [id] FROM [example]',
[],
new Expression('5+5'),
null,
'SELECT TOP (5+5) * FROM (SELECT rowNum = ROW_NUMBER() over (ORDER BY (SELECT NULL)), [id] FROM [example]) sub',
],
'distinct with limit and offset' => [
'SELECT DISTINCT [id] FROM [example]',
[],
10,
5,
'SELECT TOP 10 * FROM (SELECT DISTINCT rowNum = ROW_NUMBER() over (ORDER BY (SELECT NULL)), [id] FROM [example]) sub WHERE rowNum > 5',
],
];
}

public function testUpdateWithVarbinaryData(): void
{
$qb = $this->getQueryBuilder(true, true);
$params = [];
$sql = $qb->update('T_upsert_varbinary', ['blob_col' => 'test data'], ['id' => 1], $params);
$this->assertStringContainsString('CONVERT(VARBINARY(MAX), 0x' . bin2hex('test data') . ')', $sql);
$this->assertSame([':qp0' => 1], $params);
}

public function testCompositeInWithSubqueryThrowsException(): void
{
$qb = $this->getQueryBuilder();
$params = [];
$condition = ['in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')];
$this->expectException('yii\base\NotSupportedException');
$qb->buildCondition($condition, $params);
}

public function testAddCommentOnNonExistentTableThrowsException(): void
{
$qb = $this->getQueryBuilder(true, true);
$this->expectException('yii\base\InvalidArgumentException');
$this->expectExceptionMessage('Table not found: non_existent_table');
$qb->addCommentOnColumn('non_existent_table', 'col', 'comment');
}

public function testDropCommentFromNonExistentTableThrowsException(): void
{
$qb = $this->getQueryBuilder(true, true);
$this->expectException('yii\base\InvalidArgumentException');
$this->expectExceptionMessage('Table not found: non_existent_table');
$qb->dropCommentFromColumn('non_existent_table', 'col');
}
}
175 changes: 175 additions & 0 deletions tests/framework/db/mssql/SchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
namespace yiiunit\framework\db\mssql;

use yii\base\NotSupportedException;
use yii\db\Constraint;
use yii\db\DefaultValueConstraint;
use yii\db\mssql\Schema;
use yii\db\mssql\TableSchema;
use yiiunit\framework\db\AnyValue;

/**
Expand Down Expand Up @@ -202,4 +204,177 @@ public function testGetPrimaryKey(): void

$this->assertEquals($selectResult['id'], $insertResult['id']);
}

public function testQuoteColumnNameWithBrackets(): void
{
$schema = $this->getConnection()->getSchema();
$this->assertSame('[already_quoted]', $schema->quoteColumnName('[already_quoted]'));
}

/**
* @dataProvider resolveTableNameProvider
*/
public function testResolveTableName(
string $name,
?string $expectedCatalog,
string $expectedSchema,
string $expectedTable,
string $expectedFullName
): void {
$schema = $this->getConnection()->getSchema();
$method = new \ReflectionMethod($schema, 'resolveTableName');
if (PHP_VERSION_ID < 80100) {
$method->setAccessible(true);
}
$result = $method->invoke($schema, $name);
$this->assertSame($expectedCatalog, $result->catalogName);
$this->assertSame($expectedSchema, $result->schemaName);
$this->assertSame($expectedTable, $result->name);
$this->assertSame($expectedFullName, $result->fullName);
}

public static function resolveTableNameProvider(): array
{
return [
'single part' => [
'customer',
null,
'dbo',
'customer',
'customer',
],
'two parts' => [
'sales.customer',
null,
'sales',
'customer',
'sales.customer',
],
'two parts default schema' => [
'dbo.customer',
null,
'dbo',
'customer',
'customer',
],
'three parts' => [
'catalog1.sales.customer',
'catalog1',
'sales',
'customer',
'catalog1.sales.customer',
],
'four parts' => [
'[server1].catalog1.sales.customer',
'catalog1',
'sales',
'customer',
'catalog1.sales.customer',
],
];
}

public function testSavepointOperations(): void
{
$db = $this->getConnection(true, true);
$db->beginTransaction();
$db->createCommand("INSERT INTO [profile] ([description]) VALUES ('sp_test')")->execute();
$db->getSchema()->createSavepoint('sp1');
$db->createCommand("INSERT INTO [profile] ([description]) VALUES ('sp_test_after')")->execute();
$db->getSchema()->rollBackSavepoint('sp1');
$db->transaction->commit();

$afterCount = (int)$db->createCommand("SELECT COUNT(*) FROM [profile] WHERE [description] = 'sp_test_after'")->queryScalar();
$this->assertSame(0, $afterCount);
$beforeCount = (int)$db->createCommand("SELECT COUNT(*) FROM [profile] WHERE [description] = 'sp_test'")->queryScalar();
$this->assertSame(1, $beforeCount);

$db->createCommand("DELETE FROM [profile] WHERE [description] = 'sp_test'")->execute();
}

public function testReleaseSavepointIsNoOp(): void
{
$db = $this->getConnection(true, true);
$db->beginTransaction();
$db->getSchema()->createSavepoint('sp1');
$db->getSchema()->releaseSavepoint('sp1');
$this->assertTrue($db->transaction->getIsActive());
$db->transaction->rollBack();
}

/**
* @dataProvider resolveTableNameProvider
*/
public function testResolveTableNames(
string $name,
?string $expectedCatalog,
string $expectedSchema,
string $expectedTable,
string $expectedFullName
): void {
$schema = $this->getConnection()->getSchema();
$table = new TableSchema();
$method = new \ReflectionMethod($schema, 'resolveTableNames');
if (PHP_VERSION_ID < 80100) {
$method->setAccessible(true);
}
$method->invoke($schema, $table, $name);
$this->assertSame($expectedCatalog, $table->catalogName);
$this->assertSame($expectedSchema, $table->schemaName);
$this->assertSame($expectedTable, $table->name);
$this->assertSame($expectedFullName, $table->fullName);
}

public function testGetSchemaPrimaryKeysWithExplicitSchema(): void
{
$schema = $this->getConnection(true, true)->getSchema();
$primaryKeys = $schema->getSchemaPrimaryKeys('dbo');
$this->assertNotEmpty($primaryKeys);
$this->assertContainsOnlyInstancesOf(Constraint::class, $primaryKeys);
}

public function testNullDefaultValueColumn(): void
{
$schema = $this->getConnection(true, true)->getSchema();
$table = $schema->getTableSchema('null_values');
$this->assertNull($table->getColumn('var3')->defaultValue);
$this->assertNull($table->getColumn('stringcol')->defaultValue);
}

public function testInsertWithCompositePrimaryKey(): void
{
$db = $this->getConnection(true, true);
$result = $db->getSchema()->insert('employee', [
'id' => 100,
'department_id' => 1,
'first_name' => 'Test',
'last_name' => 'User',
]);
$this->assertSame('100', $result['id']);
$this->assertSame('1', $result['department_id']);

$db->createCommand('DELETE FROM [employee] WHERE [id] = 100 AND [department_id] = 1')->execute();
}

public function testGetViewNamesWithDefaultSchema(): void
{
$schema = $this->getConnection(true, true)->getSchema();
$viewNames = $schema->getViewNames();
$this->assertContains('animal_view', $viewNames);
}

public function testFindUniqueIndexes(): void
{
$db = $this->getConnection(true, true);
$table = $db->getSchema()->getTableSchema('T_upsert');
$indexes = $db->getSchema()->findUniqueIndexes($table);
$this->assertNotEmpty($indexes);
}

public function testCreateColumnSchemaBuilder(): void
{
$schema = $this->getConnection()->getSchema();
$builder = $schema->createColumnSchemaBuilder('string', 255);
$this->assertInstanceOf('yii\db\mssql\ColumnSchemaBuilder', $builder);
}
}
Loading