Merge branch 'QA_5_1'

Signed-off-by: William Desportes <williamdes@wdes.fr>
This commit is contained in:
William Desportes 2021-05-31 17:09:04 +02:00
commit 919ce3975f
No known key found for this signature in database
GPG Key ID: 90A0EF1B8251A889
8 changed files with 208 additions and 40 deletions

View File

@ -54,6 +54,8 @@ jobs:
db-server: ["mysql:5.7"]
steps:
- uses: actions/checkout@v2
- name: Refresh apt cache
run: sudo apt-get update
- name: Install gettext
run: sudo apt-get install -y gettext
- name: Generate mo files

View File

@ -121,6 +121,8 @@ phpMyAdmin - ChangeLog
- issue #16920 Fixed "Uncaught TypeError: PhpMyAdmin\Import::detectType()" on ODS import
- issue #16926 Fixed ODS import warning: Undefined array key "ods_empty_rows"
- issue #16888 Fixed JS error on renaming tables in saved Designer page
- issue #16504 Fixed create view dialog is too big and won't scroll (on small screens)
- issue #16931 Fixed php notice "Undefined index: utf8mb3" on MySQL 8.0.11+ servers with default utf8 server charset
5.1.0 (2021-02-24)
- issue #15350 Change Media (MIME) type references to Media type

View File

