Merge pull request #16322 from mauriciofauth/tbl-maint-pages

Create dedicated pages for table maintenance actions
This commit is contained in:
Maurício Meneghini Fauth 2020-08-31 15:11:59 -03:00 committed by GitHub
commit 5d5f149dd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 645 additions and 448 deletions

View File

@ -298,15 +298,15 @@ AJAX.registerOnload('database/structure.js', function () {
}
if (action === 'analyze_tbl') {
url = 'index.php?route=/database/structure/analyze-table';
url = 'index.php?route=/table/maintenance/analyze';
} else if (action === 'sync_unique_columns_central_list') {
url = 'index.php?route=/database/structure/central-columns-add';
} else if (action === 'delete_unique_columns_central_list') {
url = 'index.php?route=/database/structure/central-columns-remove';
} else if (action === 'check_tbl') {
url = 'index.php?route=/database/structure/check-table';
url = 'index.php?route=/table/maintenance/check';
} else if (action === 'checksum_tbl') {
url = 'index.php?route=/database/structure/checksum-table';
url = 'index.php?route=/table/maintenance/checksum';
} else if (action === 'drop_tbl') {
url = 'index.php?route=/database/structure/drop-form';
} else if (action === 'empty_tbl') {
@ -314,9 +314,9 @@ AJAX.registerOnload('database/structure.js', function () {
} else if (action === 'export') {
url = 'index.php?route=/database/structure/export';
} else if (action === 'optimize_tbl') {
url = 'index.php?route=/database/structure/optimize-table';
url = 'index.php?route=/table/maintenance/optimize';
} else if (action === 'repair_tbl') {
url = 'index.php?route=/database/structure/repair-table';
url = 'index.php?route=/table/maintenance/repair';
} else if (action === 'show_create') {
url = 'index.php?route=/database/structure/show-create';
} else {

View File

@ -112,7 +112,6 @@ class QueryByExampleController extends AbstractController
null, // sql_query_for_bookmark
null, // extra_data
null, // message_to_show
null, // message
null, // sql_data
$goto, // goto
$pmaThemeImage, // pmaThemeImage

View File

@ -12,7 +12,6 @@ use PhpMyAdmin\Config\PageSettings;
use PhpMyAdmin\Core;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Html\Generator;
use PhpMyAdmin\Index;
use PhpMyAdmin\Message;
use PhpMyAdmin\Operations;
use PhpMyAdmin\RecentFavoriteTable;
@ -1439,247 +1438,6 @@ class StructureController extends AbstractController
]);
}
public function checkTable(): void
{
global $db;
/** @var string[] $selected */
$selected = $_POST['selected_tbl'] ?? [];
if (empty($selected)) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', __('No table selected.'));
return;
}
$tables = Util::backquote($selected);
$query = 'CHECK TABLE ' . implode(', ', $tables) . ';';
$this->dbi->selectDb($db);
$rows = $this->dbi->fetchResult($query);
$message = Generator::getMessage(
__('Your SQL query has been executed successfully.'),
$query,
'success'
);
$indexesProblems = '';
foreach ($selected as $table) {
$check = Index::findDuplicates($table, $db);
if (empty($check)) {
continue;
}
$indexesProblems .= sprintf(__('Problems with indexes of table `%s`'), $table);
$indexesProblems .= $check;
}
$this->render('database/structure/check_table', [
'message' => $message,
'rows' => $rows,
'indexes_problems' => $indexesProblems,
]);
}
public function analyzeTable(): void
{
global $db, $goto, $pmaThemeImage;
$selected = $_POST['selected_tbl'] ?? [];
if (empty($selected)) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', __('No table selected.'));
return;
}
$sqlQuery = '';
$selectedCount = count($selected);
for ($i = 0; $i < $selectedCount; $i++) {
$sqlQuery .= (empty($sqlQuery) ? 'ANALYZE TABLE ' : ', ') . Util::backquote($selected[$i]);
}
$sql = new Sql();
$this->response->addHTML($sql->executeQueryAndSendQueryResponse(
null,
false,
$db,
'',
null,
null,
null,
null,
null,
null,
$goto,
$pmaThemeImage,
null,
null,
$sqlQuery,
null
));
if (empty($_POST['message'])) {
$_POST['message'] = Message::success();
}
unset($_POST['submit_mult']);
$this->index();
}
public function checksumTable(): void
{
global $db, $goto, $pmaThemeImage;
$selected = $_POST['selected_tbl'] ?? [];
if (empty($selected)) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', __('No table selected.'));
return;
}
$sql_query = '';
$selectedCount = count($selected);
for ($i = 0; $i < $selectedCount; $i++) {
$sql_query .= (empty($sql_query) ? 'CHECKSUM TABLE ' : ', ') . Util::backquote($selected[$i]);
}
$sql = new Sql();
$this->response->addHTML($sql->executeQueryAndSendQueryResponse(
null,
false,
$db,
'',
null,
null,
null,
null,
null,
null,
$goto,
$pmaThemeImage,
null,
null,
$sql_query,
null
));
if (empty($_POST['message'])) {
$_POST['message'] = Message::success();
}
unset($_POST['submit_mult']);
$this->index();
}
public function optimizeTable(): void
{
global $db, $goto, $pmaThemeImage;
$selected = $_POST['selected_tbl'] ?? [];
if (empty($selected)) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', __('No table selected.'));
return;
}
$sql_query = '';
$selectedCount = count($selected);
for ($i = 0; $i < $selectedCount; $i++) {
$sql_query .= (empty($sql_query) ? 'OPTIMIZE TABLE ' : ', ') . Util::backquote($selected[$i]);
}
$sql = new Sql();
$this->response->addHTML($sql->executeQueryAndSendQueryResponse(
null,
false,
$db,
'',
null,
null,
null,
null,
null,
null,
$goto,
$pmaThemeImage,
null,
null,
$sql_query,
null
));
if (empty($_POST['message'])) {
$_POST['message'] = Message::success();
}
unset($_POST['submit_mult']);
$this->index();
}
public function repairTable(): void
{
global $db, $goto, $pmaThemeImage;
$selected = $_POST['selected_tbl'] ?? [];
if (empty($selected)) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', __('No table selected.'));
return;
}
$sql_query = '';
$selectedCount = count($selected);
for ($i = 0; $i < $selectedCount; $i++) {
$sql_query .= (empty($sql_query) ? 'REPAIR TABLE ' : ', ') . Util::backquote($selected[$i]);
}
$sql = new Sql();
$this->response->addHTML($sql->executeQueryAndSendQueryResponse(
null,
false,
$db,
'',
null,
null,
null,
null,
null,
null,
$goto,
$pmaThemeImage,
null,
null,
$sql_query,
null
));
if (empty($_POST['message'])) {
$_POST['message'] = Message::success();
}
unset($_POST['submit_mult']);
$this->index();
}
public function dropTable(): void
{
global $db, $message, $reload, $sql_query;

View File

@ -806,7 +806,6 @@ final class ImportController extends AbstractController
null, // sql_query_for_bookmark - see below
null, // extra_data
null, // message_to_show
null, // message
null, // sql_data
$goto, // goto
$pmaThemeImage, // pmaThemeImage

View File

@ -53,7 +53,7 @@ class SqlController extends AbstractController
public function index(): void
{
global $cfg, $db, $display_query, $pmaThemeImage, $sql_query, $table, $message;
global $cfg, $db, $display_query, $pmaThemeImage, $sql_query, $table;
global $ajax_reload, $goto, $err_url, $find_real_end, $unlim_num_rows, $import_text, $disp_query;
global $extra_data, $message_to_show, $sql_data, $disp_message, $complete_query;
global $is_gotofile, $back, $table_from_sql;
@ -209,7 +209,6 @@ class SqlController extends AbstractController
$import_text ?? null,
$extra_data ?? null,
$message_to_show ?? null,
$message ?? null,
$sql_data ?? null,
$goto,
$pmaThemeImage,

View File

@ -73,7 +73,6 @@ class DeleteController extends AbstractController
null,
null,
null,
null,
$goto,
$pmaThemeImage,
null,

View File

@ -0,0 +1,216 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\Controllers\Table;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Html\Generator;
use PhpMyAdmin\Response;
use PhpMyAdmin\Table\Maintenance;
use PhpMyAdmin\Template;
use function count;
use function is_array;
final class MaintenanceController extends AbstractController
{
/** @var Maintenance */
private $model;
/**
* @param Response $response
* @param DatabaseInterface $dbi
* @param string $db
* @param string $table
*/
public function __construct(
$response,
$dbi,
Template $template,
$db,
$table,
Maintenance $model
) {
parent::__construct($response, $dbi, $template, $db, $table);
$this->model = $model;
}
public function analyze(): void
{
global $cfg;
/** @var string[] $selected */
$selected = $_POST['selected_tbl'] ?? [];
if (empty($selected) || ! is_array($selected)) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', __('No table selected.'));
return;
}
if ($cfg['DisableMultiTableMaintenance'] && count($selected) > 1) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', __('Maintenance operations on multiple tables are disabled.'));
return;
}
[$rows, $query] = $this->model->getAnalyzeTableRows($this->db, $selected);
$message = Generator::getMessage(
__('Your SQL query has been executed successfully.'),
$query,
'success'
);
$this->render('table/maintenance/analyze', [
'message' => $message,
'rows' => $rows,
]);
}
public function check(): void
{
global $cfg;
/** @var string[] $selected */
$selected = $_POST['selected_tbl'] ?? [];
if (empty($selected) || ! is_array($selected)) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', __('No table selected.'));
return;
}
if ($cfg['DisableMultiTableMaintenance'] && count($selected) > 1) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', __('Maintenance operations on multiple tables are disabled.'));
return;
}
[$rows, $query] = $this->model->getCheckTableRows($this->db, $selected);
$message = Generator::getMessage(
__('Your SQL query has been executed successfully.'),
$query,
'success'
);
$indexesProblems = $this->model->getIndexesProblems($this->db, $selected);
$this->render('table/maintenance/check', [
'message' => $message,
'rows' => $rows,
'indexes_problems' => $indexesProblems,
]);
}
public function checksum(): void
{
global $cfg;
/** @var string[] $selected */
$selected = $_POST['selected_tbl'] ?? [];
if (empty($selected) || ! is_array($selected)) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', __('No table selected.'));
return;
}
if ($cfg['DisableMultiTableMaintenance'] && count($selected) > 1) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', __('Maintenance operations on multiple tables are disabled.'));
return;
}
[$rows, $query, $warnings] = $this->model->getChecksumTableRows($this->db, $selected);
$message = Generator::getMessage(
__('Your SQL query has been executed successfully.'),
$query,
'success'
);
$this->render('table/maintenance/checksum', [
'message' => $message,
'rows' => $rows,
'warnings' => $warnings,
]);
}
public function optimize(): void
{
global $cfg;
/** @var string[] $selected */
$selected = $_POST['selected_tbl'] ?? [];
if (empty($selected) || ! is_array($selected)) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', __('No table selected.'));
return;
}
if ($cfg['DisableMultiTableMaintenance'] && count($selected) > 1) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', __('Maintenance operations on multiple tables are disabled.'));
return;
}
[$rows, $query] = $this->model->getOptimizeTableRows($this->db, $selected);
$message = Generator::getMessage(
__('Your SQL query has been executed successfully.'),
$query,
'success'
);
$this->render('table/maintenance/optimize', [
'message' => $message,
'rows' => $rows,
]);
}
public function repair(): void
{
global $cfg;
/** @var string[] $selected */
$selected = $_POST['selected_tbl'] ?? [];
if (empty($selected) || ! is_array($selected)) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', __('No table selected.'));
return;
}
if ($cfg['DisableMultiTableMaintenance'] && count($selected) > 1) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', __('Maintenance operations on multiple tables are disabled.'));
return;
}
[$rows, $query] = $this->model->getRepairTableRows($this->db, $selected);
$message = Generator::getMessage(
__('Your SQL query has been executed successfully.'),
$query,
'success'
);
$this->render('table/maintenance/repair', [
'message' => $message,
'rows' => $rows,
]);
}
}

