diff --git a/framework/db/mysql/Schema.php b/framework/db/mysql/Schema.php index e9678392f67..583452d9aec 100644 --- a/framework/db/mysql/Schema.php +++ b/framework/db/mysql/Schema.php @@ -205,8 +205,10 @@ protected function loadTableUniques($tableName) */ protected function loadTableChecks($tableName) { + $version = $this->db->getServerVersion(); + // check version MySQL >= 8.0.16 - if (version_compare($this->db->getSlavePdo()->getAttribute(\PDO::ATTR_SERVER_VERSION), '8.0.16', '<')) { + if (\stripos($version, 'MariaDb') === false && \version_compare($version, '8.0.16', '<')) { throw new NotSupportedException('MySQL < 8.0.16 does not support check constraints.'); } @@ -230,17 +232,9 @@ protected function loadTableChecks($tableName) $tableRows = $this->normalizePdoRowKeyCase($tableRows, true); foreach ($tableRows as $tableRow) { - $matches = []; - $columnName = null; - - if (preg_match('/\(`?([a-zA-Z0-9_]+)`?\s*[><=]/', $tableRow['check_clause'], $matches)) { - $columnName = $matches[1]; - } - $check = new CheckConstraint( [ 'name' => $tableRow['constraint_name'], - 'columnNames' => [$columnName], 'expression' => $tableRow['check_clause'], ] ); diff --git a/tests/framework/db/SchemaTest.php b/tests/framework/db/SchemaTest.php index 4dfa40b915c..ecbc35490d5 100644 --- a/tests/framework/db/SchemaTest.php +++ b/tests/framework/db/SchemaTest.php @@ -773,14 +773,6 @@ public function testTableSchemaConstraints($tableName, $type, $expected) $this->expectException('yii\base\NotSupportedException'); } - if ( - $this->driverName === 'mysql' && - version_compare($this->getConnection(false)->getServerVersion(), '8.0.16', '<') && - $type === 'checks' - ) { - $this->expectException('yii\base\NotSupportedException'); - } - $constraints = $this->getConnection(false)->getSchema()->{'getTable' . ucfirst($type)}($tableName); $this->assertMetadataEquals($expected, $constraints); } @@ -797,14 +789,6 @@ public function testTableSchemaConstraintsWithPdoUppercase($tableName, $type, $e $this->expectException('yii\base\NotSupportedException'); } - if ( - $this->driverName === 'mysql' && - version_compare($this->getConnection(false)->getServerVersion(), '8.0.16', '<') && - $type === 'checks' - ) { - $this->expectException('yii\base\NotSupportedException'); - } - $connection = $this->getConnection(false); $connection->getSlavePdo(true)->setAttribute(PDO::ATTR_CASE, PDO::CASE_UPPER); $constraints = $connection->getSchema()->{'getTable' . ucfirst($type)}($tableName, true); @@ -823,21 +807,13 @@ public function testTableSchemaConstraintsWithPdoLowercase($tableName, $type, $e $this->expectException('yii\base\NotSupportedException'); } - if ( - $this->driverName === 'mysql' && - version_compare($this->getConnection(false)->getServerVersion(), '8.0.16', '<') && - $type === 'checks' - ) { - $this->expectException('yii\base\NotSupportedException'); - } - $connection = $this->getConnection(false); $connection->getSlavePdo(true)->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER); $constraints = $connection->getSchema()->{'getTable' . ucfirst($type)}($tableName, true); $this->assertMetadataEquals($expected, $constraints); } - private function assertMetadataEquals($expected, $actual) + protected function assertMetadataEquals($expected, $actual) { switch (\strtolower(\gettype($expected))) { case 'object': @@ -865,7 +841,7 @@ private function assertMetadataEquals($expected, $actual) $this->assertEquals($expected, $actual); } - private function normalizeArrayKeys(array &$array, $caseSensitive) + protected function normalizeArrayKeys(array &$array, $caseSensitive) { $newArray = []; foreach ($array as $value) { @@ -889,7 +865,7 @@ private function normalizeArrayKeys(array &$array, $caseSensitive) $array = $newArray; } - private function normalizeConstraints(&$expected, &$actual) + protected function normalizeConstraints(&$expected, &$actual) { if (\is_array($expected)) { foreach ($expected as $key => $value) { @@ -904,7 +880,7 @@ private function normalizeConstraints(&$expected, &$actual) } } - private function normalizeConstraintPair(Constraint $expectedConstraint, Constraint $actualConstraint) + protected function normalizeConstraintPair(Constraint $expectedConstraint, Constraint $actualConstraint) { if ($expectedConstraint::className() !== $actualConstraint::className()) { return; diff --git a/tests/framework/db/mysql/CommandTest.php b/tests/framework/db/mysql/CommandTest.php index 60c562c737b..6619a93e636 100644 --- a/tests/framework/db/mysql/CommandTest.php +++ b/tests/framework/db/mysql/CommandTest.php @@ -35,6 +35,7 @@ public function testAddDropCheckSeveral() 'int1' => 'integer', 'int2' => 'integer', 'int3' => 'integer', + 'int4' => 'integer', ])->execute(); $this->assertEmpty($schema->getTableChecks($tableName, true)); @@ -43,14 +44,22 @@ public function testAddDropCheckSeveral() ['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)'], + ['name' => 'check_int1_less_than_int2', 'expression' => '[[int1]] < [[int2]]', 'expected' => '(`int1` < `int2`)'], ]; + if (\stripos($db->getServerVersion(), 'MariaDb') !== false) { + $constraints[0]['expected'] = '`int1` > 0'; + $constraints[1]['expected'] = '`int2` <> 0'; + $constraints[2]['expected'] = '`int3` < 100'; + $constraints[3]['expected'] = '`int1` < `int2`'; + } + foreach ($constraints as $constraint) { $db->createCommand()->addCheck($constraint['name'], $tableName, $constraint['expression'])->execute(); } $tableChecks = $schema->getTableChecks($tableName, true); - $this->assertCount(3, $tableChecks); + $this->assertCount(4, $tableChecks); foreach ($constraints as $index => $constraint) { $this->assertSame( diff --git a/tests/framework/db/mysql/SchemaTest.php b/tests/framework/db/mysql/SchemaTest.php index aa2634ff307..fc9aa46d652 100644 --- a/tests/framework/db/mysql/SchemaTest.php +++ b/tests/framework/db/mysql/SchemaTest.php @@ -78,8 +78,8 @@ public function constraintsProvider() { $result = parent::constraintsProvider(); - $result['1: check'][2][0]->expression = "(`C_check` <> _utf8mb4\\'\\')"; - + $result['1: check'][2][0]->columnNames = null; + $result['1: check'][2][0]->expression = "`C_check` <> ''"; $result['2: primary key'][2]->name = null; // Work aroung bug in MySQL 5.1 - it creates only this table in lowercase. O_o @@ -88,6 +88,115 @@ public function constraintsProvider() return $result; } + /** + * @dataProvider constraintsProvider + * @param string $tableName + * @param string $type + * @param mixed $expected + */ + public function testTableSchemaConstraints($tableName, $type, $expected) + { + $version = $this->getConnection(false)->getServerVersion(); + + if ($expected === false) { + $this->expectException('yii\base\NotSupportedException'); + } + + if ( + $this->driverName === 'mysql' && + \stripos($version, 'MariaDb') === false && + version_compare($version, '8.0.16', '<') && + $type === 'checks' + ) { + $this->expectException('yii\base\NotSupportedException'); + } elseif ( + $this->driverName === 'mysql' && + \stripos($version, 'MariaDb') === false && + version_compare($version, '8.0.16', '>=') && + $tableName === 'T_constraints_1' && + $type === 'checks' + ) { + $expected[0]->expression = "(`C_check` <> _utf8mb4\\'\\')"; + } + + $constraints = $this->getConnection(false)->getSchema()->{'getTable' . ucfirst($type)}($tableName); + $this->assertMetadataEquals($expected, $constraints); + } + + /** + * @dataProvider uppercaseConstraintsProvider + * @param string $tableName + * @param string $type + * @param mixed $expected + */ + public function testTableSchemaConstraintsWithPdoUppercase($tableName, $type, $expected) + { + $version = $this->getConnection(false)->getServerVersion(); + + if ($expected === false) { + $this->expectException('yii\base\NotSupportedException'); + } + + if ( + $this->driverName === 'mysql' && + \stripos($version, 'MariaDb') === false && + version_compare($version, '8.0.16', '<') && + $type === 'checks' + ) { + $this->expectException('yii\base\NotSupportedException'); + } elseif ( + $this->driverName === 'mysql' && + \stripos($version, 'MariaDb') === false && + version_compare($version, '8.0.16', '>=') && + $tableName === 'T_constraints_1' && + $type === 'checks' + ) { + $expected[0]->expression = "(`C_check` <> _utf8mb4\\'\\')"; + } + + $connection = $this->getConnection(false); + $connection->getSlavePdo(true)->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_UPPER); + $constraints = $connection->getSchema()->{'getTable' . ucfirst($type)}($tableName, true); + $this->assertMetadataEquals($expected, $constraints); + } + + /** + * @dataProvider lowercaseConstraintsProvider + * @param string $tableName + * @param string $type + * @param mixed $expected + */ + public function testTableSchemaConstraintsWithPdoLowercase($tableName, $type, $expected) + { + $version = $this->getConnection(false)->getServerVersion(); + + if ($expected === false) { + $this->expectException('yii\base\NotSupportedException'); + } + + if ( + $this->driverName === 'mysql' && + \stripos($version, 'MariaDb') === false && + version_compare($version, '8.0.16', '<') && + $type === 'checks' + ) { + $this->expectException('yii\base\NotSupportedException'); + } elseif ( + $this->driverName === 'mysql' && + \stripos($version, 'MariaDb') === false && + version_compare($version, '8.0.16', '>=') && + $tableName === 'T_constraints_1' && + $type === 'checks' + ) { + $expected[0]->expression = "(`C_check` <> _utf8mb4\\'\\')"; + } + + $connection = $this->getConnection(false); + $connection->getSlavePdo(true)->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_LOWER); + $constraints = $connection->getSchema()->{'getTable' . ucfirst($type)}($tableName, true); + $this->assertMetadataEquals($expected, $constraints); + } + /** * When displayed in the INFORMATION_SCHEMA.COLUMNS table, a default CURRENT TIMESTAMP is displayed * as CURRENT_TIMESTAMP up until MariaDB 10.2.2, and as current_timestamp() from MariaDB 10.2.3. diff --git a/tests/framework/db/mysql/connection/DeadLockTest.php b/tests/framework/db/mysql/connection/DeadLockTest.php index 6e3da047eea..550b2852a69 100644 --- a/tests/framework/db/mysql/connection/DeadLockTest.php +++ b/tests/framework/db/mysql/connection/DeadLockTest.php @@ -31,6 +31,9 @@ class DeadLockTest extends \yiiunit\framework\db\mysql\ConnectionTest */ public function testDeadlockException() { + if (\stripos($this->getConnection(false)->getServerVersion(), 'MariaDB') !== false) { + $this->markTestSkipped('MariaDB does not support this test'); + } if (PHP_VERSION_ID >= 70400 && PHP_VERSION_ID < 70500) { $this->markTestSkipped('Stable failed in PHP 7.4'); }