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:
parent
9b467fd4ef
commit
ce12a87858
@ -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 ? "'" : '';
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
-
|
||||
|
||||
@ -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
|
||||
*
|
||||
|
||||
@ -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>
|
||||
Loading…
Reference in New Issue
Block a user