diff --git a/src/Driver/AbstractMySQLDriver.php b/src/Driver/AbstractMySQLDriver.php index 96252120452..d8f3fb35c5b 100644 --- a/src/Driver/AbstractMySQLDriver.php +++ b/src/Driver/AbstractMySQLDriver.php @@ -17,8 +17,8 @@ use Doctrine\Deprecations\Deprecation; use function assert; +use function preg_match; use function stripos; -use function substr; use function version_compare; /** @@ -33,17 +33,18 @@ abstract class AbstractMySQLDriver implements VersionAwarePlatformDriver */ public function createDatabasePlatformForVersion($version) { - $mariadb = stripos($version, 'MariaDB') !== false; + $mariadb = stripos($version, 'mariadb') !== false; if ($mariadb && version_compare($this->getMariaDbMysqlVersionNumber($version), '10.2.7', '>=')) { return new MariaDb1027Platform(); } if (! $mariadb) { - if (version_compare($version, '8.0.0', '>=')) { + $oracleMysqlVersion = $this->getOracleMysqlVersionNumber($version); + if (version_compare($oracleMysqlVersion, '8', '>=')) { return new MySQL80Platform(); } - if (version_compare($version, '5.7.9', '>=')) { + if (version_compare($oracleMysqlVersion, '5.7.9', '>=')) { return new MySQL57Platform(); } } @@ -58,19 +59,64 @@ public function createDatabasePlatformForVersion($version) return $this->getDatabasePlatform(); } + /** + * Get a normalized 'version number' from the server string + * returned by Oracle MySQL servers. + * + * @param string $versionString Version string returned by the driver, i.e. '5.7.10' + * + * @throws Exception + */ + private function getOracleMysqlVersionNumber(string $versionString): string + { + if ( + preg_match( + '/^(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+))?)?/', + $versionString, + $versionParts, + ) === 0 + ) { + throw Exception::invalidPlatformVersionSpecified( + $versionString, + '..', + ); + } + + $majorVersion = $versionParts['major']; + $minorVersion = $versionParts['minor'] ?? 0; + $patchVersion = $versionParts['patch'] ?? null; + + if ($majorVersion === '5' && $minorVersion === '7') { + $patchVersion ??= '9'; + } + + return $majorVersion . '.' . $minorVersion . '.' . $patchVersion; + } + /** * Detect MariaDB server version, including hack for some mariadb distributions * that starts with the prefix '5.5.5-' * * @param string $versionString Version string as returned by mariadb server, i.e. '5.5.5-Mariadb-10.0.8-xenial' + * + * @throws Exception */ private function getMariaDbMysqlVersionNumber(string $versionString): string { - if (substr($versionString, 0, 6) === '5.5.5-') { - return substr($versionString, 6); + if ( + preg_match( + '/^(?:5\.5\.5-)?(mariadb-)?(?P\d+)\.(?P\d+)\.(?P\d+)/i', + $versionString, + $versionParts, + ) === 0 + ) { + throw Exception::invalidPlatformVersionSpecified( + $versionString, + '^(?:5\.5\.5-)?(mariadb-)?..', + ); } - return $versionString; + return $versionParts['major'] . '.' . $versionParts['minor'] . '.' . $versionParts['patch']; } /** diff --git a/tests/Driver/AbstractDriverTest.php b/tests/Driver/AbstractDriverTest.php index 21a11bd0d0e..e14403b8db5 100644 --- a/tests/Driver/AbstractDriverTest.php +++ b/tests/Driver/AbstractDriverTest.php @@ -5,6 +5,7 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Driver; use Doctrine\DBAL\Driver\API\ExceptionConverter; +use Doctrine\DBAL\Exception; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Schema\AbstractSchemaManager; use Doctrine\DBAL\VersionAwarePlatformDriver; @@ -61,6 +62,16 @@ public function testCreatesDatabasePlatformForVersion(): void } } + public function testThrowsExceptionOnCreatingDatabasePlatformsForInvalidVersion(): void + { + if (! $this->driver instanceof VersionAwarePlatformDriver) { + self::markTestSkipped('This test is only intended for version aware platform drivers.'); + } + + $this->expectException(Exception::class); + $this->driver->createDatabasePlatformForVersion('foo'); + } + public function testReturnsDatabasePlatform(): void { self::assertEquals($this->createPlatform(), $this->driver->getDatabasePlatform()); diff --git a/tests/Driver/AbstractMySQLDriverTest.php b/tests/Driver/AbstractMySQLDriverTest.php index d96dfd6d8cf..68454c09871 100644 --- a/tests/Driver/AbstractMySQLDriverTest.php +++ b/tests/Driver/AbstractMySQLDriverTest.php @@ -48,17 +48,21 @@ protected function getDatabasePlatformsForVersions(): array { return [ ['5.6.9', MySQLPlatform::class], + ['5.7', MySQL57Platform::class], ['5.7.0', MySQLPlatform::class], ['5.7.8', MySQLPlatform::class], ['5.7.9', MySQL57Platform::class], ['5.7.10', MySQL57Platform::class], + ['8', MySQL80Platform::class], + ['8.0', MySQL80Platform::class], ['8.0.11', MySQL80Platform::class], + ['6', MySQL57Platform::class], ['10.0.15-MariaDB-1~wheezy', MySQLPlatform::class], ['5.5.5-10.1.25-MariaDB', MySQLPlatform::class], ['10.1.2a-MariaDB-a1~lenny-log', MySQLPlatform::class], ['5.5.40-MariaDB-1~wheezy', MySQLPlatform::class], - ['5.5.5-10.2.8-MariaDB-1~xenial', MariaDb1027Platform::class], - ['5.5.5-10.2.8-MariaDB-10.2.8+maria~xenial-log', MariaDb1027Platform::class], + ['5.5.5-MariaDB-10.2.8+maria~xenial-log', MariaDb1027Platform::class], + ['10.2.8-MariaDB-10.2.8+maria~xenial-log', MariaDb1027Platform::class], ['10.2.8-MariaDB-1~lenny-log', MariaDb1027Platform::class], ]; }