@ -4565,6 +4565,7 @@ Functions.createViewDialog = function ($this) {
var $dialog = $('<div></div>').attr('id', 'createViewDialog').append(data.message).dialog({
width: 600,
minWidth: 400,
height: $(window).height(),
modal: true,
buttons: buttonOptions,
title: Messages.strCreateView,

View File

@ -159,7 +159,28 @@ class Charsets
$serverCharset = $dbi->fetchValue('SELECT @@character_set_server;');
}
self::$serverCharset = self::$charsets[$serverCharset];
self::$serverCharset = self::$charsets[$serverCharset] ?? null;
// MySQL 8.0.11+ fallback, issue #16931
if (self::$serverCharset === null && $serverCharset === 'utf8mb3') {
// See: https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-11.html#mysqld-8-0-11-charset
// The utf8mb3 character set will be replaced by utf8mb4 in a future MySQL version.
// The utf8 character set is currently an alias for utf8mb3,
// but will at that point become a reference to utf8mb4.
// To avoid ambiguity about the meaning of utf8,
// consider specifying utf8mb4 explicitly for character set references instead of utf8.
// Warning: #3719 'utf8' is currently an alias for the character set UTF8MB3 [...]
return self::$charsets['utf8'];
}
if (self::$serverCharset === null) {// Fallback in case nothing is found
return Charset::fromServer(
[
'Charset' => __('Unknown'),
'Description' => __('Unknown'),
]
);
}
return self::$serverCharset;
}

View File

@ -39,6 +39,20 @@ abstract class AbstractTestCase extends TestCase
'__PHPUNIT_BOOTSTRAP',
];
/**
* The DatabaseInterface loaded by setGlobalDbi
*
* @var DatabaseInterface
*/
protected $dbi;
/**
* The DbiDummy loaded by setGlobalDbi
*
* @var DbiDummy
*/
protected $dummyDbi;
/**
* Prepares environment for the test.
* Clean all variables
@ -126,7 +140,9 @@ abstract class AbstractTestCase extends TestCase
protected function setGlobalDbi(): void
{
global $dbi;
$dbi = DatabaseInterface::load(new DbiDummy());
$this->dummyDbi = new DbiDummy();
$this->dbi = DatabaseInterface::load($this->dummyDbi);
$dbi = $this->dbi;
}
protected function setGlobalConfig(): void

View File

@ -17,11 +17,65 @@ class CharsetsTest extends AbstractTestCase
protected function setUp(): void
{
parent::setUp();
parent::setGlobalDbi();
$GLOBALS['server'] = 0;
$GLOBALS['cfg']['DBG']['sql'] = false;
$GLOBALS['cfg']['Server']['DisableIS'] = false;
}
public function testGetServerCharset(): void
{
$this->dummyDbi->addResult(
'SHOW SESSION VARIABLES LIKE \'character_set_server\';',
[
[
'character_set_server',
'utf8mb3',
],
],
[
'Variable_name',
'Value',
]
);
$this->dummyDbi->addResult(
'SHOW SESSION VARIABLES LIKE \'character_set_server\';',
false
);
$this->dummyDbi->addResult(
'SELECT @@character_set_server;',
false
);
$this->dummyDbi->addResult(
'SHOW SESSION VARIABLES LIKE \'character_set_server\';',
false
);
$this->dummyDbi->addResult(
'SELECT @@character_set_server;',
[
['utf8mb3'],
]
);
$charset = Charsets::getServerCharset(
$GLOBALS['dbi'],
$GLOBALS['cfg']['Server']['DisableIS']
);
$this->assertSame('utf8', $charset->getName());
$charset = Charsets::getServerCharset(
$GLOBALS['dbi'],
$GLOBALS['cfg']['Server']['DisableIS']
);
$this->assertSame('Unknown', $charset->getName());
$charset = Charsets::getServerCharset(
$GLOBALS['dbi'],
$GLOBALS['cfg']['Server']['DisableIS']
);
$this->assertSame('utf8', $charset->getName());
}
public function testFindCollationByName(): void
{
$this->assertNull(Charsets::findCollationByName(

View File

@ -20,9 +20,6 @@ use stdClass;
*/
class DatabaseInterfaceTest extends AbstractTestCase
{
/** @var DatabaseInterface */
private $dbi;
/**
* Configures test parameters.
*/
@ -47,20 +44,19 @@ class DatabaseInterfaceTest extends AbstractTestCase
public function testGetCurrentUser($value, string $string, array $expected): void
{
SessionCache::remove('mysql_cur_user');
parent::setGlobalDbi();
$extension = new DbiDummy();
$extension->setResult('SELECT CURRENT_USER();', $value);
$dbi = new DatabaseInterface($extension);
$this->dummyDbi->addResult('SELECT CURRENT_USER();', $value);
$this->dummyDbi->addResult('SELECT CURRENT_USER();', $value);
$this->assertEquals(
$expected,
$dbi->getCurrentUserAndHost()
$this->dbi->getCurrentUserAndHost()
);
$this->assertEquals(
$string,
$dbi->getCurrentUser()
$this->dbi->getCurrentUser()
);
}
@ -277,15 +273,13 @@ class DatabaseInterfaceTest extends AbstractTestCase
public function testIsAmazonRdsData(array $value, bool $expected): void
{
SessionCache::remove('is_amazon_rds');
parent::setGlobalDbi();
$extension = new DbiDummy();
$extension->setResult('SELECT @@basedir', $value);
$dbi = new DatabaseInterface($extension);
$this->dummyDbi->addResult('SELECT @@basedir', $value);
$this->assertEquals(
$expected,
$dbi->isAmazonRds()
$this->dbi->isAmazonRds()
);
}

View File

@ -38,8 +38,34 @@ use const MYSQLI_TYPE_STRING;
*/
class DbiDummy implements DbiExtension
{
/** @var array */
private $queries = [];
/**
* First in, last out queries
*
* The results will be distributed in the filo way
*
* @var array
* @phpstan-var array{
* 'query': string,
* 'result': ((int[]|string[]|array{string: string})[])|bool|empty-array,
* 'columns'?: string[],
* 'metadata'?: object[]|empty-array,
* 'used'?: bool,
* 'pos'?: int
* }[]
*/
private $filoQueries = [];
/**
* @var array
* @phpstan-var array{
* 'query': string,
* 'result': ((int[]|string[]|array{string: string})[])|bool|empty-array,
* 'columns'?: string[],
* 'metadata'?: object[]|empty-array,
* 'pos'?: int
* }[]
*/
private $dummyQueries = [];
public const OFFSET_GLOBAL = 1000;
@ -80,6 +106,33 @@ class DbiDummy implements DbiExtension
return true;
}
/**
* @return false|int|null
*/
private function findFiloQuery(string $query)
{
for ($i = 0, $nb = count($this->filoQueries); $i < $nb; $i++) {
if ($this->filoQueries[$i]['query'] !== $query) {
continue;
}
if ($this->filoQueries[$i]['used'] ?? false) {
continue;// Is has already been used
}
$this->filoQueries[$i]['pos'] = 0;
$this->filoQueries[$i]['used'] = true;
if (! is_array($this->filoQueries[$i]['result'])) {
return false;
}
return $i;
}
return null;
}
/**
* runs a query and returns the result
*
@ -92,26 +145,18 @@ class DbiDummy implements DbiExtension
public function realQuery($query, $link = null, $options = 0)
{
$query = trim((string) preg_replace('/ */', ' ', str_replace("\n", ' ', $query)));
for ($i = 0, $nb = count($this->queries); $i < $nb; $i++) {
if ($this->queries[$i]['query'] != $query) {
continue;
}
$this->queries[$i]['pos'] = 0;
if (! is_array($this->queries[$i]['result'])) {
return false;
}
return $i;
$filoQuery = $this->findFiloQuery($query);
if ($filoQuery !== null) {// Found a matching query
return $filoQuery;
}
for ($i = 0, $nb = count($GLOBALS['dummy_queries']); $i < $nb; $i++) {
if ($GLOBALS['dummy_queries'][$i]['query'] != $query) {
for ($i = 0, $nb = count($this->dummyQueries); $i < $nb; $i++) {
if ($this->dummyQueries[$i]['query'] !== $query) {
continue;
}
$GLOBALS['dummy_queries'][$i]['pos'] = 0;
if (! is_array($GLOBALS['dummy_queries'][$i]['result'])) {
$this->dummyQueries[$i]['pos'] = 0;
if (! is_array($this->dummyQueries[$i]['result'])) {
return false;
}
@ -437,16 +482,21 @@ class DbiDummy implements DbiExtension
/**
* Adds query result for testing
*
* @param string $query SQL
* @param array|false $result Expected result
* @param string $query SQL
* @param array|bool $result Expected result
* @param string[] $columns The result columns
* @param object[] $metadata The result metadata
* @phpstan-param (int[]|string[]|array{string: string})[]|bool $result
*
* @return void
*/
public function setResult($query, $result)
public function addResult(string $query, $result, array $columns = [], array $metadata = [])
{
$this->queries[] = [
$this->filoQueries[] = [
'query' => $query,
'result' => $result,
'columns' => $columns,
'metadata' => $metadata,
];
}
@ -476,10 +526,10 @@ class DbiDummy implements DbiExtension
}
if ($result >= self::OFFSET_GLOBAL) {
return $GLOBALS['dummy_queries'][$result - self::OFFSET_GLOBAL];
return $this->dummyQueries[$result - self::OFFSET_GLOBAL];
}
return $this->queries[$result];
return $this->filoQueries[$result];
}
private function init(): void
@ -487,7 +537,7 @@ class DbiDummy implements DbiExtension
/**
* Array of queries this "driver" supports
*/
$GLOBALS['dummy_queries'] = [
$this->dummyQueries = [
[
'query' => 'SELECT 1',
'result' => [['1']],
@ -817,12 +867,24 @@ class DbiDummy implements DbiExtension
'Maxlen',
],
'result' => [
[
'armscii8',
'ARMSCII-8 Armenian',
'armscii8_general_ci',
'1',
],
[
'utf8',
'utf8_general_ci',
'UTF-8 Unicode',
'3',
],
[
'utf8mb4',
'UTF-8 Unicode',
'utf8mb4_0900_ai_ci',
'4',
],
[
'latin1',
'latin1_swedish_ci',
@ -848,6 +910,22 @@ class DbiDummy implements DbiExtension
'Sortlen',
],
'result' => [
[
'utf8mb4_general_ci',
'utf8mb4',
'45',
'Yes',
'Yes',
'1',
],
[
'armscii8_general_ci',
'armscii8',
'32',
'Yes',
'Yes',
'1',
],
[
'utf8_general_ci',
'utf8',