diff --git a/libraries/classes/Controllers/Table/PartitionController.php b/libraries/classes/Controllers/Table/PartitionController.php new file mode 100644 index 0000000000..6e5388c6a7 --- /dev/null +++ b/libraries/classes/Controllers/Table/PartitionController.php @@ -0,0 +1,211 @@ +model = $partition; + } + + public function analyze(): void + { + $partitionName = $_POST['partition_name'] ?? ''; + + if (strlen($partitionName) === 0) { + return; + } + + [$rows, $query] = $this->model->analyze($this->db, $this->table, $partitionName); + + $message = Generator::getMessage( + __('Your SQL query has been executed successfully.'), + $query, + 'success' + ); + + $this->render('table/partition/analyze', [ + 'partition_name' => $partitionName, + 'message' => $message, + 'rows' => $rows, + ]); + } + + public function check(): void + { + $partitionName = $_POST['partition_name'] ?? ''; + + if (strlen($partitionName) === 0) { + return; + } + + [$rows, $query] = $this->model->check($this->db, $this->table, $partitionName); + + $message = Generator::getMessage( + __('Your SQL query has been executed successfully.'), + $query, + 'success' + ); + + $this->render('table/partition/check', [ + 'partition_name' => $partitionName, + 'message' => $message, + 'rows' => $rows, + ]); + } + + public function drop(): void + { + $partitionName = $_POST['partition_name'] ?? ''; + + if (strlen($partitionName) === 0) { + return; + } + + [$result, $query] = $this->model->drop($this->db, $this->table, $partitionName); + + if ($result) { + $message = Generator::getMessage( + __('Your SQL query has been executed successfully.'), + $query, + 'success' + ); + } else { + $message = Generator::getMessage( + __('Error'), + $query, + 'error' + ); + } + + $this->render('table/partition/drop', [ + 'partition_name' => $partitionName, + 'message' => $message, + ]); + } + + public function optimize(): void + { + $partitionName = $_POST['partition_name'] ?? ''; + + if (strlen($partitionName) === 0) { + return; + } + + [$rows, $query] = $this->model->optimize($this->db, $this->table, $partitionName); + + $message = Generator::getMessage( + __('Your SQL query has been executed successfully.'), + $query, + 'success' + ); + + $this->render('table/partition/optimize', [ + 'partition_name' => $partitionName, + 'message' => $message, + 'rows' => $rows, + ]); + } + + public function rebuild(): void + { + $partitionName = $_POST['partition_name'] ?? ''; + + if (strlen($partitionName) === 0) { + return; + } + + [$result, $query] = $this->model->rebuild($this->db, $this->table, $partitionName); + + if ($result) { + $message = Generator::getMessage( + __('Your SQL query has been executed successfully.'), + $query, + 'success' + ); + } else { + $message = Generator::getMessage( + __('Error'), + $query, + 'error' + ); + } + + $this->render('table/partition/rebuild', [ + 'partition_name' => $partitionName, + 'message' => $message, + ]); + } + + public function repair(): void + { + $partitionName = $_POST['partition_name'] ?? ''; + + if (strlen($partitionName) === 0) { + return; + } + + [$rows, $query] = $this->model->repair($this->db, $this->table, $partitionName); + + $message = Generator::getMessage( + __('Your SQL query has been executed successfully.'), + $query, + 'success' + ); + + $this->render('table/partition/repair', [ + 'partition_name' => $partitionName, + 'message' => $message, + 'rows' => $rows, + ]); + } + + public function truncate(): void + { + $partitionName = $_POST['partition_name'] ?? ''; + + if (strlen($partitionName) === 0) { + return; + } + + [$result, $query] = $this->model->truncate($this->db, $this->table, $partitionName); + + if ($result) { + $message = Generator::getMessage( + __('Your SQL query has been executed successfully.'), + $query, + 'success' + ); + } else { + $message = Generator::getMessage( + __('Error'), + $query, + 'error' + ); + } + + $this->render('table/partition/truncate', [ + 'partition_name' => $partitionName, + 'message' => $message, + ]); + } +} diff --git a/libraries/classes/Controllers/Table/StructureController.php b/libraries/classes/Controllers/Table/StructureController.php index 5308e83284..519df6f9a6 100644 --- a/libraries/classes/Controllers/Table/StructureController.php +++ b/libraries/classes/Controllers/Table/StructureController.php @@ -805,19 +805,6 @@ class StructureController extends AbstractController public function partitioning(): void { - global $containerBuilder, $reload; - - if (isset($_POST['partition_maintenance'])) { - /** @var SqlController $controller */ - $controller = $containerBuilder->get(SqlController::class); - $controller->index(); - - $reload = true; - $this->index(); - - return; - } - if (isset($_POST['save_partitioning'])) { $this->dbi->selectDb($this->db); $this->updatePartitioning(); diff --git a/libraries/classes/Table/Partition.php b/libraries/classes/Table/Partition.php new file mode 100644 index 0000000000..b64f41f027 --- /dev/null +++ b/libraries/classes/Table/Partition.php @@ -0,0 +1,138 @@ +dbi = $dbi; + } + + public function analyze(string $db, string $table, string $partition): array + { + $query = sprintf( + 'ALTER TABLE %s ANALYZE PARTITION %s;', + Util::backquote($table), + Util::backquote($partition) + ); + + $this->dbi->selectDb($db); + $result = $this->dbi->fetchResult($query); + + $rows = []; + foreach ($result as $row) { + $rows[$row['Table']][] = $row; + } + + return [$rows, $query]; + } + + public function check(string $db, string $table, string $partition): array + { + $query = sprintf( + 'ALTER TABLE %s CHECK PARTITION %s;', + Util::backquote($table), + Util::backquote($partition) + ); + + $this->dbi->selectDb($db); + $result = $this->dbi->fetchResult($query); + + $rows = []; + foreach ($result as $row) { + $rows[$row['Table']][] = $row; + } + + return [$rows, $query]; + } + + public function drop(string $db, string $table, string $partition): array + { + $query = sprintf( + 'ALTER TABLE %s DROP PARTITION %s;', + Util::backquote($table), + Util::backquote($partition) + ); + + $this->dbi->selectDb($db); + $result = $this->dbi->tryQuery($query); + + return [(bool) $result, $query]; + } + + public function optimize(string $db, string $table, string $partition): array + { + $query = sprintf( + 'ALTER TABLE %s OPTIMIZE PARTITION %s;', + Util::backquote($table), + Util::backquote($partition) + ); + + $this->dbi->selectDb($db); + $result = $this->dbi->fetchResult($query); + + $rows = []; + foreach ($result as $row) { + $rows[$row['Table']][] = $row; + } + + return [$rows, $query]; + } + + public function rebuild(string $db, string $table, string $partition): array + { + $query = sprintf( + 'ALTER TABLE %s REBUILD PARTITION %s;', + Util::backquote($table), + Util::backquote($partition) + ); + + $this->dbi->selectDb($db); + $result = $this->dbi->tryQuery($query); + + return [(bool) $result, $query]; + } + + public function repair(string $db, string $table, string $partition): array + { + $query = sprintf( + 'ALTER TABLE %s REPAIR PARTITION %s;', + Util::backquote($table), + Util::backquote($partition) + ); + + $this->dbi->selectDb($db); + $result = $this->dbi->fetchResult($query); + + $rows = []; + foreach ($result as $row) { + $rows[$row['Table']][] = $row; + } + + return [$rows, $query]; + } + + public function truncate(string $db, string $table, string $partition): array + { + $query = sprintf( + 'ALTER TABLE %s TRUNCATE PARTITION %s;', + Util::backquote($table), + Util::backquote($partition) + ); + + $this->dbi->selectDb($db); + $result = $this->dbi->tryQuery($query); + + return [(bool) $result, $query]; + } +} diff --git a/libraries/routes.php b/libraries/routes.php index 8b7581a04e..a047aad606 100644 --- a/libraries/routes.php +++ b/libraries/routes.php @@ -80,6 +80,7 @@ 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\PartitionController; use PhpMyAdmin\Controllers\Table\RecentFavoriteController; use PhpMyAdmin\Controllers\Table\RelationController; use PhpMyAdmin\Controllers\Table\ReplaceController; @@ -291,6 +292,15 @@ return static function (RouteCollector $routes): void { $routes->post('/optimize', [MaintenanceController::class, 'optimize']); $routes->post('/repair', [MaintenanceController::class, 'repair']); }); + $routes->addGroup('/partition', static function (RouteCollector $routes): void { + $routes->post('/analyze', [PartitionController::class, 'analyze']); + $routes->post('/check', [PartitionController::class, 'check']); + $routes->post('/drop', [PartitionController::class, 'drop']); + $routes->post('/optimize', [PartitionController::class, 'optimize']); + $routes->post('/rebuild', [PartitionController::class, 'rebuild']); + $routes->post('/repair', [PartitionController::class, 'repair']); + $routes->post('/truncate', [PartitionController::class, 'truncate']); + }); $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']); diff --git a/libraries/services.php b/libraries/services.php index 7146afc967..c445a8ff71 100644 --- a/libraries/services.php +++ b/libraries/services.php @@ -184,6 +184,10 @@ return [ 'class' => PhpMyAdmin\Table\Maintenance::class, 'arguments' => ['$dbi' => '@dbi'], ], + 'table_partition' => [ + 'class' => PhpMyAdmin\Table\Partition::class, + 'arguments' => ['$dbi' => '@dbi'], + ], 'table_search' => [ 'class' => PhpMyAdmin\Table\Search::class, 'arguments' => ['$dbi' => '@dbi'], diff --git a/libraries/services_controllers.php b/libraries/services_controllers.php index ccb3af9dc5..d391ccf896 100644 --- a/libraries/services_controllers.php +++ b/libraries/services_controllers.php @@ -706,6 +706,16 @@ return [ '$model' => '@table_maintenance', ], ], + PhpMyAdmin\Controllers\Table\PartitionController::class => [ + 'class' => PhpMyAdmin\Controllers\Table\PartitionController::class, + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$db' => '%db%', + '$table' => '%table%', + '$partition' => '@table_partition', + ], + ], PhpMyAdmin\Controllers\Table\OperationsController::class => [ 'class' => PhpMyAdmin\Controllers\Table\OperationsController::class, 'arguments' => [ diff --git a/templates/table/partition/analyze.twig b/templates/table/partition/analyze.twig new file mode 100644 index 0000000000..9a95cbf2aa --- /dev/null +++ b/templates/table/partition/analyze.twig @@ -0,0 +1,36 @@ +
+

{% trans 'Analyze partition' %}

+ + {{ message|raw }} + + {% for name, table in rows %} +
+
{{ name }} ({{ partition_name }})
+ + +
+ {% endfor %} +
diff --git a/templates/table/partition/check.twig b/templates/table/partition/check.twig new file mode 100644 index 0000000000..8e38270402 --- /dev/null +++ b/templates/table/partition/check.twig @@ -0,0 +1,36 @@ +
+

{% trans 'Check partition' %}

+ + {{ message|raw }} + + {% for name, table in rows %} +
+
{{ name }} ({{ partition_name }})
+ + +
+ {% endfor %} +
diff --git a/templates/table/partition/drop.twig b/templates/table/partition/drop.twig new file mode 100644 index 0000000000..c93a6470ba --- /dev/null +++ b/templates/table/partition/drop.twig @@ -0,0 +1,5 @@ +
+

{% trans 'Drop partition' %}

+ + {{ message|raw }} +
diff --git a/templates/table/partition/optimize.twig b/templates/table/partition/optimize.twig new file mode 100644 index 0000000000..50a804084e --- /dev/null +++ b/templates/table/partition/optimize.twig @@ -0,0 +1,36 @@ +
+

{% trans 'Optimize partition' %}

+ + {{ message|raw }} + + {% for name, table in rows %} +
+
{{ name }} ({{ partition_name }})
+ + +
+ {% endfor %} +
diff --git a/templates/table/partition/rebuild.twig b/templates/table/partition/rebuild.twig new file mode 100644 index 0000000000..1e1d120147 --- /dev/null +++ b/templates/table/partition/rebuild.twig @@ -0,0 +1,5 @@ +
+

{% trans 'Rebuild partition' %}

+ + {{ message|raw }} +
diff --git a/templates/table/partition/repair.twig b/templates/table/partition/repair.twig new file mode 100644 index 0000000000..a72b278d47 --- /dev/null +++ b/templates/table/partition/repair.twig @@ -0,0 +1,36 @@ +
+

{% trans 'Repair partition' %}

+ + {{ message|raw }} + + {% for name, table in rows %} +
+
{{ name }} ({{ partition_name }})
+ + +
+ {% endfor %} +
diff --git a/templates/table/partition/truncate.twig b/templates/table/partition/truncate.twig new file mode 100644 index 0000000000..259ce69f3e --- /dev/null +++ b/templates/table/partition/truncate.twig @@ -0,0 +1,5 @@ +
+

{% trans 'Truncate partition' %}

+ + {{ message|raw }} +
diff --git a/templates/table/structure/display_partitions.twig b/templates/table/structure/display_partitions.twig index b026a66360..9078460bd0 100644 --- a/templates/table/structure/display_partitions.twig +++ b/templates/table/structure/display_partitions.twig @@ -74,18 +74,78 @@ {{ index_length[1] }} {{ partition.getComment() }} - {% for action, icon in action_icons %} - - - {{ icon|raw }} - - - {% endfor %} + + + + {{ get_icon('b_search', 'Analyze'|trans) }} + + + + + + {{ get_icon('eye', 'Check'|trans) }} + + + + + + {{ get_icon('normalize', 'Optimize'|trans) }} + + + + + + {{ get_icon('s_tbl', 'Rebuild'|trans) }} + + + + + + {{ get_icon('b_tblops', 'Repair'|trans) }} + + + + + + {{ get_icon('b_empty', 'Truncate'|trans) }} + + + + {% if range_or_list %} + + + {{ get_icon('b_drop', 'Drop'|trans) }} + + + {% endif %} {% if has_sub_partitions %} {% for sub_partition in partition.getSubPartitions() %} @@ -140,7 +200,7 @@ 'sql_query': 'ALTER TABLE ' ~ backquote(table) ~ ' REMOVE PARTITIONING' }), 'Remove partitioning'|trans, { - 'class': 'button ajax', + 'class': 'btn btn-secondary ajax', 'id': 'remove_partitioning' }) }} diff --git a/templates/table/structure/display_structure.twig b/templates/table/structure/display_structure.twig index 7c9359fb5b..65f3e2debb 100644 --- a/templates/table/structure/display_structure.twig +++ b/templates/table/structure/display_structure.twig @@ -528,18 +528,6 @@ {% set first_sub_partition = sub_partitions[0] %} {% endif %} - {% set action_icons = { - 'ANALYZE': get_icon('b_search', 'Analyze'|trans), - 'CHECK': get_icon('eye', 'Check'|trans), - 'OPTIMIZE': get_icon('normalize', 'Optimize'|trans), - 'REBUILD': get_icon('s_tbl', 'Rebuild'|trans), - 'REPAIR': get_icon('b_tblops', 'Repair'|trans), - 'TRUNCATE': get_icon('b_empty', 'Truncate'|trans), - } %} - {% if range_or_list %} - {% set action_icons = action_icons|merge({'DROP': get_icon('b_drop', 'Drop'|trans)}) %} - {% endif %} -