diff --git a/tests/php/ORM/MySQLPDOConnectorTest.php b/tests/php/ORM/MySQLPDOConnectorTest.php index 9ce68399d4d..f027edb362a 100644 --- a/tests/php/ORM/MySQLPDOConnectorTest.php +++ b/tests/php/ORM/MySQLPDOConnectorTest.php @@ -9,6 +9,7 @@ use SilverStripe\Dev\TestOnly; use SilverStripe\ORM\Tests\MySQLPDOConnectorTest\PDOConnector; use SilverStripe\ORM\DB; +use SilverStripe\Tests\ORM\Utf8\Utf8TestHelper; /** * @requires extension PDO @@ -38,8 +39,9 @@ public function testConnectionCharsetControl($charset, $defaultCollation) $cset = $connection->query('show variables like "character_set_connection"')->fetch(PDO::FETCH_NUM)[1]; $collation = $connection->query('show variables like "collation_connection"')->fetch(PDO::FETCH_NUM)[1]; - $this->assertEquals($charset, $cset); - $this->assertEquals($defaultCollation, $collation); + $helper = new Utf8TestHelper(); + $this->assertEquals($helper->getUpdatedUtfCharsetForCurrentDB($charset), $cset); + $this->assertEquals($helper->getUpdatedUtfCollationForCurrentDB($defaultCollation), $collation); unset($cset, $connection, $connector, $config); } @@ -66,8 +68,9 @@ public function testConnectionCollationControl($charset, $defaultCollation, $cus $cset = $connection->query('show variables like "character_set_connection"')->fetch(PDO::FETCH_NUM)[1]; $collation = $connection->query('show variables like "collation_connection"')->fetch(PDO::FETCH_NUM)[1]; - $this->assertEquals($charset, $cset); - $this->assertEquals($customCollation, $collation); + $helper = new Utf8TestHelper(); + $this->assertEquals($helper->getUpdatedUtfCharsetForCurrentDB($charset), $cset); + $this->assertEquals($helper->getUpdatedUtfCollationForCurrentDB($customCollation), $collation); unset($cset, $connection, $connector, $config); } diff --git a/tests/php/ORM/MySQLiConnectorTest.php b/tests/php/ORM/MySQLiConnectorTest.php index 001c18cdb83..e4c9a34f6ae 100644 --- a/tests/php/ORM/MySQLiConnectorTest.php +++ b/tests/php/ORM/MySQLiConnectorTest.php @@ -6,6 +6,7 @@ use SilverStripe\Dev\TestOnly; use SilverStripe\ORM\Tests\MySQLiConnectorTest\MySQLiConnector; use SilverStripe\ORM\DB; +use SilverStripe\Tests\ORM\Utf8\Utf8TestHelper; /** * @requires extension mysqli @@ -31,6 +32,10 @@ public function testConnectionCharsetControl($charset, $defaultCollation) $cset = $connection->get_charset(); + // Note: we do not need to update the utf charset here because mysqli with newer + // version of mysql/mariadb still self-reports as 'utf8' rather than 'utf8mb3' + // This is unlike self::testConnectionCollationControl() + // And also unlike MySQLPDOConnectorTest::testConnectionCharsetControl() $this->assertEquals($charset, $cset->charset); $this->assertEquals($defaultCollation, $cset->collation); @@ -77,8 +82,9 @@ public function testConnectionCollationControl($charset, $defaultCollation, $cus $cset = $connection->query('show variables like "character_set_connection"')->fetch_array()[1]; $collation = $connection->query('show variables like "collation_connection"')->fetch_array()[1]; - $this->assertEquals($charset, $cset); - $this->assertEquals($customCollation, $collation); + $helper = new Utf8TestHelper(); + $this->assertEquals($helper->getUpdatedUtfCharsetForCurrentDB($charset), $cset); + $this->assertEquals($helper->getUpdatedUtfCollationForCurrentDB($customCollation), $collation); $connection->close(); unset($cset, $connection, $connector, $config); diff --git a/tests/php/ORM/Utf8/Utf8TestHelper.php b/tests/php/ORM/Utf8/Utf8TestHelper.php new file mode 100644 index 00000000000..57379b0e876 --- /dev/null +++ b/tests/php/ORM/Utf8/Utf8TestHelper.php @@ -0,0 +1,69 @@ +isMySqlGte80() || $this->isMariaDBGte106() ? 'utf8mb3' : 'utf8'; + } + + public function getUpdatedUtfCollationForCurrentDB(string $collation): string + { + if ($collation === 'utf8_general_ci') { + return $this->isMariaDBGte106() ? 'utf8mb3_general_ci' : 'utf8_general_ci'; + } + if ($collation === 'utf8_unicode_520_ci') { + return $this->isMariaDBGte106() ? 'utf8mb3_unicode_520_ci' : 'utf8_unicode_520_ci'; + } + return $collation; + } + + /** + * MySQL has used utf8 as an alias for utf8mb3 + * Beginning with MySQL 8.0.28, utf8mb3 is used + * https://dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf8mb3.html + */ + private function isMySqlGte80(): bool + { + // Example MySQL version: 8.0.29 + if (preg_match('#^([0-9]+)\.[0-9]+\.[0-9]+$#', $this->getDBVersion(), $m)) { + return (int) $m[1] >= 8; + } + return false; + } + + /** + * Until MariaDB 10.5, utf8mb3 was an alias for utf8. + * From MariaDB 10.6, utf8 is by default an alias for utf8mb3 + * https://mariadb.com/kb/en/unicode/ + */ + private function isMariaDBGte106(): bool + { + // Example mariadb version: 5.5.5-10.6.8-mariadb-1:10.6.8+maria~focal + if (preg_match('#([0-9]+)\.([0-9]+)\.[0-9]+-mariadb#', $this->getDBVersion(), $m)) { + return (int) $m[1] >= 11 || ((int) $m[1] >= 10 && (int) $m[2] >= 6); + } + return false; + } + + private function getDBVersion(): string + { + if (is_null($this->dbVersion)) { + $this->dbVersion = strtolower(DB::get_conn()->getVersion()); + } + return $this->dbVersion; + } +}