View File

@ -7,7 +7,6 @@ namespace PhpMyAdmin\Controllers\Table;
use PhpMyAdmin\Charsets;
use PhpMyAdmin\CheckUserPrivileges;
use PhpMyAdmin\Common;
use PhpMyAdmin\Controllers\SqlController;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Html\Generator;
use PhpMyAdmin\Index;
@ -67,12 +66,11 @@ class OperationsController extends AbstractController
public function index(): void
{
global $containerBuilder, $url_query, $url_params, $reread_info, $tbl_is_view, $tbl_storage_engine;
global $url_query, $url_params, $reread_info, $tbl_is_view, $tbl_storage_engine;
global $show_comment, $tbl_collation, $table_info_num_rows, $row_format, $auto_increment, $create_options;
global $table_alters, $warning_messages, $lowerCaseNames, $db, $table, $reload, $result;
global $new_tbl_storage_engine, $sql_query, $message_to_show, $columns, $hideOrderTable, $indexes;
global $notNull, $comment, $db_is_system_schema, $truncate_table_url_params, $drop_table_url_params;
global $this_sql_query;
global $notNull, $comment, $db_is_system_schema;
$this->checkUserPrivileges->getPrivileges();
@ -163,16 +161,6 @@ class OperationsController extends AbstractController
return;
}
/**
* If the table has to be maintained
*/
if (isset($_POST['table_maintenance'])) {
/** @var SqlController $controller */
$controller = $containerBuilder->get(SqlController::class);
$controller->index();
unset($result);
}
/**
* Updates table comment, type and options if required
*/
@ -449,8 +437,6 @@ class OperationsController extends AbstractController
$hasPrivileges = $GLOBALS['table_priv'] && $GLOBALS['col_priv'] && $GLOBALS['is_reload_priv'];
$switchToNew = isset($_SESSION['pma_switch_to_new']) && $_SESSION['pma_switch_to_new'];
$maintenanceActions = $this->operations->getMaintenanceActions($pma_table);
$partitions = [];
$partitionsChoices = [];
@ -495,7 +481,6 @@ class OperationsController extends AbstractController
'has_foreign_keys' => $hasForeignKeys,
'has_privileges' => $hasPrivileges,
'switch_to_new' => $switchToNew,
'maintenance_actions' => $maintenanceActions,
'is_system_schema' => isset($db_is_system_schema) && $db_is_system_schema,
'is_view' => $tbl_is_view,
'partitions' => $partitions,

