Fix #20284 - Preserve numeric strings in XML imports

When the XML file embeds the table structure, $analyses is null and
buildSql() falls back to is_numeric() to decide whether to quote. That
strips quotes from values like "01234", which silently drops the leading
zero on a varchar column and causes a duplicate-key error if the table
also contains "1234".

Add a roundtrip check: a value is still treated as numeric only when
casting it to int or float gives back the original string. "01234",
"1e10" and similar fail the roundtrip and stay quoted; plain integers
like 1 and 1234 keep their existing unquoted form.

Signed-off-by: Eyüp Can Akman <eyupcanakman@gmail.com>
This commit is contained in:
Eyüp Can Akman 2026-04-27 16:47:18 +03:00
parent 9b467fd4ef
commit ce12a87858
No known key found for this signature in database
4 changed files with 101 additions and 9 deletions

View File

@ -1176,20 +1176,24 @@ class Import
) {
$tempSQLStr .= (string) $tables[$i][self::ROWS][$j][$k];
} else {
$value = (string) $tables[$i][self::ROWS][$j][$k];
if ($analyses != null) {
$isVarchar = ($analyses[$i][self::TYPES][$colCount] === self::VARCHAR);
} else {
$isVarchar = ! is_numeric($tables[$i][self::ROWS][$j][$k])
&& ! preg_match('/^0x[0-9a-f]+$/', (string) $tables[$i][self::ROWS][$j][$k]);
$isVarchar = ! preg_match('/^0x[0-9a-f]+$/', $value)
&& (
! is_numeric($value)
|| ($value !== (string) (int) $value && $value !== (string) (float) $value)
);
}
/* Don't put quotes around NULL fields */
if (! strcmp((string) $tables[$i][self::ROWS][$j][$k], 'NULL')) {
if (! strcmp($value, 'NULL')) {
$isVarchar = false;
}
$tempSQLStr .= $isVarchar ? "'" : '';
$tempSQLStr .= $dbi->escapeString((string) $tables[$i][self::ROWS][$j][$k]);
$tempSQLStr .= $dbi->escapeString($value);
$tempSQLStr .= $isVarchar ? "'" : '';
}

View File

@ -20192,12 +20192,12 @@ parameters:
-
message: "#^Cannot access offset 2 on mixed\\.$#"
count: 9
count: 6
path: libraries/classes/Import.php
-
message: "#^Cannot access offset int\\<0, max\\> on mixed\\.$#"
count: 22
count: 17
path: libraries/classes/Import.php
-
@ -20247,7 +20247,7 @@ parameters:
-
message: "#^Cannot cast mixed to string\\.$#"
count: 8
count: 6
path: libraries/classes/Import.php
-
@ -46857,12 +46857,12 @@ parameters:
-
message: "#^Dynamic call to static method PHPUnit\\\\Framework\\\\TestCase\\:\\:any\\(\\)\\.$#"
count: 3
count: 4
path: test/classes/Plugins/Import/ImportXmlTest.php
-
message: "#^Dynamic call to static method PHPUnit\\\\Framework\\\\TestCase\\:\\:returnArgument\\(\\)\\.$#"
count: 3
count: 4
path: test/classes/Plugins/Import/ImportXmlTest.php
-

View File

@ -181,6 +181,51 @@ SQL;
self::assertTrue($GLOBALS['finished']);
}
/**
* Test for doImport with numeric-looking string values
*
* @group medium
* @requires extension simplexml
*/
public function testDoImportNumericStringValues(): void
{
global $sql_query;
$dbi = $this->getMockBuilder(DatabaseInterface::class)
->disableOriginalConstructor()
->getMock();
$dbi->expects($this->any())->method('escapeString')
->will($this->returnArgument(0));
$GLOBALS['dbi'] = $dbi;
$GLOBALS['import_file'] = 'test/test_data/phpmyadmin_importXML_Numeric_String_For_Testing.xml';
$importHandle = new File($GLOBALS['import_file']);
$importHandle->open();
$this->object->doImport($importHandle);
$expectedQuery = <<<'SQL'
CREATE DATABASE IF NOT EXISTS `testdata` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;;USE `testdata`;
CREATE TABLE IF NOT EXISTS `test_data` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`data` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `data` (`data`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
;INSERT INTO `testdata`.`test_data` (`id`, `data`) VALUES (3, '01234'),
(2, 1234),
(1, 'abcd');;
SQL;
self::assertSame(
$expectedQuery,
$sql_query
);
self::assertTrue($GLOBALS['finished']);
}
/**
* Test for doImport using no database dataset
*

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- phpMyAdmin XML Dump FOR testing
- version 4.1-dev
- https://www.phpmyadmin.net
-->
<pma_xml_export version="1.0" xmlns:pma="https://www.phpmyadmin.net/some_doc_url/">
<!--
- Structure schemas
-->
<pma:structure_schemas>
<pma:database name="testdata" collation="utf8_bin" charset="utf8">
<pma:table name="test_data">
CREATE TABLE `test_data` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`data` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `data` (`data`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
</pma:table>
</pma:database>
</pma:structure_schemas>
<!--
- Database: 'testdata'
-->
<database name="testdata">
<!-- Table test_data -->
<table name="test_data">
<column name="id">3</column>
<column name="data">01234</column>
</table>
<table name="test_data">
<column name="id">2</column>
<column name="data">1234</column>
</table>
<table name="test_data">
<column name="id">1</column>
<column name="data">abcd</column>
</table>
</database>
</pma_xml_export>