Pull-request: #17767 Fixes: #17248 Signed-off-by: William Desportes <williamdes@wdes.fr>
This commit is contained in:
commit
44a349dd93
@ -1087,16 +1087,7 @@ class DatabaseInterface implements DbalInterface
|
||||
$version = $this->fetchSingleRow('SELECT @@version, @@version_comment');
|
||||
|
||||
if (is_array($version)) {
|
||||
$this->versionString = $version['@@version'] ?? '';
|
||||
$this->versionInt = Utilities::versionToInt($this->versionString);
|
||||
$this->versionComment = $version['@@version_comment'] ?? '';
|
||||
if (stripos($this->versionString, 'mariadb') !== false) {
|
||||
$this->isMariaDb = true;
|
||||
}
|
||||
|
||||
if (stripos($this->versionComment, 'percona') !== false) {
|
||||
$this->isPercona = true;
|
||||
}
|
||||
$this->setVersion($version);
|
||||
}
|
||||
|
||||
if ($this->versionInt > 50503) {
|
||||
@ -2282,6 +2273,22 @@ class DatabaseInterface implements DbalInterface
|
||||
return $this->isPercona;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set version
|
||||
*
|
||||
* @param array $version Database version information
|
||||
* @phpstan-param array<array-key, mixed> $version
|
||||
*/
|
||||
public function setVersion(array $version): void
|
||||
{
|
||||
$this->versionString = $version['@@version'] ?? '';
|
||||
$this->versionInt = Utilities::versionToInt($this->versionString);
|
||||
$this->versionComment = $version['@@version_comment'] ?? '';
|
||||
|
||||
$this->isMariaDb = stripos($this->versionString, 'mariadb') !== false;
|
||||
$this->isPercona = stripos($this->versionComment, 'percona') !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load correct database driver
|
||||
*
|
||||
|
||||
@ -200,6 +200,15 @@ class Compatibility
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the database supports UUID data type
|
||||
* true if uuid is supported
|
||||
*/
|
||||
public static function isUUIDSupported(DatabaseInterface $dbi): bool
|
||||
{
|
||||
return $dbi->isMariaDB() && $dbi->getVersion() >= 100700; // 10.7.0
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the database server supports virtual columns
|
||||
*/
|
||||
|
||||
@ -13,6 +13,7 @@ use function __;
|
||||
use function _pgettext;
|
||||
use function array_diff;
|
||||
use function array_merge;
|
||||
use function array_values;
|
||||
use function htmlspecialchars;
|
||||
use function in_array;
|
||||
use function mb_strtoupper;
|
||||
@ -418,6 +419,9 @@ class Types
|
||||
return __('Intended for storage of IPv6 addresses, as well as IPv4 '
|
||||
. 'addresses assuming conventional mapping of IPv4 addresses '
|
||||
. 'into IPv6 addresses');
|
||||
|
||||
case 'UUID':
|
||||
return __('128-bit UUID (Universally Unique Identifier)');
|
||||
}
|
||||
|
||||
return '';
|
||||
@ -485,6 +489,9 @@ class Types
|
||||
|
||||
case 'JSON':
|
||||
return 'JSON';
|
||||
|
||||
case 'UUID':
|
||||
return 'UUID';
|
||||
}
|
||||
|
||||
return '';
|
||||
@ -501,6 +508,7 @@ class Types
|
||||
{
|
||||
$isMariaDB = $this->dbi->isMariaDB();
|
||||
$serverVersion = $this->dbi->getVersion();
|
||||
$isUUIDSupported = Compatibility::isUUIDSupported($this->dbi);
|
||||
|
||||
switch ($class) {
|
||||
case 'CHAR':
|
||||
@ -545,7 +553,11 @@ class Types
|
||||
$ret = array_diff($ret, ['INET6_NTOA']);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
if (! $isUUIDSupported) {
|
||||
$ret = array_diff($ret, ['UUID']);
|
||||
}
|
||||
|
||||
return array_values($ret);
|
||||
|
||||
case 'DATE':
|
||||
return [
|
||||
@ -621,11 +633,16 @@ class Types
|
||||
'WEEKOFYEAR',
|
||||
'YEARWEEK',
|
||||
];
|
||||
|
||||
if (($isMariaDB && $serverVersion < 100012) || $serverVersion < 50603) {
|
||||
$ret = array_diff($ret, ['INET6_ATON']);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
if (! $isUUIDSupported) {
|
||||
$ret = array_diff($ret, ['UUID_SHORT']);
|
||||
}
|
||||
|
||||
return array_values($ret);
|
||||
|
||||
case 'SPATIAL':
|
||||
if ($serverVersion >= 50600) {
|
||||
@ -744,6 +761,7 @@ class Types
|
||||
{
|
||||
$isMariaDB = $this->dbi->isMariaDB();
|
||||
$serverVersion = $this->dbi->getVersion();
|
||||
$isUUIDSupported = Compatibility::isUUIDSupported($this->dbi);
|
||||
|
||||
// most used types
|
||||
$ret = [
|
||||
@ -752,6 +770,11 @@ class Types
|
||||
'TEXT',
|
||||
'DATE',
|
||||
];
|
||||
|
||||
if ($isUUIDSupported) {
|
||||
$ret[] = 'UUID';
|
||||
}
|
||||
|
||||
// numeric
|
||||
$ret[_pgettext('numeric types', 'Numeric')] = [
|
||||
'TINYINT',
|
||||
@ -822,6 +845,10 @@ class Types
|
||||
$ret['JSON'] = ['JSON'];
|
||||
}
|
||||
|
||||
if ($isUUIDSupported) {
|
||||
$ret['UUID'] = ['UUID'];
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ use PhpMyAdmin\Database\DatabaseList;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Dbal\ResultInterface;
|
||||
use PhpMyAdmin\Query\Utilities;
|
||||
use PhpMyAdmin\SqlParser\Context;
|
||||
use PhpMyAdmin\SystemDatabase;
|
||||
use PhpMyAdmin\Utils\SessionCache;
|
||||
use stdClass;
|
||||
@ -28,6 +29,18 @@ class DatabaseInterfaceTest extends AbstractTestCase
|
||||
$GLOBALS['server'] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tear down function for mockResponse method
|
||||
*/
|
||||
protected function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
unset($GLOBALS['lang']);
|
||||
unset($GLOBALS['cfg']['Server']['SessionTimeZone']);
|
||||
Context::load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for DBI::getCurrentUser() method.
|
||||
*
|
||||
@ -172,6 +185,93 @@ class DatabaseInterfaceTest extends AbstractTestCase
|
||||
$this->assertInstanceOf(DatabaseList::class, $GLOBALS['dblist']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for DBI::postConnect() method.
|
||||
* should not call setVersion method if cannot fetch version
|
||||
*/
|
||||
public function testPostConnectShouldNotCallSetVersionIfNoVersion(): void
|
||||
{
|
||||
$GLOBALS['lang'] = 'en';
|
||||
$GLOBALS['cfg']['Server']['SessionTimeZone'] = '';
|
||||
|
||||
$mock = $this->getMockBuilder(DatabaseInterface::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['fetchSingleRow', 'query', 'setVersion'])
|
||||
->getMock();
|
||||
|
||||
$mock->expects($this->once())
|
||||
->method('fetchSingleRow')
|
||||
->will($this->returnValue(null));
|
||||
|
||||
$mock->expects($this->never())->method('setVersion');
|
||||
|
||||
$mock->postConnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for DBI::postConnect() method.
|
||||
* should call setVersion method if $version has value
|
||||
*/
|
||||
public function testPostConnectShouldCallSetVersionOnce(): void
|
||||
{
|
||||
$GLOBALS['lang'] = 'en';
|
||||
$GLOBALS['cfg']['Server']['SessionTimeZone'] = '';
|
||||
$versionQueryResult = [
|
||||
'@@version' => '10.20.7-MariaDB-1:10.9.3+maria~ubu2204',
|
||||
'@@version_comment' => 'mariadb.org binary distribution',
|
||||
];
|
||||
|
||||
$mock = $this->getMockBuilder(DatabaseInterface::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['fetchSingleRow', 'query', 'setVersion'])
|
||||
->getMock();
|
||||
|
||||
$mock->expects($this->once())
|
||||
->method('fetchSingleRow')
|
||||
->will($this->returnValue($versionQueryResult));
|
||||
|
||||
$mock->expects($this->once())->method('setVersion')->with($versionQueryResult);
|
||||
|
||||
$mock->postConnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for DBI::postConnect() method.
|
||||
* should set version int, isMariaDB and isPercona
|
||||
*
|
||||
* @param array $version Database version
|
||||
* @param int $versionInt Database version as integer
|
||||
* @param bool $isMariaDb True if mariadb
|
||||
* @param bool $isPercona True if percona
|
||||
* @phpstan-param array<array-key, mixed> $version
|
||||
*
|
||||
* @dataProvider provideDatabaseVersionData
|
||||
*/
|
||||
public function testPostConnectShouldSetVersion(
|
||||
array $version,
|
||||
int $versionInt,
|
||||
bool $isMariaDb,
|
||||
bool $isPercona
|
||||
): void {
|
||||
$GLOBALS['lang'] = 'en';
|
||||
$GLOBALS['cfg']['Server']['SessionTimeZone'] = '';
|
||||
|
||||
$mock = $this->getMockBuilder(DatabaseInterface::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['fetchSingleRow', 'query'])
|
||||
->getMock();
|
||||
|
||||
$mock->expects($this->once())
|
||||
->method('fetchSingleRow')
|
||||
->will($this->returnValue($version));
|
||||
|
||||
$mock->postConnect();
|
||||
|
||||
$this->assertEquals($mock->getVersion(), $versionInt);
|
||||
$this->assertEquals($mock->isMariaDB(), $isMariaDb);
|
||||
$this->assertEquals($mock->isPercona(), $isPercona);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for getDbCollation
|
||||
*/
|
||||
@ -702,4 +802,77 @@ class DatabaseInterfaceTest extends AbstractTestCase
|
||||
|
||||
$this->assertAllQueriesConsumed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for setVersion method.
|
||||
*
|
||||
* @param array $version Database version
|
||||
* @param int $versionInt Database version as integer
|
||||
* @param bool $isMariaDb True if mariadb
|
||||
* @param bool $isPercona True if percona
|
||||
* @phpstan-param array<array-key, mixed> $version
|
||||
*
|
||||
* @dataProvider provideDatabaseVersionData
|
||||
*/
|
||||
public function testSetVersion(
|
||||
array $version,
|
||||
int $versionInt,
|
||||
bool $isMariaDb,
|
||||
bool $isPercona
|
||||
): void {
|
||||
$this->dbi->setVersion($version);
|
||||
|
||||
$this->assertEquals($versionInt, $this->dbi->getVersion());
|
||||
$this->assertEquals($isMariaDb, $this->dbi->isMariaDb());
|
||||
$this->assertEquals($isPercona, $this->dbi->isPercona());
|
||||
$this->assertEquals($version['@@version'], $this->dbi->getVersionString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for setVersion() tests.
|
||||
*
|
||||
* @return array
|
||||
* @psalm-return array<int, array{array<array-key, mixed>, int, bool, bool}>
|
||||
*/
|
||||
public function provideDatabaseVersionData(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
[
|
||||
'@@version' => '6.1.0',
|
||||
'@@version_comment' => "Percona Server (GPL), Release '11', Revision 'c1y2gr1df4a'",
|
||||
],
|
||||
60100,
|
||||
false,
|
||||
true,
|
||||
],
|
||||
[
|
||||
[
|
||||
'@@version' => '10.01.40-MariaDB-1:10.01.40+maria~ubu2204',
|
||||
'@@version_comment' => 'mariadb.org binary distribution',
|
||||
],
|
||||
100140,
|
||||
true,
|
||||
false,
|
||||
],
|
||||
[
|
||||
[
|
||||
'@@version' => '7.10.3',
|
||||
'@@version_comment' => 'MySQL Community Server (GPL)',
|
||||
],
|
||||
71003,
|
||||
false,
|
||||
false,
|
||||
],
|
||||
[
|
||||
[
|
||||
'@@version' => '5.5.0',
|
||||
'@@version_comment' => '',
|
||||
],
|
||||
50500,
|
||||
false,
|
||||
false,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,6 +72,14 @@ class InsertEditTest extends AbstractTestCase
|
||||
$GLOBALS['cfg']['Confirm'] = true;
|
||||
$GLOBALS['cfg']['LoginCookieValidity'] = 1440;
|
||||
$GLOBALS['cfg']['enable_drag_drop_import'] = true;
|
||||
|
||||
if (! empty($GLOBALS['dbi'])) {
|
||||
$GLOBALS['dbi']->setVersion([
|
||||
'@@version' => '10.9.3-MariaDB-1:10.9.3+maria~ubu2204',
|
||||
'@@version_comment' => 'mariadb.org binary distribution',
|
||||
]);
|
||||
}
|
||||
|
||||
$this->insertEdit = new InsertEdit($GLOBALS['dbi']);
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Tests\Query;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Query\Compatibility;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
@ -35,4 +36,31 @@ class CompatibilityTest extends TestCase
|
||||
'MariaDB 10.4.3' => [true, true, 100403],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerForTestIsUUIDSupported
|
||||
*/
|
||||
public function testIsUUIDSupported(bool $expected, bool $isMariaDb, int $version): void
|
||||
{
|
||||
$dbiStub = $this->createStub(DatabaseInterface::class);
|
||||
|
||||
$dbiStub->method('isMariaDB')->willReturn($isMariaDb);
|
||||
$dbiStub->method('getVersion')->willReturn($version);
|
||||
|
||||
$this->assertSame($expected, Compatibility::isUUIDSupported($dbiStub));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, array{bool, bool, int}>
|
||||
*/
|
||||
public function providerForTestIsUUIDSupported(): array
|
||||
{
|
||||
return [
|
||||
'MySQL 5.7.5' => [false, false, 50705],
|
||||
'MySQL 8.0.30' => [false, false, 80030],
|
||||
'MariaDB 10.6.0' => [false, true, 100600],
|
||||
'MariaDB 10.7.0' => [true, true, 100700],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
1035
test/classes/TypesByDatabaseVersionTest.php
Normal file
1035
test/classes/TypesByDatabaseVersionTest.php
Normal file
File diff suppressed because it is too large
Load Diff
@ -309,6 +309,9 @@ class TypesTest extends AbstractTestCase
|
||||
['MULTILINESTRING'],
|
||||
['MULTIPOLYGON'],
|
||||
['GEOMETRYCOLLECTION'],
|
||||
['JSON'],
|
||||
['INET6'],
|
||||
['UUID'],
|
||||
];
|
||||
}
|
||||
|
||||
@ -367,7 +370,6 @@ class TypesTest extends AbstractTestCase
|
||||
'UNHEX',
|
||||
'UPPER',
|
||||
'USER',
|
||||
'UUID',
|
||||
'VERSION',
|
||||
],
|
||||
],
|
||||
@ -417,58 +419,57 @@ class TypesTest extends AbstractTestCase
|
||||
[
|
||||
'NUMBER',
|
||||
[
|
||||
'0' => 'ABS',
|
||||
'1' => 'ACOS',
|
||||
'2' => 'ASCII',
|
||||
'3' => 'ASIN',
|
||||
'4' => 'ATAN',
|
||||
'5' => 'BIT_LENGTH',
|
||||
'6' => 'BIT_COUNT',
|
||||
'7' => 'CEILING',
|
||||
'8' => 'CHAR_LENGTH',
|
||||
'9' => 'CONNECTION_ID',
|
||||
'10' => 'COS',
|
||||
'11' => 'COT',
|
||||
'12' => 'CRC32',
|
||||
'13' => 'DAYOFMONTH',
|
||||
'14' => 'DAYOFWEEK',
|
||||
'15' => 'DAYOFYEAR',
|
||||
'16' => 'DEGREES',
|
||||
'17' => 'EXP',
|
||||
'18' => 'FLOOR',
|
||||
'19' => 'HOUR',
|
||||
'20' => 'INET6_ATON',
|
||||
'21' => 'INET_ATON',
|
||||
'22' => 'LENGTH',
|
||||
'23' => 'LN',
|
||||
'24' => 'LOG',
|
||||
'25' => 'LOG2',
|
||||
'26' => 'LOG10',
|
||||
'27' => 'MICROSECOND',
|
||||
'28' => 'MINUTE',
|
||||
'29' => 'MONTH',
|
||||
'30' => 'OCT',
|
||||
'31' => 'ORD',
|
||||
'32' => 'PI',
|
||||
'33' => 'QUARTER',
|
||||
'34' => 'RADIANS',
|
||||
'35' => 'RAND',
|
||||
'36' => 'ROUND',
|
||||
'37' => 'SECOND',
|
||||
'38' => 'SIGN',
|
||||
'39' => 'SIN',
|
||||
'40' => 'SQRT',
|
||||
'41' => 'TAN',
|
||||
'42' => 'TO_DAYS',
|
||||
'43' => 'TO_SECONDS',
|
||||
'44' => 'TIME_TO_SEC',
|
||||
'45' => 'UNCOMPRESSED_LENGTH',
|
||||
'46' => 'UNIX_TIMESTAMP',
|
||||
'47' => 'UUID_SHORT',
|
||||
'48' => 'WEEK',
|
||||
'49' => 'WEEKDAY',
|
||||
'50' => 'WEEKOFYEAR',
|
||||
'51' => 'YEARWEEK',
|
||||
'ABS',
|
||||
'ACOS',
|
||||
'ASCII',
|
||||
'ASIN',
|
||||
'ATAN',
|
||||
'BIT_LENGTH',
|
||||
'BIT_COUNT',
|
||||
'CEILING',
|
||||
'CHAR_LENGTH',
|
||||
'CONNECTION_ID',
|
||||
'COS',
|
||||
'COT',
|
||||
'CRC32',
|
||||
'DAYOFMONTH',
|
||||
'DAYOFWEEK',
|
||||
'DAYOFYEAR',
|
||||
'DEGREES',
|
||||
'EXP',
|
||||
'FLOOR',
|
||||
'HOUR',
|
||||
'INET6_ATON',
|
||||
'INET_ATON',
|
||||
'LENGTH',
|
||||
'LN',
|
||||
'LOG',
|
||||
'LOG2',
|
||||
'LOG10',
|
||||
'MICROSECOND',
|
||||
'MINUTE',
|
||||
'MONTH',
|
||||
'OCT',
|
||||
'ORD',
|
||||
'PI',
|
||||
'QUARTER',
|
||||
'RADIANS',
|
||||
'RAND',
|
||||
'ROUND',
|
||||
'SECOND',
|
||||
'SIGN',
|
||||
'SIN',
|
||||
'SQRT',
|
||||
'TAN',
|
||||
'TO_DAYS',
|
||||
'TO_SECONDS',
|
||||
'TIME_TO_SEC',
|
||||
'UNCOMPRESSED_LENGTH',
|
||||
'UNIX_TIMESTAMP',
|
||||
'WEEK',
|
||||
'WEEKDAY',
|
||||
'WEEKOFYEAR',
|
||||
'YEARWEEK',
|
||||
],
|
||||
],
|
||||
[
|
||||
@ -517,7 +518,6 @@ class TypesTest extends AbstractTestCase
|
||||
'UNHEX',
|
||||
'UPPER',
|
||||
'USER',
|
||||
'UUID',
|
||||
'VERSION',
|
||||
],
|
||||
$this->object->getFunctions('enum')
|
||||
@ -640,8 +640,6 @@ class TypesTest extends AbstractTestCase
|
||||
'UTC_DATE',
|
||||
'UTC_TIME',
|
||||
'UTC_TIMESTAMP',
|
||||
'UUID',
|
||||
'UUID_SHORT',
|
||||
'VERSION',
|
||||
'WEEK',
|
||||
'WEEKDAY',
|
||||
@ -778,6 +776,14 @@ class TypesTest extends AbstractTestCase
|
||||
'SET',
|
||||
'CHAR',
|
||||
],
|
||||
[
|
||||
'JSON',
|
||||
'JSON',
|
||||
],
|
||||
[
|
||||
'UUID',
|
||||
'UUID',
|
||||
],
|
||||
[
|
||||
'UNKNOWN',
|
||||
'',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user