View File

@ -268,7 +268,6 @@ class SearchController extends AbstractController
null, // sql_query_for_bookmark
null, // extra_data
null, // message_to_show
null, // message
null, // sql_data
$GLOBALS['goto'], // goto
$GLOBALS['pmaThemeImage'], // pmaThemeImage

View File

@ -1068,7 +1068,6 @@ class StructureController extends AbstractController
null, // sql_query_for_bookmark
null, // extra_data
null, // message_to_show
null, // message
null, // sql_data
$goto, // goto
$pmaThemeImage, // pmaThemeImage

View File

@ -121,7 +121,6 @@ class MultiTableQuery
null, // sql_query_for_bookmark - see below
null, // extra_data
null, // message_to_show
null, // message
null, // sql_data
$goto, // goto
$pmaThemeImage, // pmaThemeImage

View File

@ -12,10 +12,8 @@ use PhpMyAdmin\Plugins\Export\ExportSql;
use function array_merge;
use function count;
use function explode;
use function htmlspecialchars;
use function implode;
use function mb_strtolower;
use function sprintf;
use function str_replace;
use function strlen;
use function strtolower;
@ -595,96 +593,6 @@ class Operations
return $possible_row_formats;
}
/**
* @param Table $tableObject Table object
*
* @return array
*/
public function getMaintenanceActions(Table $tableObject): array
{
global $table;
$actions = [];
if ($tableObject->isEngine(['MYISAM', 'ARIA', 'INNODB', 'BERKELEYDB', 'TOKUDB'])) {
$actions[] = [
'params' => [
'sql_query' => 'ANALYZE TABLE ' . Util::backquote($table),
'table_maintenance' => 'Go',
],
'message' => __('Analyze table'),
'link' => 'ANALYZE_TABLE',
];
}
if ($tableObject->isEngine(['MYISAM', 'ARIA', 'INNODB', 'TOKUDB'])) {
$actions[] = [
'params' => [
'sql_query' => 'CHECK TABLE ' . Util::backquote($table),
'table_maintenance' => 'Go',
],
'message' => __('Check table'),
'link' => 'CHECK_TABLE',
];
}
$actions[] = [
'params' => [
'sql_query' => 'CHECKSUM TABLE ' . Util::backquote($table),
'table_maintenance' => 'Go',
],
'message' => __('Checksum table'),
'link' => 'CHECKSUM_TABLE',
];
if ($tableObject->isEngine(['INNODB'])) {
$actions[] = [
'params' => [
'sql_query' => 'ALTER TABLE ' . Util::backquote($table) . ' ENGINE = InnoDB;',
],
'message' => __('Defragment table'),
'link' => 'InnoDB_File_Defragmenting',
];
}
$actions[] = [
'params' => [
'sql_query' => 'FLUSH TABLE ' . Util::backquote($table),
'message_to_show' => sprintf(
__('Table %s has been flushed.'),
htmlspecialchars($table)
),
'reload' => true,
],
'message' => __('Flush the table (FLUSH)'),
'link' => 'FLUSH',
];
if ($tableObject->isEngine(['MYISAM', 'ARIA', 'INNODB', 'BERKELEYDB', 'TOKUDB'])) {
$actions[] = [
'params' => [
'sql_query' => 'OPTIMIZE TABLE ' . Util::backquote($table),
'table_maintenance' => 'Go',
],
'message' => __('Optimize table'),
'link' => 'OPTIMIZE_TABLE',
];
}
if ($tableObject->isEngine(['MYISAM', 'ARIA'])) {
$actions[] = [
'params' => [
'sql_query' => 'REPAIR TABLE ' . Util::backquote($table),
'table_maintenance' => 'Go',
],
'message' => __('Repair table'),
'link' => 'REPAIR_TABLE',
];
}
return $actions;
}
/**
* @return array<string, string>
*/

