Commit 28b8b4e4 authored by catch's avatar catch
Browse files

Issue #3109534 by TravisCarden, mondrake, effulgentsia, andypost, Gábor...

Issue #3109534 by TravisCarden, mondrake, effulgentsia, andypost, Gábor Hojtsy, catch, daffie, xjm: Raise the minimum MySQL version to 5.7.8 and MariaDB version to 10.2.7 in Drupal 9
parent fc9d6cea
......@@ -51,10 +51,10 @@ Drupal requires:
- PHP 7.3.0 (or greater) (http://php.net/). For better security support it is
recommended to update to at least 7.3.13.
- One of the following databases:
- MySQL 5.5.3 (or greater) (http://www.mysql.com/).
- MariaDB 5.5.20 (or greater) (https://mariadb.org/). MariaDB is a fully
- MySQL 5.7.8 (or greater) (http://www.mysql.com/).
- MariaDB 10.2.7 (or greater) (https://mariadb.org/). MariaDB is a fully
compatible drop-in replacement for MySQL.
- Percona Server 5.5.8 (or greater) (http://www.percona.com/). Percona
- Percona Server 5.7.8 (or greater) (http://www.percona.com/). Percona
Server is a backwards-compatible replacement for MySQL.
- PostgreSQL 9.1.2 (or greater) (http://www.postgresql.org/).
- SQLite 3.7.11 (or greater) (http://www.sqlite.org/).
......
......@@ -546,6 +546,53 @@ public function driver() {
return 'mysql';
}
/**
* {@inheritdoc}
*/
public function version() {
if ($this->isMariaDb()) {
return $this->getMariaDbVersionMatch();
}
return $this->getServerVersion();
}
/**
* Determines whether the MySQL distribution is MariaDB or not.
*
* @return bool
* Returns TRUE if the distribution is MariaDB, or FALSE if not.
*/
public function isMariaDb(): bool {
return (bool) $this->getMariaDbVersionMatch();
}
/**
* Gets the MariaDB portion of the server version.
*
* @return string
* The MariaDB portion of the server version if present, or NULL if not.
*/
protected function getMariaDbVersionMatch(): ?string {
// MariaDB may prefix its version string with '5.5.5-', which should be
// ignored.
// @see https://github.com/MariaDB/server/blob/f6633bf058802ad7da8196d01fd19d75c53f7274/include/mysql_com.h#L42.
$regex = '/^(?:5\.5\.5-)?(\d+\.\d+\.\d+.*-mariadb.*)/i';
preg_match($regex, $this->getServerVersion(), $matches);
return (empty($matches[1])) ? NULL : $matches[1];
}
/**
* Gets the server version.
*
* @return string
* The PDO server version.
*/
protected function getServerVersion(): string {
return $this->connection->getAttribute(\PDO::ATTR_SERVER_VERSION);
}
public function databaseType() {
return 'mysql';
}
......
......@@ -2,8 +2,9 @@
namespace Drupal\Core\Database\Driver\mysql\Install;
use Drupal\Core\Database\Install\Tasks as InstallTasks;
use Drupal\Core\Database\ConnectionNotDefinedException;
use Drupal\Core\Database\Database;
use Drupal\Core\Database\Install\Tasks as InstallTasks;
use Drupal\Core\Database\Driver\mysql\Connection;
use Drupal\Core\Database\DatabaseNotFoundException;
......@@ -12,6 +13,22 @@
*/
class Tasks extends InstallTasks {
/**
* Minimum required MySQL version.
*
* 5.7.8 is the minimum version that supports the JSON datatype.
* @see https://dev.mysql.com/doc/refman/5.7/en/json.html
*/
const MYSQL_MINIMUM_VERSION = '5.7.8';
/**
* Minimum required MariaDB version.
*
* 10.2.7 is the minimum version that supports the JSON datatype (alias).
* @see https://mariadb.com/kb/en/json-data-type/
*/
const MARIADB_MINIMUM_VERSION = '10.2.7';
/**
* Minimum required MySQLnd version.
*/
......@@ -43,18 +60,28 @@ public function __construct() {
* {@inheritdoc}
*/
public function name() {
return t('MySQL, MariaDB, Percona Server, or equivalent');
try {
if (!$this->isConnectionActive() || !$this->getConnection() instanceof Connection) {
throw new ConnectionNotDefinedException('The database connection is not active or not a MySql connection');
}
if ($this->getConnection()->isMariaDb()) {
return $this->t('MariaDB');
}
return $this->t('MySQL, Percona Server, or equivalent');
}
catch (ConnectionNotDefinedException $e) {
return $this->t('MySQL, MariaDB, Percona Server, or equivalent');
}
}
/**
* {@inheritdoc}
*/
public function minimumVersion() {
// This can not be increased above '5.5.5' without dropping support for all
// MariaDB versions. MariaDB prefixes its version string with '5.5.5-'. For
// more information, see
// https://github.com/MariaDB/server/blob/f6633bf058802ad7da8196d01fd19d75c53f7274/include/mysql_com.h#L42.
return '5.5.3';
if ($this->getConnection()->isMariaDb()) {
return static::MARIADB_MINIMUM_VERSION;
}
return static::MYSQL_MINIMUM_VERSION;
}
/**
......
......@@ -3,6 +3,7 @@
namespace Drupal\Core\Database\Install;
use Drupal\Core\Database\Database;
use Drupal\Core\StringTranslation\TranslatableMarkup;
/**
* Database installer structure.
......@@ -300,4 +301,34 @@ public function validateDatabaseSettings($database) {
return $errors;
}
/**
* Translates a string to the current language or to a given language.
*
* @see \Drupal\Core\StringTranslation\TranslatableMarkup::__construct()
*/
protected function t($string, array $args = [], array $options = []) {
return new TranslatableMarkup($string, $args, $options);
}
/**
* Determines if there is an active connection.
*
* @return bool
* TRUE if there is at least one database connection established, FALSE
* otherwise.
*/
protected function isConnectionActive() {
return Database::isActiveConnection();
}
/**
* Returns the database connection.
*
* @return \Drupal\Core\Database\Connection
* The database connection.
*/
protected function getConnection() {
return Database::getConnection();
}
}
<?php
namespace Drupal\Tests\Core\Database\Driver\mysql;
use Drupal\Core\Database\Driver\mysql\Connection;
use Drupal\Tests\UnitTestCase;
/**
* Tests MySQL database connections.
*
* @coversDefaultClass \Drupal\Core\Database\Driver\mysql\Connection
* @group Database
*/
class ConnectionTest extends UnitTestCase {
/**
* A PDO object prophecy.
*
* @var \PDO|\Prophecy\Prophecy\ObjectProphecy
*/
private $pdoConnection;
/**
* {@inheritdoc}
*/
public function setUp() {
$this->pdoConnection = $this->prophesize(\PDO::class);
}
/**
* Creates a Connection object for testing.
*
* @return \Drupal\Core\Database\Driver\mysql\Connection
*/
private function createConnection(): Connection {
/** @var \PDO $pdo_connection */
$pdo_connection = $this->pdoConnection->reveal();
return new class($pdo_connection) extends Connection {
public function __construct(\PDO $connection) {
$this->connection = $connection;
}
};
}
/**
* @covers ::version
* @covers ::isMariaDb
* @dataProvider providerVersionAndIsMariaDb
*/
public function testVersionAndIsMariaDb(bool $expected_is_mariadb, string $server_version, string $expected_version): void {
$this->pdoConnection
->getAttribute(\PDO::ATTR_SERVER_VERSION)
->shouldBeCalled()
->willReturn($server_version);
$connection = $this->createConnection();
$is_mariadb = $connection->isMariaDb();
$version = $connection->version();
$this->assertSame($expected_is_mariadb, $is_mariadb);
$this->assertSame($expected_version, $version);
}
/**
* Provides test data.
*
* @return array
*/
public function providerVersionAndIsMariaDb(): array {
return [
// MariaDB.
[
TRUE,
'10.2.0-MariaDB',
'10.2.0-MariaDB',
],
[
TRUE,
'10.2.1-MARIADB',
'10.2.1-MARIADB',
],
[
TRUE,
'10.2.2-alphaX-MARIADB',
'10.2.2-alphaX-MARIADB',
],
[
TRUE,
'5.5.5-10.2.20-MariaDB-1:10.2.20+maria~bionic',
'10.2.20-MariaDB-1:10.2.20+maria~bionic',
],
[
TRUE,
'5.5.5-10.3.22-MariaDB-0+deb10u1',
'10.3.22-MariaDB-0+deb10u1',
],
[
TRUE,
'5.5.5-10.3.22-buzz+-MariaDB-0+deb10u1',
'10.3.22-buzz+-MariaDB-0+deb10u1',
],
// MySQL.
[
FALSE,
'5.5.5-10.2.20-notMariaDB',
'5.5.5-10.2.20-notMariaDB',
],
[
FALSE,
'5.5.5',
'5.5.5',
],
[
FALSE,
'5.5.5-',
'5.5.5-',
],
[
FALSE,
'5.7.28',
'5.7.28',
],
[
FALSE,
'5.7.28-31',
'5.7.28-31',
],
];
}
}
<?php
namespace Drupal\Tests\Core\Database\Driver\mysql\install;
use Drupal\Core\Database\Driver\mysql\Connection;
use Drupal\Core\Database\Driver\mysql\Install\Tasks;
use Drupal\Tests\UnitTestCase;
/**
* Tests the MySQL install tasks.
*
* @coversDefaultClass \Drupal\Core\Database\Driver\mysql\Install\Tasks
* @group Database
*/
class TasksTest extends UnitTestCase {
/**
* A connection object prophecy.
*
* @var \Drupal\Core\Database\Driver\mysql\Connection|\Prophecy\Prophecy\ObjectProphecy
*/
private $connection;
/**
* {@inheritdoc}
*/
public function setUp() {
$this->connection = $this->prophesize(Connection::class);
}
/**
* Creates a Tasks object for testing.
*
* @return \Drupal\Core\Database\Driver\mysql\Install\Tasks
*/
private function createTasks(): Tasks {
/** @var \Drupal\Core\Database\Driver\mysql\Connection $connection */
$connection = $this->connection->reveal();
return new class($connection) extends Tasks {
private $connection;
public function __construct(Connection $connection) {
$this->connection = $connection;
}
protected function isConnectionActive() {
return TRUE;
}
protected function getConnection() {
return $this->connection;
}
protected function t($string, array $args = [], array $options = []) {
return $string;
}
};
}
/**
* Creates a Tasks object for testing, without connection.
*
* @return \Drupal\Core\Database\Driver\mysql\Install\Tasks
*/
private function createTasksNoConnection(): Tasks {
return new class() extends Tasks {
protected function isConnectionActive() {
return FALSE;
}
protected function getConnection() {
return NULL;
}
protected function t($string, array $args = [], array $options = []) {
return $string;
}
};
}
/**
* @covers ::minimumVersion
* @covers ::name
* @dataProvider providerNameAndMinimumVersion
*/
public function testNameAndMinimumVersion(bool $is_mariadb, string $expected_name, string $expected_minimum_version): void {
$this->connection
->isMariaDb()
->shouldBeCalledTimes(2)
->willReturn($is_mariadb);
$tasks = $this->createTasks();
$minimum_version = $tasks->minimumVersion();
$name = $tasks->name();
$this->assertSame($expected_minimum_version, $minimum_version);
$this->assertSame($expected_name, $name);
}
/**
* Provides test data.
*
* @return array
*/
public function providerNameAndMinimumVersion(): array {
return [
[
TRUE,
'MariaDB',
Tasks::MARIADB_MINIMUM_VERSION,
],
[
FALSE,
'MySQL, Percona Server, or equivalent',
Tasks::MYSQL_MINIMUM_VERSION,
],
];
}
/**
* @covers ::name
*/
public function testNameWithNoConnection() {
$tasks = $this->createTasksNoConnection();
$this->assertSame('MySQL, MariaDB, Percona Server, or equivalent', $tasks->name());
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment