From cde6b9008c331851fc9c4e51c976d170c4a6b165 Mon Sep 17 00:00:00 2001 From: Jakub Vrana Date: Mon, 14 Apr 2025 13:51:43 +0200 Subject: [PATCH] Move partitioning functions --- adminer/create.inc.php | 74 ++++++++++++++++----------------- adminer/drivers/mysql.inc.php | 18 +++++++- adminer/include/driver.inc.php | 8 ++++ adminer/include/editing.inc.php | 14 ------- 4 files changed, 59 insertions(+), 55 deletions(-) diff --git a/adminer/create.inc.php b/adminer/create.inc.php index cf28adf2..4eddfba4 100644 --- a/adminer/create.inc.php +++ b/adminer/create.inc.php @@ -2,10 +2,8 @@ namespace Adminer; $TABLE = $_GET["create"]; -$partition_by = array(); -foreach (array('HASH', 'LINEAR HASH', 'KEY', 'LINEAR KEY', 'RANGE', 'LIST') as $key) { - $partition_by[$key] = $key; -} +$partition_by = driver()->partitionBy; +$partitions_info = driver()->partitionsInfo($TABLE); $referencable_primary = referencable_primary($TABLE); $foreign_keys = array(); @@ -81,39 +79,37 @@ if ($_POST && !process_fields($row["fields"]) && !$error) { } $partitioning = ""; - if (support("partitioning")) { - if (isset($partition_by[$row["partition_by"]])) { - $params = array(); - foreach ($row as $key => $val) { - if (preg_match('~^partition~', $key)) { - $params[$key] = $val; - } + if (in_array($row["partition_by"], $partition_by)) { + $params = array(); + foreach ($row as $key => $val) { + if (preg_match('~^partition~', $key)) { + $params[$key] = $val; } - foreach ($params["partition_names"] as $key => $name) { - if ($name == "") { - unset($params["partition_names"][$key]); - unset($params["partition_values"][$key]); - } - } - if ($params != get_partitions_info($TABLE)) { - $partitions = array(); - if ($params["partition_by"] == 'RANGE' || $params["partition_by"] == 'LIST') { - foreach ($params["partition_names"] as $key => $name) { - $value = $params["partition_values"][$key]; - $partitions[] = "\n PARTITION " . idf_escape($name) . " VALUES " . ($params["partition_by"] == 'RANGE' ? "LESS THAN" : "IN") . ($value != "" ? " ($value)" : " MAXVALUE"); //! SQL injection - } - } - // $params["partition"] can be expression, not only column - $partitioning .= "\nPARTITION BY $params[partition_by]($params[partition])"; - if ($partitions) { - $partitioning .= " (" . implode(",", $partitions) . "\n)"; - } elseif ($params["partitions"]) { - $partitioning .= " PARTITIONS " . (+$params["partitions"]); - } - } - } elseif (preg_match("~partitioned~", $table_status["Create_options"])) { - $partitioning .= "\nREMOVE PARTITIONING"; } + foreach ($params["partition_names"] as $key => $name) { + if ($name == "") { + unset($params["partition_names"][$key]); + unset($params["partition_values"][$key]); + } + } + if ($params != $partitions_info) { + $partitions = array(); + if ($params["partition_by"] == 'RANGE' || $params["partition_by"] == 'LIST') { + foreach ($params["partition_names"] as $key => $name) { + $value = $params["partition_values"][$key]; + $partitions[] = "\n PARTITION " . idf_escape($name) . " VALUES " . ($params["partition_by"] == 'RANGE' ? "LESS THAN" : "IN") . ($value != "" ? " ($value)" : " MAXVALUE"); //! SQL injection + } + } + // $params["partition"] can be expression, not only column + $partitioning .= "\nPARTITION BY $params[partition_by]($params[partition])"; + if ($partitions) { + $partitioning .= " (" . implode(",", $partitions) . "\n)"; + } elseif ($params["partitions"]) { + $partitioning .= " PARTITIONS " . (+$params["partitions"]); + } + } + } elseif (preg_match("~partitioned~", $table_status["Create_options"])) { + $partitioning .= "\nREMOVE PARTITIONING"; } $message = lang('Table has been altered.'); @@ -159,8 +155,8 @@ if (!$_POST) { $row["fields"][] = $field; } - if (support("partitioning")) { - $row += get_partitions_info($TABLE); + if ($partition_by) { + $row += $partitions_info; $row["partition_names"][] = ""; $row["partition_values"][] = ""; } @@ -221,10 +217,10 @@ if (support("columns")) { " . html_select("partition_by", array("" => "") + $partition_by, $row["partition_by"]) . on_help("event.target.value.replace(/./, 'PARTITION BY \$&')", 1) . script("qsl('select').onchange = partitionByChange;"); + echo "

" . html_select("partition_by", array_merge(array(""), $partition_by), $row["partition_by"]) . on_help("event.target.value.replace(/./, 'PARTITION BY \$&')", 1) . script("qsl('select').onchange = partitionByChange;"); echo "()\n"; echo lang('Partitions') . ": \n"; echo "\n"; diff --git a/adminer/drivers/mysql.inc.php b/adminer/drivers/mysql.inc.php index 33f5ef4b..4309de3d 100644 --- a/adminer/drivers/mysql.inc.php +++ b/adminer/drivers/mysql.inc.php @@ -258,6 +258,9 @@ if (!defined('Adminer\DRIVER')) { $this->types[lang('Numbers')]["vector"] = 16383; $this->insertFunctions['vector'] = 'string_to_vector'; } + if (min_version(5.1, '', $connection)) { + $this->partitionBy = array("HASH", "LINEAR HASH", "KEY", "LINEAR KEY", "RANGE", "LIST"); + } if (min_version(5.7, 10.2, $connection)) { $this->generated = array("STORED", "VIRTUAL"); } @@ -335,6 +338,17 @@ if (!defined('Adminer\DRIVER')) { } } + function partitionsInfo(string $table): array { + $from = "FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = " . q(DB) . " AND TABLE_NAME = " . q($table); + $result = connection()->query("SELECT PARTITION_METHOD, PARTITION_EXPRESSION, PARTITION_ORDINAL_POSITION $from ORDER BY PARTITION_ORDINAL_POSITION DESC LIMIT 1"); + $return = array(); + list($return["partition_by"], $return["partition"], $return["partitions"]) = $result->fetch_row(); + $partitions = get_key_vals("SELECT PARTITION_NAME, PARTITION_DESCRIPTION $from AND PARTITION_NAME != '' ORDER BY PARTITION_ORDINAL_POSITION"); + $return["partition_names"] = array_keys($partitions); + $return["partition_values"] = array_values($partitions); + return $return; + } + function hasCStyleEscapes(): bool { static $c_style; if ($c_style === null) { @@ -1012,10 +1026,10 @@ if (!defined('Adminer\DRIVER')) { } /** Check whether a feature is supported - * @param literal-string $feature "check|comment|copy|database|descidx|drop_col|dump|event|indexes|kill|materializedview|partitioning|privileges|procedure|processlist|routine|scheme|sequence|status|table|trigger|type|variables|view|view_trigger" + * @param literal-string $feature "check|comment|copy|database|descidx|drop_col|dump|event|indexes|kill|materializedview|privileges|procedure|processlist|routine|scheme|sequence|status|table|trigger|type|variables|view|view_trigger" */ function support(string $feature): bool { - return !preg_match("~scheme|sequence|type|view_trigger|materializedview" . (min_version(8) ? "" : "|descidx" . (min_version(5.1) ? "" : "|event|partitioning")) . (min_version('8.0.16', '10.2.1') ? "" : "|check") . "~", $feature); + return !preg_match("~scheme|sequence|type|view_trigger|materializedview" . (min_version(8) ? "" : "|descidx" . (min_version(5.1) ? "" : "|event")) . (min_version('8.0.16', '10.2.1') ? "" : "|check") . "~", $feature); } /** Kill a process diff --git a/adminer/include/driver.inc.php b/adminer/include/driver.inc.php index 8cd1b208..f3a59819 100644 --- a/adminer/include/driver.inc.php +++ b/adminer/include/driver.inc.php @@ -26,6 +26,7 @@ abstract class SqlDriver { /** @var list */ public $functions = array(); // functions used in select /** @var list */ public $grouping = array(); // grouping functions used in select /** @var string */ public $onActions = "RESTRICT|NO ACTION|CASCADE|SET NULL|SET DEFAULT"; // used in foreign_keys() + /** @var list */ public $partitionBy = array(); // supported partitioning types /** @var string */ public $inout = "IN|OUT|INOUT"; // used in routines /** @var string */ public $enumLength = "'(?:''|[^'\\\\]|\\\\.)*'"; // regular expression for parsing enum lengths /** @var list */ public $generated = array(); // allowed types of generated columns @@ -231,6 +232,13 @@ abstract class SqlDriver { return array(); } + /** Get partitions info + * @return array{partition_by?:string, partition?:string, partitions?:string, partition_names?:list, partition_values?:list} + */ + function partitionsInfo(string $table): array { + return array(); + } + /** Check if C-style escapes are supported */ function hasCStyleEscapes(): bool { return false; diff --git a/adminer/include/editing.inc.php b/adminer/include/editing.inc.php index 4af1f272..a7d3382a 100644 --- a/adminer/include/editing.inc.php +++ b/adminer/include/editing.inc.php @@ -201,20 +201,6 @@ function edit_type(string $key, array $field, array $collations, array $foreign_ ); } -/** Get partition info -* @return array{partition_by:string, partition:string, partitions:string, partition_names:list, partition_values:list} -*/ -function get_partitions_info(string $table): array { - $from = "FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = " . q(DB) . " AND TABLE_NAME = " . q($table); - $result = connection()->query("SELECT PARTITION_METHOD, PARTITION_EXPRESSION, PARTITION_ORDINAL_POSITION $from ORDER BY PARTITION_ORDINAL_POSITION DESC LIMIT 1"); - $return = array(); - list($return["partition_by"], $return["partition"], $return["partitions"]) = $result->fetch_row(); - $partitions = get_key_vals("SELECT PARTITION_NAME, PARTITION_DESCRIPTION $from AND PARTITION_NAME != '' ORDER BY PARTITION_ORDINAL_POSITION"); - $return["partition_names"] = array_keys($partitions); - $return["partition_values"] = array_values($partitions); - return $return; -} - /** Filter length value including enums */ function process_length(?string $length): string { $enum_length = driver()->enumLength;