Skip to content

Commit

Permalink
Add draft loadTableChecks() method, and add tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
terabytesoftw committed May 18, 2024
1 parent f3f2f2b commit 4996fd3
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 10 deletions.
48 changes: 46 additions & 2 deletions framework/db/mysql/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Yii;
use yii\base\InvalidConfigException;
use yii\base\NotSupportedException;
use yii\db\CheckConstraint;
use yii\db\Constraint;
use yii\db\ConstraintFinderInterface;
use yii\db\ConstraintFinderTrait;
Expand Down Expand Up @@ -201,11 +202,54 @@ protected function loadTableUniques($tableName)

/**
* {@inheritdoc}
* @throws NotSupportedException if this method is called.
*/
protected function loadTableChecks($tableName)
{
throw new NotSupportedException('MySQL does not support check constraints.');
// check version MySQL >= 8.0.16
if (version_compare($this->db->getSlavePdo()->getAttribute(\PDO::ATTR_SERVER_VERSION), '8.0.16', '<')) {
$this->markTestSkipped('MySQL < 8.0.16 does not support CHECK constraints.');
}

$checks = [];

$sql = <<<SQL
SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = :tableName
SQL;

$resolvedName = $this->resolveTableName($tableName);
$tableRows = $this->db->createCommand($sql, [':tableName' => $resolvedName->name])->queryAll();

if ($tableRows === []) {
return $checks;
}

foreach ($tableRows as $tableRow) {
$sql = <<<SQL
SELECT * FROM INFORMATION_SCHEMA.CHECK_CONSTRAINTS WHERE CONSTRAINT_NAME = :constraintName
SQL;

$checkRows = $this->db->createCommand($sql, [':constraintName' => $tableRow['CONSTRAINT_NAME']])->queryAll();

foreach ($checkRows as $checkRow) {
$matches = [];
$columnName = null;

if (preg_match('/\(`?([a-zA-Z0-9_]+)`?\s*[><=]/', $checkRow['CHECK_CLAUSE'], $matches)) {
$columnName = $matches[1];
}

$check = new CheckConstraint(
[
'name' => $checkRow['CONSTRAINT_NAME'],
'columnNames' => $columnName,
'expression' => $checkRow['CHECK_CLAUSE'],
]
);
$checks[] = $check;
}
}

return $checks;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions tests/framework/db/CommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ public function invalidSelectColumns()
* Test INSERT INTO ... SELECT SQL statement with wrong query object.
*
* @dataProvider invalidSelectColumns
*
*
* @param mixed $invalidSelectColumns
*/
public function testInsertSelectFailed($invalidSelectColumns)
Expand Down Expand Up @@ -1208,7 +1208,6 @@ public function testAddDropCheck()
$db = $this->getConnection(false);
$tableName = 'test_ck';
$name = 'test_ck_constraint';
/** @var \yii\db\pgsql\Schema $schema */
$schema = $db->getSchema();

if ($schema->getTableSchema($tableName) !== null) {
Expand All @@ -1226,6 +1225,7 @@ public function testAddDropCheck()
);

$db->createCommand()->dropCheck($name, $tableName)->execute();

$this->assertEmpty($schema->getTableChecks($tableName, true));
}

Expand Down
44 changes: 44 additions & 0 deletions tests/framework/db/mysql/CommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,48 @@ class CommandTest extends \yiiunit\framework\db\CommandTest
public $driverName = 'mysql';

protected $upsertTestCharCast = 'CONVERT([[address]], CHAR)';

public function testAddDropCheckSeveral()
{
$db = $this->getConnection(false);
$tableName = 'test_ck_several';
$schema = $db->getSchema();

if ($schema->getTableSchema($tableName) !== null) {
$db->createCommand()->dropTable($tableName)->execute();
}
$db->createCommand()->createTable($tableName, [
'int1' => 'integer',
'int2' => 'integer',
'int3' => 'integer',
])->execute();

$this->assertEmpty($schema->getTableChecks($tableName, true));

$constraints = [
['name' => 'check_int1_positive', 'expression' => '[[int1]] > 0', 'expected' => '(`int1` > 0)'],
['name' => 'check_int2_nonzero', 'expression' => '[[int2]] <> 0', 'expected' => '(`int2` <> 0)'],
['name' => 'check_int3_less_than_100', 'expression' => '[[int3]] < 100', 'expected' => '(`int3` < 100)'],
];

foreach ($constraints as $constraint) {
$db->createCommand()->addCheck($constraint['name'], $tableName, $constraint['expression'])->execute();
}

$tableChecks = $schema->getTableChecks($tableName, true);
$this->assertCount(3, $tableChecks);

foreach ($constraints as $index => $constraint) {
$this->assertSame(
$constraints[$index]['expected'],
$tableChecks[$index]->expression
);
}

foreach ($constraints as $constraint) {
$db->createCommand()->dropCheck($constraint['name'], $tableName)->execute();
}

$this->assertEmpty($schema->getTableChecks($tableName, true));
}
}
7 changes: 1 addition & 6 deletions tests/framework/db/mysql/QueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,6 @@ public function uniquesProvider()
return $result;
}

public function checksProvider()
{
$this->markTestSkipped('Adding/dropping check constraints is not supported in MySQL.');
}

public function defaultValuesProvider()
{
$this->markTestSkipped('Adding/dropping default constraints is not supported in MySQL.');
Expand Down Expand Up @@ -403,7 +398,7 @@ public function testDefaultValues()
// primary key columns should have NULL as value
$sql = $command->insert('null_values', [])->getRawSql();
$this->assertEquals("INSERT INTO `null_values` (`id`) VALUES (NULL)", $sql);

// non-primary key columns should have DEFAULT as value
$sql = $command->insert('negative_default_values', [])->getRawSql();
$this->assertEquals("INSERT INTO `negative_default_values` (`tinyint_col`) VALUES (DEFAULT)", $sql);
Expand Down

0 comments on commit 4996fd3

Please sign in to comment.