diff --git a/ChangeLog b/ChangeLog index 94573dafde..763f046036 100644 --- a/ChangeLog +++ b/ChangeLog @@ -77,6 +77,11 @@ phpMyAdmin - ChangeLog - issue #16842 Fixed missing password modes on PerconaDB - issue #16947 Fix "Change login information" form not working - issue #17004 Fix Advisor for MariaDB >= 10.5 because of removed "innodb_log_files_in_group" variable +- issue #17037 Fix change structure does not surface errors +- issue #17016 Fixed online Transaction, errors not reported on structure edit +- issue #17042 Fix SQL escaping bug on DB name with special chars on submit query with rollback option +- issue #17027 Better handle the display of sorted binary columns in results summary +- issue #16398 Quote non numeric values on parameterized queries 5.1.1 (2021-06-04) - issue #13325 Fixed created procedure shows up in triggers and events and vice-versa diff --git a/libraries/advisory_rules_generic.php b/libraries/advisory_rules_generic.php index a9d6fc0e6d..6a65948e68 100644 --- a/libraries/advisory_rules_generic.php +++ b/libraries/advisory_rules_generic.php @@ -642,7 +642,7 @@ return [ // From MariaDB 10.5, there is 1 redo log. // For MariaDB 10.4 and before, the number of redo log files is configured // by the innodb_log_files_in_group system variable. - 'formula' => '(innodb_log_file_size * 1)/ innodb_buffer_pool_size * 100', + 'formula' => 'innodb_log_file_size / innodb_buffer_pool_size * 100', 'test' => 'value < 20 && innodb_log_file_size / (1024 * 1024) < 256', 'issue' => __( 'The InnoDB log file size is not an appropriate size, in relation to the InnoDB buffer pool.' diff --git a/libraries/classes/Controllers/ImportController.php b/libraries/classes/Controllers/ImportController.php index bb475fb9d7..2b751d8b52 100644 --- a/libraries/classes/Controllers/ImportController.php +++ b/libraries/classes/Controllers/ImportController.php @@ -34,6 +34,7 @@ use function ini_set; use function intval; use function is_array; use function is_link; +use function is_numeric; use function is_uploaded_file; use function mb_strlen; use function mb_strtolower; @@ -176,17 +177,22 @@ final class ImportController extends AbstractController ) { $parameters = $_POST['parameters']; foreach ($parameters as $parameter => $replacement) { + $replacementValue = $this->dbi->escapeString($replacement); + if (! is_numeric($replacementValue)) { + $replacementValue = '\'' . $replacementValue . '\''; + } + $quoted = preg_quote($parameter, '/'); // making sure that :param does not apply values to :param1 $sql_query = preg_replace( '/' . $quoted . '([^a-zA-Z0-9_])/', - $this->dbi->escapeString($replacement) . '${1}', + $replacementValue . '${1}', $sql_query ); // for parameters the appear at the end of the string $sql_query = preg_replace( '/' . $quoted . '$/', - $this->dbi->escapeString($replacement), + $replacementValue, $sql_query ); } diff --git a/libraries/classes/Controllers/Table/StructureController.php b/libraries/classes/Controllers/Table/StructureController.php index 9f1dad2dc4..467a6a3d98 100644 --- a/libraries/classes/Controllers/Table/StructureController.php +++ b/libraries/classes/Controllers/Table/StructureController.php @@ -1220,11 +1220,11 @@ class StructureController extends AbstractController $this->dbi->query($revert_query); $this->response->setRequestStatus(false); - $this->response->addJSON( - 'message', - Message::rawError( - __('Query error') . ':
' . $orig_error - ) + $message = Message::rawError( + __('Query error') . ':
' . $orig_error + ); + $this->response->addHTML( + Generator::getMessage($message, $sql_query, 'error') ); $regenerate = true; } diff --git a/libraries/classes/Display/Results.php b/libraries/classes/Display/Results.php index f65b249675..c54a60c9c0 100644 --- a/libraries/classes/Display/Results.php +++ b/libraries/classes/Display/Results.php @@ -4296,9 +4296,10 @@ class Results // check for non printable sorted row data $meta = $fieldsMeta[$sortedColumnIndex]; - $isBlobOrGeometry = $meta->isType(FieldMetadata::TYPE_BLOB) || $meta->isMappedTypeGeometry; + $isBlobOrGeometryOrBinary = $meta->isType(FieldMetadata::TYPE_BLOB) + || $meta->isMappedTypeGeometry || $meta->isBinary; - if ($isBlobOrGeometry) { + if ($isBlobOrGeometryOrBinary) { $columnForFirstRow = $this->handleNonPrintableContents( $meta->getMappedType(), $row[$sortedColumnIndex], @@ -4328,7 +4329,7 @@ class Results // check for non printable sorted row data $meta = $fieldsMeta[$sortedColumnIndex]; - if ($isBlobOrGeometry) { + if ($isBlobOrGeometryOrBinary) { $columnForLastRow = $this->handleNonPrintableContents( $meta->getMappedType(), $row[$sortedColumnIndex], diff --git a/libraries/classes/Import.php b/libraries/classes/Import.php index 58ce392175..07e27a5816 100644 --- a/libraries/classes/Import.php +++ b/libraries/classes/Import.php @@ -1800,8 +1800,8 @@ class Import // Query to check if table is 'Transactional'. $checkQuery = 'SELECT `ENGINE` FROM `information_schema`.`tables` ' - . 'WHERE `table_name` = "' . $table . '" ' - . 'AND `table_schema` = "' . $db . '" ' + . 'WHERE `table_name` = "' . $dbi->escapeString($table) . '" ' + . 'AND `table_schema` = "' . $dbi->escapeString($db) . '" ' . 'AND UPPER(`engine`) IN ("' . implode('", "', $transactionalEngines) . '")'; diff --git a/test/classes/Controllers/ImportControllerTest.php b/test/classes/Controllers/ImportControllerTest.php new file mode 100644 index 0000000000..15eb998fb9 --- /dev/null +++ b/test/classes/Controllers/ImportControllerTest.php @@ -0,0 +1,73 @@ + 'Saint-Louis - Châteaulin', ':1' => '4']; + $_POST['sql_query'] = 'SELECT A.*' . "\n" + . 'FROM table1 A' . "\n" + . 'WHERE A.nomEtablissement = :nomEta AND foo = :1 AND `:a` IS NULL'; + $sql_query = $_POST['sql_query']; + + $this->dummyDbi->addResult( + 'SELECT A.* FROM table1 A WHERE A.nomEtablissement = \'Saint-Louis - Châteaulin\'' + . ' AND foo = 4 AND `:a` IS NULL LIMIT 0, 25', + [] + ); + + $this->dummyDbi->addResult( + 'SHOW CREATE TABLE `pma_test`.`table1`', + [] + ); + + $this->dummyDbi->addResult( + 'SHOW FULL COLUMNS FROM `pma_test`.`table1`', + [] + ); + + /** @var ImportController $importController */ + $importController = $containerBuilder->get(ImportController::class); + $importController->index(); + $this->assertResponseWasSuccessfull(); + + $this->assertStringContainsString( + 'MySQL returned an empty result set (i.e. zero rows).', + $this->getResponseHtmlResult() + ); + + $this->assertStringContainsString( + 'SELECT A.*' . "\n" . 'FROM table1 A' . "\n" + . 'WHERE A.nomEtablissement = \'Saint-Louis - Châteaulin\' AND foo = 4 AND `:a` IS NULL', + $this->getResponseHtmlResult() + ); + + $this->assertAllQueriesConsumed(); + } +}