gl-website-deployer/admin/phpMyAdmin/libraries/classes/Partitioning/TablePartitionDefinition.php
2024-11-23 20:45:29 +01:00

199 lines
6.6 KiB
PHP

<?php
declare(strict_types=1);
namespace PhpMyAdmin\Partitioning;
use function array_intersect_key;
use function array_merge;
use function array_splice;
use function is_numeric;
use function min;
final class TablePartitionDefinition
{
/**
* @param array|null $details Details that may be pre-filled
*
* @return array
*/
public static function getDetails(?array $details = null): array
{
if (! isset($details)) {
$details = self::generateDetails();
}
return $details;
}
/**
* @return array
*/
private static function generateDetails(): array
{
$partitionDetails = self::extractDetailsFromRequest();
// Only LIST and RANGE type parameters allow subpartitioning
$partitionDetails['can_have_subpartitions'] = $partitionDetails['partition_count'] > 1
&& isset($partitionDetails['partition_by'])
&& ($partitionDetails['partition_by'] === 'RANGE'
|| $partitionDetails['partition_by'] === 'RANGE COLUMNS'
|| $partitionDetails['partition_by'] === 'LIST'
|| $partitionDetails['partition_by'] === 'LIST COLUMNS');
// Values are specified only for LIST and RANGE type partitions
$partitionDetails['value_enabled'] = isset($partitionDetails['partition_by'])
&& ($partitionDetails['partition_by'] === 'RANGE'
|| $partitionDetails['partition_by'] === 'RANGE COLUMNS'
|| $partitionDetails['partition_by'] === 'LIST'
|| $partitionDetails['partition_by'] === 'LIST COLUMNS');
return self::extractPartitions($partitionDetails);
}
/**
* Extract some partitioning and subpartitioning parameters from the request
*
* @return array
*/
private static function extractDetailsFromRequest(): array
{
$partitionParams = [
'partition_by' => null,
'partition_expr' => null,
'subpartition_by' => null,
'subpartition_expr' => null,
];
//Initialize details with values to "null" if not in request
$details = array_merge(
$partitionParams,
//Keep $_POST values, but only for keys that are in $partitionParams
array_intersect_key($_POST, $partitionParams)
);
$details['partition_count'] = self::extractPartitionCount('partition_count') ?: 0;
$details['subpartition_count'] = self::extractPartitionCount('subpartition_count') ?: 0;
return $details;
}
/**
* @param string $paramLabel Label searched in request
*/
private static function extractPartitionCount(string $paramLabel): int
{
if (isset($_POST[$paramLabel]) && is_numeric($_POST[$paramLabel])) {
// MySQL's limit is 8192, so do not allow more
// @see https://dev.mysql.com/doc/refman/en/partitioning-limitations.html
$count = min((int) $_POST[$paramLabel], 8192);
} else {
$count = 0;
}
return $count;
}
/**
* @param array $partitionDetails Details of partitions
*
* @return array
*/
private static function extractPartitions(array $partitionDetails): array
{
$partitionCount = $partitionDetails['partition_count'];
$subpartitionCount = $partitionDetails['subpartition_count'];
// No partitions
if ($partitionCount <= 1) {
return $partitionDetails;
}
// Has partitions
$partitions = $_POST['partitions'] ?? [];
// Remove details of the additional partitions
// when number of partitions have been reduced
array_splice($partitions, $partitionCount);
for ($i = 0; $i < $partitionCount; $i++) {
if (! isset($partitions[$i])) { // Newly added partition
$partitions[$i] = [
'name' => 'p' . $i,
'value_type' => '',
'value' => '',
'engine' => '',
'comment' => '',
'data_directory' => '',
'index_directory' => '',
'max_rows' => '',
'min_rows' => '',
'tablespace' => '',
'node_group' => '',
];
}
$partition =& $partitions[$i];
$partition['prefix'] = 'partitions[' . $i . ']';
// Changing from HASH/KEY to RANGE/LIST
if (! isset($partition['value_type'])) {
$partition['value_type'] = '';
$partition['value'] = '';
}
if (! isset($partition['engine'])) { // When removing subpartitioning
$partition['engine'] = '';
$partition['comment'] = '';
$partition['data_directory'] = '';
$partition['index_directory'] = '';
$partition['max_rows'] = '';
$partition['min_rows'] = '';
$partition['tablespace'] = '';
$partition['node_group'] = '';
}
// No subpartitions
if ($subpartitionCount < 2 || $partitionDetails['can_have_subpartitions'] !== true) {
unset($partition['subpartitions'], $partition['subpartition_count']);
continue;
}
// Has subpartitions
$partition['subpartition_count'] = $subpartitionCount;
if (! isset($partition['subpartitions'])) {
$partition['subpartitions'] = [];
}
$subpartitions =& $partition['subpartitions'];
// Remove details of the additional subpartitions
// when number of subpartitions have been reduced
array_splice($subpartitions, $subpartitionCount);
for ($j = 0; $j < $subpartitionCount; $j++) {
if (! isset($subpartitions[$j])) { // Newly added subpartition
$subpartitions[$j] = [
'name' => $partition['name'] . '_s' . $j,
'engine' => '',
'comment' => '',
'data_directory' => '',
'index_directory' => '',
'max_rows' => '',
'min_rows' => '',
'tablespace' => '',
'node_group' => '',
];
}
$subpartitions[$j]['prefix'] = 'partitions[' . $i . ']'
. '[subpartitions][' . $j . ']';
}
}
$partitionDetails['partitions'] = $partitions;
return $partitionDetails;
}
}