View File

@ -26,7 +26,6 @@ use function htmlspecialchars;
use function in_array;
use function is_array;
use function is_bool;
use function is_string;
use function microtime;
use function session_start;
use function session_write_close;
@ -1479,7 +1478,6 @@ class Sql
* @param array $analyzed_sql_results analysed sql results
* @param string $db current database
* @param string $table current table
* @param Message|string|null $message message to show
* @param array|null $sql_data sql data
* @param DisplayResults $displayResultsObject Instance of DisplayResults
* @param string $pmaThemeImage uri of the theme image
@ -1498,7 +1496,6 @@ class Sql
array $analyzed_sql_results,
$db,
$table,
$message,
?array $sql_data,
$displayResultsObject,
$pmaThemeImage,
@ -1606,36 +1603,6 @@ class Sql
];
}
$tableMaintenanceHtml = '';
if (isset($_POST['table_maintenance'])) {
$scripts->addFile('makegrid.js');
$scripts->addFile('sql.js');
if (isset($message)) {
$message = is_string($message) ? Message::success($message) : $message;
$tableMaintenanceHtml = Generator::getMessage(
$message,
$GLOBALS['sql_query'],
'success'
);
}
$tableMaintenanceHtml .= $this->getHtmlForSqlQueryResultsTable(
$displayResultsObject,
$pmaThemeImage,
$url_query,
$displayParts,
false,
$unlim_num_rows,
$num_rows,
$showtable,
$result,
$analyzed_sql_results
);
if (empty($sql_data) || ($sql_data['valid_queries'] <= 1)) {
$response->addHTML($tableMaintenanceHtml);
exit;
}
}
if (! isset($_POST['printview']) || $_POST['printview'] != '1') {
$scripts->addFile('makegrid.js');
$scripts->addFile('sql.js');
@ -1704,7 +1671,6 @@ class Sql
}
return $this->template->render('sql/sql_query_results', [
'table_maintenance' => $tableMaintenanceHtml,
'previous_update_query' => $previousUpdateQueryHtml,
'profiling_chart' => $profilingChartHtml,
'missing_unique_column_message' => $missingUniqueColumnMessage,
@ -1725,7 +1691,6 @@ class Sql
* @param string|null $sql_query_for_bookmark the sql query to be stored as bookmark
* @param array|null $extra_data extra data
* @param string|null $message_to_show message to show
* @param Message|string|null $message message
* @param array|null $sql_data sql data
* @param string $goto goto page url
* @param string $pmaThemeImage uri of the PMA theme image
@ -1743,7 +1708,6 @@ class Sql
$sql_query_for_bookmark,
$extra_data,
$message_to_show,
$message,
$sql_data,
$goto,
$pmaThemeImage,
@ -1774,7 +1738,6 @@ class Sql
$sql_query_for_bookmark, // sql_query_for_bookmark
$extra_data, // extra_data
$message_to_show, // message_to_show
$message, // message
$sql_data, // sql_data
$goto, // goto
$pmaThemeImage, // pmaThemeImage
@ -1796,7 +1759,6 @@ class Sql
* @param string|null $sql_query_for_bookmark the sql query to be stored as bookmark
* @param array|null $extra_data extra data
* @param string|null $message_to_show message to show
* @param Message|string|null $message message
* @param array|null $sql_data sql data
* @param string $goto goto page url
* @param string $pmaThemeImage uri of the PMA theme image
@ -1816,7 +1778,6 @@ class Sql
?string $sql_query_for_bookmark,
$extra_data,
?string $message_to_show,
$message,
$sql_data,
$goto,
$pmaThemeImage,
@ -1913,7 +1874,6 @@ class Sql
$analyzed_sql_results,
$db,
$table,
$message ?? null,
$sql_data ?? null,
$displayResultsObject,
$pmaThemeImage,

View File

@ -0,0 +1,142 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\Table;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Index;
use PhpMyAdmin\Util;
use function implode;
use function sprintf;
final class Maintenance
{
/** @var DatabaseInterface */
private $dbi;
public function __construct(DatabaseInterface $dbi)
{
$this->dbi = $dbi;
}
/**
* @param string[] $tables
*
* @return array
*/
public function getAnalyzeTableRows(string $db, array $tables): array
{
$backQuotedTables = Util::backquote($tables);
$query = 'ANALYZE TABLE ' . implode(', ', $backQuotedTables) . ';';
$this->dbi->selectDb($db);
$result = $this->dbi->fetchResult($query);
$rows = [];
foreach ($result as $row) {
$rows[$row['Table']][] = $row;
}
return [$rows, $query];
}
/**
* @param string[] $tables
*
* @return array
*/
public function getCheckTableRows(string $db, array $tables): array
{
$backQuotedTables = Util::backquote($tables);
$query = 'CHECK TABLE ' . implode(', ', $backQuotedTables) . ';';
$this->dbi->selectDb($db);
$result = $this->dbi->fetchResult($query);
$rows = [];
foreach ($result as $row) {
$rows[$row['Table']][] = $row;
}
return [$rows, $query];
}
/**
* @param string[] $tables
*
* @return array
*/
public function getChecksumTableRows(string $db, array $tables): array
{
$backQuotedTables = Util::backquote($tables);
$query = 'CHECKSUM TABLE ' . implode(', ', $backQuotedTables) . ';';
$this->dbi->selectDb($db);
$rows = $this->dbi->fetchResult($query);
$warnings = $this->dbi->getWarnings();
return [$rows, $query, $warnings];
}
/** @param string[] $tables */
public function getIndexesProblems(string $db, array $tables): string
{
$indexesProblems = '';
foreach ($tables as $table) {
$check = Index::findDuplicates($table, $db);
if (empty($check)) {
continue;
}
$indexesProblems .= sprintf(__('Problems with indexes of table `%s`'), $table);
$indexesProblems .= $check;
}
return $indexesProblems;
}
/**
* @param string[] $tables
*
* @return array
*/
public function getOptimizeTableRows(string $db, array $tables): array
{
$backQuotedTables = Util::backquote($tables);
$query = 'OPTIMIZE TABLE ' . implode(', ', $backQuotedTables) . ';';
$this->dbi->selectDb($db);
$result = $this->dbi->fetchResult($query);
$rows = [];
foreach ($result as $row) {
$rows[$row['Table']][] = $row;
}
return [$rows, $query];
}
/**
* @param string[] $tables
*
* @return array
*/
public function getRepairTableRows(string $db, array $tables): array
{
$backQuotedTables = Util::backquote($tables);
$query = 'REPAIR TABLE ' . implode(', ', $backQuotedTables) . ';';
$this->dbi->selectDb($db);
$result = $this->dbi->fetchResult($query);
$rows = [];
foreach ($result as $row) {
$rows[$row['Table']][] = $row;
}
return [$rows, $query];
}
}

View File

@ -76,6 +76,7 @@ use PhpMyAdmin\Controllers\Table\GetFieldController;
use PhpMyAdmin\Controllers\Table\GisVisualizationController;
use PhpMyAdmin\Controllers\Table\ImportController as TableImportController;
use PhpMyAdmin\Controllers\Table\IndexesController;
use PhpMyAdmin\Controllers\Table\MaintenanceController;
use PhpMyAdmin\Controllers\Table\OperationsController as TableOperationsController;
use PhpMyAdmin\Controllers\Table\RecentFavoriteController;
use PhpMyAdmin\Controllers\Table\RelationController;
@ -141,7 +142,6 @@ return static function (RouteCollector $routes): void {
$routes->addRoute(['GET', 'POST'], '', [StructureController::class, 'index']);
$routes->post('/add-prefix', [StructureController::class, 'addPrefix']);
$routes->post('/add-prefix-table', [StructureController::class, 'addPrefixTable']);
$routes->post('/analyze-table', [StructureController::class, 'analyzeTable']);
$routes->post('/central-columns-add', [StructureController::class, 'centralColumnsAdd']);
$routes->post('/central-columns-make-consistent', [
StructureController::class,
@ -149,8 +149,6 @@ return static function (RouteCollector $routes): void {
]);
$routes->post('/central-columns-remove', [StructureController::class, 'centralColumnsRemove']);
$routes->post('/change-prefix-form', [StructureController::class, 'changePrefixForm']);
$routes->post('/check-table', [StructureController::class, 'checkTable']);
$routes->post('/checksum-table', [StructureController::class, 'checksumTable']);
$routes->post('/copy-form', [StructureController::class, 'copyForm']);
$routes->post('/copy-table', [StructureController::class, 'copyTable']);
$routes->post('/copy-table-with-prefix', [StructureController::class, 'copyTableWithPrefix']);
@ -163,12 +161,10 @@ return static function (RouteCollector $routes): void {
StructureController::class,
'addRemoveFavoriteTablesAction',
]);
$routes->post('/optimize-table', [StructureController::class, 'optimizeTable']);
$routes->addRoute(['GET', 'POST'], '/real-row-count', [
StructureController::class,
'handleRealRowCountRequestAction',
]);
$routes->post('/repair-table', [StructureController::class, 'repairTable']);
$routes->post('/replace-prefix', [StructureController::class, 'replacePrefix']);
$routes->post('/show-create', [StructureController::class, 'showCreate']);
});
@ -278,6 +274,13 @@ return static function (RouteCollector $routes): void {
$routes->addRoute(['GET', 'POST'], '/gis-visualization', [GisVisualizationController::class, 'index']);
$routes->addRoute(['GET', 'POST'], '/import', [TableImportController::class, 'index']);
$routes->addRoute(['GET', 'POST'], '/indexes', [IndexesController::class, 'index']);
$routes->addGroup('/maintenance', static function (RouteCollector $routes): void {
$routes->post('/analyze', [MaintenanceController::class, 'analyze']);
$routes->post('/check', [MaintenanceController::class, 'check']);
$routes->post('/checksum', [MaintenanceController::class, 'checksum']);
$routes->post('/optimize', [MaintenanceController::class, 'optimize']);
$routes->post('/repair', [MaintenanceController::class, 'repair']);
});
$routes->addRoute(['GET', 'POST'], '/operations', [TableOperationsController::class, 'index']);
$routes->addRoute(['GET', 'POST'], '/recent-favorite', [RecentFavoriteController::class, 'index']);
$routes->addRoute(['GET', 'POST'], '/relation', [RelationController::class, 'index']);

View File

@ -171,6 +171,10 @@ return [
'class' => PhpMyAdmin\Server\Status\Monitor::class,
'arguments' => ['@dbi'],
],
'table_maintenance' => [
'class' => PhpMyAdmin\Table\Maintenance::class,
'arguments' => ['dbi' => '@dbi'],
],
'table_search' => [
'class' => PhpMyAdmin\Table\Search::class,
'arguments' => ['dbi' => '@dbi'],

View File

@ -710,6 +710,17 @@ return [
'table' => '%table%',
],
],
PhpMyAdmin\Controllers\Table\MaintenanceController::class => [
'class' => PhpMyAdmin\Controllers\Table\MaintenanceController::class,
'arguments' => [
'response' => '@response',
'dbi' => '@dbi',
'template' => '@template',
'db' => '%db%',
'table' => '%table%',
'model' => '@table_maintenance',
],
],
PhpMyAdmin\Controllers\Table\OperationsController::class => [
'class' => PhpMyAdmin\Controllers\Table\OperationsController::class,
'arguments' => [

View File

@ -1,29 +0,0 @@
<div class="container-fluid">
<h2>
{% trans 'Checking tables' %}
{{ show_mysql_docu('CHECK_TABLE') }}
</h2>
{{ message|raw }}
<table class="mt-3">
<thead>
<tr>
<th>{% trans 'Table' %}</th>
<th>{% trans 'Message type' %}</th>
<th>{% trans 'Message' %}</th>
</tr>
</thead>
<tbody>
{% for row in rows %}
<tr>
<td>{{ row.Table }}</td>
<td>{{ row.Msg_type|title }}</td>
<td>{{ row.Msg_text }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{{ indexes_problems|raw }}
</div>

View File

@ -1,4 +1,3 @@
{{ table_maintenance|raw }}
<div class="sqlqueryresults ajax">
{{ previous_update_query|raw }}
{{ profiling_chart|raw }}

View File

@ -0,0 +1,39 @@
<div class="container-fluid">
<h2>
{% trans 'Analyze table' %}
{{ show_mysql_docu('ANALYZE_TABLE') }}
</h2>
{{ message|raw }}
{% for name, table in rows %}
<div class="card mb-3">
<div class="card-header">{{ name }}</div>
<ul class="list-group list-group-flush">
{% for row in table %}
<li class="list-group-item">
{% if row.Op|lower != 'analyze' %}
<span class="badge badge-secondary">{{ row.Op|title }}</span>
{% endif %}
{% set badge_variation %}
{%- if row.Msg_type|lower == 'error' -%}
badge-danger
{%- elseif row.Msg_type|lower == 'warning' -%}
badge-warning
{%- elseif row.Msg_type|lower == 'info' or row.Msg_type|lower == 'note' -%}
badge-info
{%- else -%}
badge-secondary
{%- endif -%}
{% endset %}
<span class="badge {{ badge_variation }}">{{ row.Msg_type|title }}</span>
{{ row.Msg_text }}
</li>
{% endfor %}
</ul>
</div>
{% endfor %}
</div>

View File

@ -0,0 +1,41 @@
<div class="container-fluid">
<h2>
{% trans 'Check table' %}
{{ show_mysql_docu('CHECK_TABLE') }}
</h2>
{{ message|raw }}
{% for name, table in rows %}
<div class="card mb-3">
<div class="card-header">{{ name }}</div>
<ul class="list-group list-group-flush">
{% for row in table %}
<li class="list-group-item">
{% if row.Op|lower != 'check' %}
<span class="badge badge-secondary">{{ row.Op|title }}</span>
{% endif %}
{% set badge_variation %}
{%- if row.Msg_type|lower == 'error' -%}
badge-danger
{%- elseif row.Msg_type|lower == 'warning' -%}
badge-warning
{%- elseif row.Msg_type|lower == 'info' or row.Msg_type|lower == 'note' -%}
badge-info
{%- else -%}
badge-secondary
{%- endif -%}
{% endset %}
<span class="badge {{ badge_variation }}">{{ row.Msg_type|title }}</span>
{{ row.Msg_text }}
</li>
{% endfor %}
</ul>
</div>
{% endfor %}
{{ indexes_problems|raw }}
</div>

View File

@ -0,0 +1,37 @@
<div class="container-fluid">
<h2>
{% trans 'Checksum table' %}
{{ show_mysql_docu('CHECKSUM_TABLE') }}
</h2>
{{ message|raw }}
<table class="my-3">
<thead>
<tr>
<th>{% trans 'Table' %}</th>
<th>{% trans 'Checksum' %}</th>
</tr>
</thead>
<tbody>
{% for row in rows %}
<tr>
<td>{{ row.Table }}</td>
<td class="text-right">
{% if row.Checksum is not null %}
{{ row.Checksum }}
{% else %}
<em class="text-muted">NULL</em>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% for warning in warnings %}
{% apply notice %}
{{ warning.Level }}: #{{ warning.Code }} {{ warning.Message }}
{% endapply %}
{% endfor %}
</div>

View File

@ -0,0 +1,39 @@
<div class="container-fluid">
<h2>
{% trans 'Optimize table' %}
{{ show_mysql_docu('OPTIMIZE_TABLE') }}
</h2>
{{ message|raw }}
{% for name, table in rows %}
<div class="card mb-3">
<div class="card-header">{{ name }}</div>
<ul class="list-group list-group-flush">
{% for row in table %}
<li class="list-group-item">
{% if row.Op|lower != 'optimize' %}
<span class="badge badge-secondary">{{ row.Op|title }}</span>
{% endif %}
{% set badge_variation %}
{%- if row.Msg_type|lower == 'error' -%}
badge-danger
{%- elseif row.Msg_type|lower == 'warning' -%}
badge-warning
{%- elseif row.Msg_type|lower == 'info' or row.Msg_type|lower == 'note' -%}
badge-info
{%- else -%}
badge-secondary
{%- endif -%}
{% endset %}
<span class="badge {{ badge_variation }}">{{ row.Msg_type|title }}</span>
{{ row.Msg_text }}
</li>
{% endfor %}
</ul>
</div>
{% endfor %}
</div>

View File

@ -0,0 +1,39 @@
<div class="container-fluid">
<h2>
{% trans 'Repair table' %}
{{ show_mysql_docu('REPAIR_TABLE') }}
</h2>
{{ message|raw }}
{% for name, table in rows %}
<div class="card mb-3">
<div class="card-header">{{ name }}</div>
<ul class="list-group list-group-flush">
{% for row in table %}
<li class="list-group-item">
{% if row.Op|lower != 'repair' %}
<span class="badge badge-secondary">{{ row.Op|title }}</span>
{% endif %}
{% set badge_variation %}
{%- if row.Msg_type|lower == 'error' -%}
badge-danger
{%- elseif row.Msg_type|lower == 'warning' -%}
badge-warning
{%- elseif row.Msg_type|lower == 'info' or row.Msg_type|lower == 'note' -%}
badge-info
{%- else -%}
badge-secondary
{%- endif -%}
{% endset %}
<span class="badge {{ badge_variation }}">{{ row.Msg_type|title }}</span>
{{ row.Msg_text }}
</li>
{% endfor %}
</ul>
</div>
{% endfor %}
</div>

View File

@ -311,16 +311,68 @@
<div class="card mb-2">
<div class="card-header">{% trans 'Table maintenance' %}</div>
<ul class="list-group list-group-flush" id="tbl_maintenance">
{% for action in maintenance_actions %}
{% if storage_engine in ['MYISAM', 'ARIA', 'INNODB', 'BERKELEYDB', 'TOKUDB'] %}
<li class="list-group-item">
{{ link_or_button(
url('/sql', url_params|merge(action.params)),
action.message,
{'class': 'maintain_action ajax'}
) }}
{{ show_mysql_docu(action.link) }}
<a href="{{ url('/table/maintenance/analyze') }}" data-post="{{ get_common({'db': db, 'table': table, 'selected_tbl': [table]}) }}">
{% trans 'Analyze table' %}
</a>
{{ show_mysql_docu('ANALYZE_TABLE') }}
</li>
{% endfor %}
{% endif %}
{% if storage_engine in ['MYISAM', 'ARIA', 'INNODB', 'TOKUDB'] %}
<li class="list-group-item">
<a href="{{ url('/table/maintenance/check') }}" data-post="{{ get_common({'db': db, 'table': table, 'selected_tbl': [table]}) }}">
{% trans 'Check table' %}
</a>
{{ show_mysql_docu('CHECK_TABLE') }}
</li>
{% endif %}
<li class="list-group-item">
<a href="{{ url('/table/maintenance/checksum') }}" data-post="{{ get_common({'db': db, 'table': table, 'selected_tbl': [table]}) }}">
{% trans 'Checksum table' %}
</a>
{{ show_mysql_docu('CHECKSUM_TABLE') }}
</li>
{% if storage_engine == 'INNODB' %}
<li class="list-group-item">
<a class="maintain_action ajax" href="{{ url('/sql') }}" data-post="{{ get_common(url_params|merge({'sql_query': 'ALTER TABLE ' ~ backquote(table) ~ ' ENGINE = InnoDB;'})) }}">
{% trans 'Defragment table' %}
</a>
{{ show_mysql_docu('InnoDB_File_Defragmenting') }}
</li>
{% endif %}
<li class="list-group-item">
<a class="maintain_action ajax" href="{{ url('/sql') }}" data-post="{{ get_common(url_params|merge({
'sql_query': 'FLUSH TABLE ' ~ backquote(table),
'message_to_show': 'Table %s has been flushed.'|trans|format(table|e),
'reload': true
})) }}">
{% trans 'Flush the table (FLUSH)' %}
</a>
{{ show_mysql_docu('FLUSH') }}
</li>
{% if storage_engine in ['MYISAM', 'ARIA', 'INNODB', 'BERKELEYDB', 'TOKUDB'] %}
<li class="list-group-item">
<a href="{{ url('/table/maintenance/optimize') }}" data-post="{{ get_common({'db': db, 'table': table, 'selected_tbl': [table]}) }}">
{% trans 'Optimize table' %}
</a>
{{ show_mysql_docu('OPTIMIZE_TABLE') }}
</li>
{% endif %}
{% if storage_engine in ['MYISAM', 'ARIA'] %}
<li class="list-group-item">
<a href="{{ url('/table/maintenance/repair') }}" data-post="{{ get_common({'db': db, 'table': table, 'selected_tbl': [table]}) }}">
{% trans 'Repair table' %}
</a>
{{ show_mysql_docu('REPAIR_TABLE') }}
</li>
{% endif %}
</ul>
</div>

View File

@ -20,7 +20,7 @@
@import "../../../node_modules/bootstrap/scss/card";
@import "../../../node_modules/bootstrap/scss/breadcrumb";
//@import "../../../node_modules/bootstrap/scss/pagination";
//@import "../../../node_modules/bootstrap/scss/badge";
@import "../../../node_modules/bootstrap/scss/badge";
//@import "../../../node_modules/bootstrap/scss/jumbotron";
@import "../../../node_modules/bootstrap/scss/alert";
//@import "../../../node_modules/bootstrap/scss/progress";