Skip to content

Commit ba02d77

Browse files
committed
Merge branch 'QA_5_2'
Signed-off-by: Maurício Meneghini Fauth <mauricio@fauth.dev>
2 parents 85be7db + d0215d3 commit ba02d77

5 files changed

Lines changed: 168 additions & 10 deletions

File tree

ChangeLog

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ phpMyAdmin - ChangeLog
4040
- issue #17736 Add utf8mb3 as an alias of utf8 on the charset description page
4141
- issue #16418 Fix FAQ 1.44 about manually removing vendor folders
4242
- issue #12359 Setup page now sends the Content-Security-Policy headers
43+
- issue #17747 The Column Visibility Toggle will not be hidden by other elements
44+
- issue #17756 Edit/Copy/Delete row now works when using GROUP BY
4345

4446
5.2.0 (2022-05-10)
4547
- issue #16521 Upgrade Bootstrap to version 5

libraries/classes/FieldMetadata.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,13 +227,22 @@ final class FieldMetadata
227227

228228
public function __construct(int $fieldType, int $fieldFlags, object $field)
229229
{
230+
$this->mappedType = $this->getTypeMap()[$fieldType] ?? null;
231+
230232
$this->isMultipleKey = (bool) ($fieldFlags & MYSQLI_MULTIPLE_KEY_FLAG);
231233
$this->isPrimaryKey = (bool) ($fieldFlags & MYSQLI_PRI_KEY_FLAG);
232234
$this->isUniqueKey = (bool) ($fieldFlags & MYSQLI_UNIQUE_KEY_FLAG);
233235
$this->isNotNull = (bool) ($fieldFlags & MYSQLI_NOT_NULL_FLAG);
234236
$this->isUnsigned = (bool) ($fieldFlags & MYSQLI_UNSIGNED_FLAG);
235237
$this->isZerofill = (bool) ($fieldFlags & MYSQLI_ZEROFILL_FLAG);
236-
$this->isNumeric = (bool) ($fieldFlags & MYSQLI_NUM_FLAG);
238+
239+
// as flags 32768 can be NUM_FLAG or GROUP_FLAG
240+
// reference: https://www.php.net/manual/en/mysqli-result.fetch-fields.php
241+
// so check field type instead of flags
242+
// but if no or unknown field type then check flags
243+
$this->isNumeric = $this->isType(self::TYPE_INT)
244+
|| ($fieldType <= 0 && ($fieldFlags & MYSQLI_NUM_FLAG));
245+
237246
$this->isBlob = (bool) ($fieldFlags & MYSQLI_BLOB_FLAG);
238247
$this->isEnum = (bool) ($fieldFlags & MYSQLI_ENUM_FLAG);
239248
$this->isSet = (bool) ($fieldFlags & MYSQLI_SET_FLAG);
@@ -244,8 +253,6 @@ public function __construct(int $fieldType, int $fieldFlags, object $field)
244253
MYSQLI_AUTO_INCREMENT_FLAG => 'auto_increment',
245254
*/
246255

247-
$this->mappedType = $this->getTypeMap()[$fieldType] ?? null;
248-
249256
$this->isMappedTypeBit = $this->isType(self::TYPE_BIT);
250257
$this->isMappedTypeGeometry = $this->isType(self::TYPE_GEOMETRY);
251258
$this->isMappedTypeTimestamp = $this->isType(self::TYPE_TIMESTAMP);

libraries/classes/Util.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -824,11 +824,7 @@ private static function getConditionValue(
824824
$isBinaryString = $meta->isType(FieldMetadata::TYPE_STRING) && $meta->isBinary();
825825
// 63 is the binary charset, see: https://dev.mysql.com/doc/internals/en/charsets.html
826826
$isBlobAndIsBinaryCharset = $meta->isType(FieldMetadata::TYPE_BLOB) && $meta->charsetnr === 63;
827-
// timestamp is numeric on some MySQL 4.1
828-
// for real we use CONCAT above and it should compare to string
829-
// See commit: 049fc7fef7548c2ba603196937c6dcaf9ff9bf00
830-
// See bug: https://sourceforge.net/p/phpmyadmin/bugs/3064/
831-
if ($meta->isNumeric && ! $meta->isMappedTypeTimestamp && $meta->isNotType(FieldMetadata::TYPE_REAL)) {
827+
if ($meta->isNumeric) {
832828
$conditionValue = '= ' . $row;
833829
} elseif ($isBlobAndIsBinaryCharset || (! empty($row) && $isBinaryString)) {
834830
// hexify only if this is a true not empty BLOB or a BINARY
@@ -860,7 +856,7 @@ private static function getConditionValue(
860856
. self::printableBitValue((int) $row, (int) $meta->length) . "'";
861857
} else {
862858
$conditionValue = '= \''
863-
. $GLOBALS['dbi']->escapeString($row) . '\'';
859+
. $GLOBALS['dbi']->escapeString((string) $row) . '\'';
864860
}
865861

866862
return [$conditionValue, $condition];

test/classes/FieldMetadataTest.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use const MYSQLI_BLOB_FLAG;
1111
use const MYSQLI_NUM_FLAG;
1212
use const MYSQLI_TYPE_FLOAT;
13+
use const MYSQLI_TYPE_INT24;
1314
use const MYSQLI_TYPE_STRING;
1415

1516
/**
@@ -88,6 +89,23 @@ public function testIsBinary(): void
8889
}
8990

9091
public function testIsNumeric(): void
92+
{
93+
$fm = new FieldMetadata(MYSQLI_TYPE_INT24, MYSQLI_NUM_FLAG, (object) []);
94+
$this->assertSame('int', $fm->getMappedType());
95+
$this->assertFalse($fm->isBinary());
96+
$this->assertFalse($fm->isEnum());
97+
$this->assertFalse($fm->isUniqueKey());
98+
$this->assertFalse($fm->isUnsigned());
99+
$this->assertFalse($fm->isZerofill());
100+
$this->assertFalse($fm->isSet());
101+
$this->assertFalse($fm->isNotNull());
102+
$this->assertFalse($fm->isPrimaryKey());
103+
$this->assertFalse($fm->isMultipleKey());
104+
$this->assertTrue($fm->isNumeric());
105+
$this->assertFalse($fm->isBlob());
106+
}
107+
108+
public function testIsNumericForUnknownFieldType(): void
91109
{
92110
$fm = new FieldMetadata(-1, MYSQLI_NUM_FLAG, (object) []);
93111
$this->assertSame('', $fm->getMappedType());
@@ -134,7 +152,7 @@ public function testIsNumericFloat(): void
134152
$this->assertFalse($fm->isNotNull());
135153
$this->assertFalse($fm->isPrimaryKey());
136154
$this->assertFalse($fm->isMultipleKey());
137-
$this->assertTrue($fm->isNumeric());
155+
$this->assertFalse($fm->isNumeric());
138156
$this->assertFalse($fm->isBlob());
139157
}
140158
}

test/classes/UtilTest.php

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
use const MYSQLI_TYPE_STRING;
3939
use const MYSQLI_UNIQUE_KEY_FLAG;
4040

41+
const FIELD_TYPE_INTEGER = 1;
42+
const FIELD_TYPE_VARCHAR = 253;
43+
const FIELD_TYPE_UNKNOWN = -1;
44+
4145
/**
4246
* @covers \PhpMyAdmin\Util
4347
*/
@@ -253,6 +257,137 @@ public function testGetUniqueConditionWithUniqueKey(): void
253257
$this->assertEquals(['`table`.`id` = \'unique\'', true, ['`table`.`id`' => '= \'unique\'']], $actual);
254258
}
255259

260+
/**
261+
* Test for Util::getUniqueCondition
262+
* note: GROUP_FLAG = MYSQLI_NUM_FLAG = 32769
263+
*
264+
* @param FieldMetadata[] $meta Meta Information for Field
265+
* @param array $row Current Ddata Row
266+
* @param array $expected Expected Result
267+
* @psalm-param array<int, mixed> $row
268+
* @psalm-param array{string, bool, array<string, string>} $expected
269+
*
270+
* @dataProvider providerGetUniqueConditionForGroupFlag
271+
*/
272+
public function testGetUniqueConditionForGroupFlag(array $meta, array $row, array $expected): void
273+
{
274+
$GLOBALS['dbi'] = $this->createDatabaseInterface();
275+
276+
$fieldsCount = count($meta);
277+
$actual = Util::getUniqueCondition($fieldsCount, $meta, $row);
278+
279+
$this->assertEquals($expected, $actual);
280+
}
281+
282+
/**
283+
* Provider for testGetUniqueConditionForGroupFlag
284+
*
285+
* @return array<string, array{FieldMetadata[], array<int, mixed>, array{string, bool, array<string, string>}}>
286+
*/
287+
public function providerGetUniqueConditionForGroupFlag(): array
288+
{
289+
return [
290+
'field type is integer, value is number - not escape string' => [
291+
[
292+
new FieldMetadata(FIELD_TYPE_INTEGER, MYSQLI_NUM_FLAG, (object) [
293+
'name' => 'col',
294+
'table' => 'table',
295+
'orgtable' => 'table',
296+
]),
297+
],
298+
[123],
299+
[
300+
'`table`.`col` = 123',
301+
false,
302+
['`table`.`col`' => '= 123'],
303+
],
304+
],
305+
'field type is unknown, value is string - not escape string' => [
306+
[
307+
new FieldMetadata(FIELD_TYPE_UNKNOWN, MYSQLI_NUM_FLAG, (object) [
308+
'name' => 'col',
309+
'table' => 'table',
310+
'orgtable' => 'table',
311+
]),
312+
],
313+
['test'],
314+
[
315+
'`table`.`col` = test',
316+
false,
317+
['`table`.`col`' => '= test'],
318+
],
319+
],
320+
'field type is varchar, value is string - escape string' => [
321+
[
322+
new FieldMetadata(FIELD_TYPE_VARCHAR, MYSQLI_NUM_FLAG, (object) [
323+
'name' => 'col',
324+
'table' => 'table',
325+
'orgtable' => 'table',
326+
]),
327+
],
328+
['test'],
329+
[
330+
"`table`.`col` = 'test'",
331+
false,
332+
['`table`.`col`' => "= 'test'"],
333+
],
334+
],
335+
'field type is varchar, value is string with double quote - escape string' => [
336+
[
337+
new FieldMetadata(FIELD_TYPE_VARCHAR, MYSQLI_NUM_FLAG, (object) [
338+
'name' => 'col',
339+
'table' => 'table',
340+
'orgtable' => 'table',
341+
]),
342+
],
343+
['"test"'],
344+
[
345+
"`table`.`col` = '\\\"test\\\"'",
346+
false,
347+
['`table`.`col`' => "= '\\\"test\\\"'"],
348+
],
349+
],
350+
'field type is varchar, value is string with single quote - escape string' => [
351+
[
352+
new FieldMetadata(FIELD_TYPE_VARCHAR, MYSQLI_NUM_FLAG, (object) [
353+
'name' => 'col',
354+
'table' => 'table',
355+
'orgtable' => 'table',
356+
]),
357+
],
358+
["'test'"],
359+
[
360+
"`table`.`col` = '\'test\''",
361+
false,
362+
['`table`.`col`' => "= '\'test\''"],
363+
],
364+
],
365+
'group by multiple columns and field type is mixed' => [
366+
[
367+
new FieldMetadata(FIELD_TYPE_VARCHAR, MYSQLI_NUM_FLAG, (object) [
368+
'name' => 'col',
369+
'table' => 'table',
370+
'orgtable' => 'table',
371+
]),
372+
new FieldMetadata(FIELD_TYPE_INTEGER, MYSQLI_NUM_FLAG, (object) [
373+
'name' => 'status_id',
374+
'table' => 'table',
375+
'orgtable' => 'table',
376+
]),
377+
],
378+
['test', 2],
379+
[
380+
"`table`.`col` = 'test' AND `table`.`status_id` = 2",
381+
false,
382+
[
383+
'`table`.`col`' => "= 'test'",
384+
'`table`.`status_id`' => '= 2',
385+
],
386+
],
387+
],
388+
];
389+
}
390+
256391
/**
257392
* Test for Page Selector
258393
*/

0 commit comments

Comments
 (0)