Merge pull request #16508 from mauriciofauth/partitions-table

Create Table\PartitionController class
This commit is contained in:
Maurício Meneghini Fauth 2020-11-30 22:40:17 -03:00 committed by GitHub
commit 767f83a2d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 605 additions and 39 deletions

View File

@ -0,0 +1,211 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\Controllers\Table;
use PhpMyAdmin\Html\Generator;
use PhpMyAdmin\Response;
use PhpMyAdmin\Table\Partition;
use PhpMyAdmin\Template;
use function strlen;
final class PartitionController extends AbstractController
{
/** @var Partition */
private $model;
/**
* @param Response $response
* @param string $db
* @param string $table
* @param Partition $partition
*/
public function __construct($response, Template $template, $db, $table, $partition)
{
parent::__construct($response, $template, $db, $table);
$this->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,
]);
}
}

View File

@ -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();

View File

@ -0,0 +1,138 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\Table;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Util;
use function sprintf;
final class Partition
{
/** @var DatabaseInterface */
private $dbi;
public function __construct(DatabaseInterface $dbi)
{
$this->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];
}
}

View File

@ -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']);

View File

@ -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'],

View File

@ -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' => [

View File

@ -0,0 +1,36 @@
<div class="container-fluid">
<h2>{% trans 'Analyze partition' %}</h2>
{{ message|raw }}
{% for name, table in rows %}
<div class="card mb-3">
<div class="card-header">{{ name }} ({{ partition_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,36 @@
<div class="container-fluid">
<h2>{% trans 'Check partition' %}</h2>
{{ message|raw }}
{% for name, table in rows %}
<div class="card mb-3">
<div class="card-header">{{ name }} ({{ partition_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 %}
</div>

View File

@ -0,0 +1,5 @@
<div class="container-fluid">
<h2>{% trans 'Drop partition' %}</h2>
{{ message|raw }}
</div>

View File

@ -0,0 +1,36 @@
<div class="container-fluid">
<h2>{% trans 'Optimize partition' %}</h2>
{{ message|raw }}
{% for name, table in rows %}
<div class="card mb-3">
<div class="card-header">{{ name }} ({{ partition_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,5 @@
<div class="container-fluid">
<h2>{% trans 'Rebuild partition' %}</h2>
{{ message|raw }}
</div>

View File

@ -0,0 +1,36 @@
<div class="container-fluid">
<h2>{% trans 'Repair partition' %}</h2>
{{ message|raw }}
{% for name, table in rows %}
<div class="card mb-3">
<div class="card-header">{{ name }} ({{ partition_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

@ -0,0 +1,5 @@
<div class="container-fluid">
<h2>{% trans 'Truncate partition' %}</h2>
{{ message|raw }}
</div>

View File

@ -74,18 +74,78 @@
<span class="unit">{{ index_length[1] }}</span>
</td>
<td>{{ partition.getComment() }}</td>
{% for action, icon in action_icons %}
<td>
<a id="partition_action_{{ action }}" class="ajax" href="{{ url('/table/structure/partitioning') }}" data-post="{{ get_common({
'db': db,
'table': table,
'sql_query': 'ALTER TABLE ' ~ backquote(table) ~ ' ' ~ action ~ ' PARTITION ' ~ partition.getName(),
'partition_maintenance': true
}) }}">
{{ icon|raw }}
</a>
</td>
{% endfor %}
<td>
<a id="partition_action_ANALYZE" class="ajax" href="{{ url('/table/partition/analyze') }}" data-post="{{ get_common({
'db': db,
'table': table,
'partition_name': partition.getName(),
}) }}">
{{ get_icon('b_search', 'Analyze'|trans) }}
</a>
</td>
<td>
<a id="partition_action_CHECK" class="ajax" href="{{ url('/table/partition/check') }}" data-post="{{ get_common({
'db': db,
'table': table,
'partition_name': partition.getName(),
}) }}">
{{ get_icon('eye', 'Check'|trans) }}
</a>
</td>
<td>
<a id="partition_action_OPTIMIZE" class="ajax" href="{{ url('/table/partition/optimize') }}" data-post="{{ get_common({
'db': db,
'table': table,
'partition_name': partition.getName(),
}) }}">
{{ get_icon('normalize', 'Optimize'|trans) }}
</a>
</td>
<td>
<a id="partition_action_REBUILD" class="ajax" href="{{ url('/table/partition/rebuild') }}" data-post="{{ get_common({
'db': db,
'table': table,
'partition_name': partition.getName(),
}) }}">
{{ get_icon('s_tbl', 'Rebuild'|trans) }}
</a>
</td>
<td>
<a id="partition_action_REPAIR" class="ajax" href="{{ url('/table/partition/repair') }}" data-post="{{ get_common({
'db': db,
'table': table,
'partition_name': partition.getName(),
}) }}">
{{ get_icon('b_tblops', 'Repair'|trans) }}
</a>
</td>
<td>
<a id="partition_action_TRUNCATE" class="ajax" href="{{ url('/table/partition/truncate') }}" data-post="{{ get_common({
'db': db,
'table': table,
'partition_name': partition.getName(),
}) }}">
{{ get_icon('b_empty', 'Truncate'|trans) }}
</a>
</td>
{% if range_or_list %}
<td>
<a id="partition_action_DROP" class="ajax" href="{{ url('/table/partition/drop') }}" data-post="{{ get_common({
'db': db,
'table': table,
'partition_name': partition.getName(),
}) }}">
{{ get_icon('b_drop', 'Drop'|trans) }}
</a>
</td>
{% 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'
}) }}
<input class="btn btn-secondary" type="submit" value="{% trans 'Edit partitioning' %}">

View File

@ -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 %}
<div id="partitions-2"{% if default_sliders_state != 'disabled' -%}
{{- default_sliders_state == 'closed' ? ' style="display: none; overflow:auto;"' }} class="pma_auto_slider" title="{% trans 'Partitions' %}"
{%- endif %}>
@ -554,7 +542,6 @@
'has_sub_partitions': has_sub_partitions,
'sub_partition_method': has_sub_partitions ? first_sub_partition.getMethod(),
'sub_partition_expression': has_sub_partitions ? first_sub_partition.getExpression(),
'action_icons': action_icons,
'range_or_list': range_or_list
} only %}
{% else %}