From 01fe709b7a99d2cab8fe53c002ee7bfb95bf524d Mon Sep 17 00:00:00 2001 From: Peter Knut Date: Sun, 21 Mar 2021 15:56:46 +0100 Subject: [PATCH 01/10] Replace deprecated "filtered" query with "bool" query - Allow to choose "must", "should", "must_not" condition. - Add system "_id" column to the field list. So it can be used in search condition. --- adminer/drivers/elastic.inc.php | 66 ++++++++++++++++----------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/adminer/drivers/elastic.inc.php b/adminer/drivers/elastic.inc.php index a6b2de8a..49d9eae4 100644 --- a/adminer/drivers/elastic.inc.php +++ b/adminer/drivers/elastic.inc.php @@ -122,7 +122,7 @@ if (isset($_GET["elastic"])) { function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) { global $adminer; $data = array(); - $query = "$table/_search"; + $query = (min_version(6) ? "" : "$table/") . "_search"; if ($select != array("*")) { $data["fields"] = $select; } @@ -142,21 +142,15 @@ if (isset($_GET["elastic"])) { } foreach ($where as $val) { list($col, $op, $val) = explode(" ", $val, 3); - if ($col == "_id") { - $data["query"]["ids"]["values"][] = $val; - } - elseif ($col . $val != "") { - $term = array("term" => array(($col != "" ? $col : "_all") => $val)); + if ($col . $val != "") { + $term = array(($col != "" ? $col : "_all") => $val); if ($op == "=") { - $data["query"]["filtered"]["filter"]["and"][] = $term; - } else { - $data["query"]["filtered"]["query"]["bool"]["must"][] = $term; + $data["query"]["bool"]["filter"][] = array("term" => $term); + } elseif (in_array($op, array("must", "should", "must_not"))) { + $data["query"]["bool"][$op][]["match"] = $term; } } } - if ($data["query"] && !$data["query"]["filtered"]["query"] && !$data["query"]["ids"]) { - $data["query"]["filtered"]["query"] = array("match_all" => array()); - } $start = microtime(true); $search = $this->_conn->query($query, $data); if ($print) { @@ -175,7 +169,7 @@ if (isset($_GET["elastic"])) { if ($select != array("*")) { $fields = array(); foreach ($select as $key) { - $fields[$key] = $hit['fields'][$key]; + $fields[$key] = $key == "_id" ? [$hit["_id"]] : $hit['fields'][$key]; } } foreach ($fields as $key => $val) { @@ -373,25 +367,31 @@ if (isset($_GET["elastic"])) { } } - $return = array(); - if ($mappings) { - foreach ($mappings as $name => $field) { - $return[$name] = array( - "field" => $name, - "full_type" => $field["type"], - "type" => $field["type"], - "privileges" => array( - "insert" => 1, - "select" => 1, - "update" => 1, - "where" => !isset($field["index"]) || $field["index"] ?: null, - "order" => $field["type"] != "text" ?: null - ), - ); - if ($field["properties"]) { // only leaf fields can be edited - unset($return[$name]["privileges"]["insert"]); - unset($return[$name]["privileges"]["update"]); - } + $return = array( + "_id" => array( + "field" => "_id", + "full_type" => "text", + "type" => "text", + "privileges" => array("insert" => 1, "select" => 1, "where" => 1, "order" => 1), + ) + ); + + foreach ($mappings as $name => $field) { + $return[$name] = array( + "field" => $name, + "full_type" => $field["type"], + "type" => $field["type"], + "privileges" => array( + "insert" => 1, + "select" => 1, + "update" => 1, + "where" => !isset($field["index"]) || $field["index"] ?: null, + "order" => $field["type"] != "text" ?: null + ), + ); + if ($field["properties"]) { // only leaf fields can be edited + unset($return[$name]["privileges"]["insert"]); + unset($return[$name]["privileges"]["update"]); } } return $return; @@ -494,7 +494,7 @@ if (isset($_GET["elastic"])) { return array( 'possible_drivers' => array("json + allow_url_fopen"), 'jush' => "elastic", - 'operators' => array("=", "query"), + 'operators' => array("=", "must", "should", "must_not"), 'functions' => array(), 'grouping' => array(), 'edit_functions' => array(array("json")), From e8c9164a7797730985e6f7ba137bc19d965725ba Mon Sep 17 00:00:00 2001 From: Peter Knut Date: Sun, 21 Mar 2021 20:40:43 +0100 Subject: [PATCH 02/10] Fix searching if "anywhere" field is selected - Allow to search only in fields with index. --- adminer/drivers/elastic.inc.php | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/adminer/drivers/elastic.inc.php b/adminer/drivers/elastic.inc.php index 49d9eae4..22da0a4b 100644 --- a/adminer/drivers/elastic.inc.php +++ b/adminer/drivers/elastic.inc.php @@ -141,9 +141,25 @@ if (isset($_GET["elastic"])) { } } foreach ($where as $val) { - list($col, $op, $val) = explode(" ", $val, 3); - if ($col . $val != "") { - $term = array(($col != "" ? $col : "_all") => $val); + if (preg_match('~^\((.+ OR .+)\)$~', $val, $matches)) { + $parts = explode(" OR ", $matches[1]); + $terms = array(); + foreach ($parts as $part) { + list($col, $op, $val) = explode(" ", $part, 3); + $term = array($col => $val); + if ($op == "=") { + $terms[] = array("term" => $term); + } elseif (in_array($op, array("must", "should", "must_not"))) { + $data["query"]["bool"][$op][]["match"] = $term; + } + } + + if (!empty($terms)) { + $data["query"]["bool"]["filter"][]["bool"]["should"] = $terms; + } + } else { + list($col, $op, $val) = explode(" ", $val, 3); + $term = array($col => $val); if ($op == "=") { $data["query"]["bool"]["filter"][] = array("term" => $term); } elseif (in_array($op, array("must", "should", "must_not"))) { @@ -377,6 +393,8 @@ if (isset($_GET["elastic"])) { ); foreach ($mappings as $name => $field) { + if (isset($field["index"]) && !$field["index"]) continue; + $return[$name] = array( "field" => $name, "full_type" => $field["type"], From 857cbf03f205f0c73fcaff0f0146dc40256c24c7 Mon Sep 17 00:00:00 2001 From: Peter Knut Date: Sat, 3 Apr 2021 15:19:53 +0200 Subject: [PATCH 03/10] Fix version condition for deprecated mapping types Mapping types are still supported in version 6, but only one mapping type can be created. In version 7, mapping types are deprecated and there is only one system '_doc' mapping type. See: https://www.elastic.co/guide/en/elasticsearch/reference/6.0/removal-of-types.html --- adminer/drivers/elastic.inc.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/adminer/drivers/elastic.inc.php b/adminer/drivers/elastic.inc.php index 22da0a4b..a069cf85 100644 --- a/adminer/drivers/elastic.inc.php +++ b/adminer/drivers/elastic.inc.php @@ -122,7 +122,7 @@ if (isset($_GET["elastic"])) { function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) { global $adminer; $data = array(); - $query = (min_version(6) ? "" : "$table/") . "_search"; + $query = (min_version(7) ? "" : "$table/") . "_search"; if ($select != array("*")) { $data["fields"] = $select; } @@ -307,7 +307,7 @@ if (isset($_GET["elastic"])) { function tables_list() { global $connection; - if (min_version(6)) { + if (min_version(7)) { return array('_doc' => 'table'); } @@ -368,7 +368,7 @@ if (isset($_GET["elastic"])) { global $connection; $mappings = array(); - if (min_version(6)) { + if (min_version(7)) { $result = $connection->query("_mapping"); if ($result) { $mappings = $result[$connection->_db]['mappings']['properties']; From 49effeff090bc33fc9d9a1ffde98311242684318 Mon Sep 17 00:00:00 2001 From: Peter Knut Date: Mon, 5 Apr 2021 00:13:07 +0200 Subject: [PATCH 04/10] Fix global search in all tables --- adminer/db.inc.php | 2 +- adminer/drivers/elastic.inc.php | 20 +++++++++++++++++++- adminer/include/driver.inc.php | 8 ++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/adminer/db.inc.php b/adminer/db.inc.php index 6c879fce..4b3974ec 100644 --- a/adminer/db.inc.php +++ b/adminer/db.inc.php @@ -61,7 +61,7 @@ if ($adminer->homepage()) { echo " \n"; echo "\n"; if ($_POST["search"] && $_POST["query"] != "") { - $_GET["where"][0]["op"] = "LIKE %%"; + $_GET["where"][0]["op"] = $driver->convertOperator("LIKE %%"); search_tables(); } } diff --git a/adminer/drivers/elastic.inc.php b/adminer/drivers/elastic.inc.php index a069cf85..86192399 100644 --- a/adminer/drivers/elastic.inc.php +++ b/adminer/drivers/elastic.inc.php @@ -55,6 +55,14 @@ if (isset($_GET["elastic"])) { * @return array|false */ function query($path, array $content = null, $method = 'GET') { + // Support for global search through all tables + if ($path != "" && $path[0] == "S" && preg_match('/SELECT 1 FROM ([^ ]+) WHERE (.+) LIMIT ([0-9]+)/', $path, $matches)) { + global $driver; + + $where = explode(" AND ", $matches[2]); + + return $driver->select($matches[1], array("*"), $where, null, array(), $matches[3]); + } return $this->rootQuery(($this->_db != "" ? "$this->_db/" : "/") . ltrim($path, '/'), $content, $method); } @@ -108,7 +116,9 @@ if (isset($_GET["elastic"])) { } function fetch_row() { - return array_values($this->fetch_assoc()); + $row = $this->fetch_assoc(); + + return $row ? array_values($row) : false; } } @@ -242,6 +252,10 @@ if (isset($_GET["elastic"])) { } return $this->_conn->affected_rows; } + + function convertOperator($operator) { + return $operator == "LIKE %%" ? "should" : $operator; + } } @@ -279,6 +293,10 @@ if (isset($_GET["elastic"])) { return $return; } + function limit($query, $where, $limit, $offset = 0, $separator = " ") { + return " $query$where" . ($limit !== null ? $separator . "LIMIT $limit" . ($offset ? " OFFSET $offset" : "") : ""); + } + function collations() { return array(); } diff --git a/adminer/include/driver.inc.php b/adminer/include/driver.inc.php index 99582bd4..bdee7a8d 100644 --- a/adminer/include/driver.inc.php +++ b/adminer/include/driver.inc.php @@ -142,6 +142,14 @@ function add_driver($id, $name) { return $idf; } + /** Convert operator so it can be used in search + * @param string $operator + * @return string + */ + function convertOperator($operator) { + return $operator; + } + /** Convert value returned by database to actual value * @param string * @param array From c3e2e6c58fc968f1cb15ecba07d332ec141f5a8c Mon Sep 17 00:00:00 2001 From: Peter Knut Date: Sat, 18 Sep 2021 23:05:43 +0200 Subject: [PATCH 05/10] Compatibility with Elasticsearch 7.14 - Removed empty body from requests. - Fix deleting records. --- adminer/drivers/elastic.inc.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/adminer/drivers/elastic.inc.php b/adminer/drivers/elastic.inc.php index 86192399..ec4fae1d 100644 --- a/adminer/drivers/elastic.inc.php +++ b/adminer/drivers/elastic.inc.php @@ -231,10 +231,10 @@ if (isset($_GET["elastic"])) { function delete($type, $queryWhere, $limit = 0) { //! use $limit $ids = array(); - if (is_array($_GET["where"]) && $_GET["where"]["_id"]) { + if (isset($_GET["where"]["_id"]) && $_GET["where"]["_id"]) { $ids[] = $_GET["where"]["_id"]; } - if (is_array($_POST['check'])) { + if (isset($_POST['check'])) { foreach ($_POST['check'] as $check) { $parts = preg_split('~ *= *~', $check); if (count($parts) == 2) { @@ -245,8 +245,8 @@ if (isset($_GET["elastic"])) { $this->_conn->affected_rows = 0; foreach ($ids as $id) { $query = "{$type}/{$id}"; - $response = $this->_conn->query($query, '{}', 'DELETE'); - if (is_array($response) && $response['found'] == true) { + $response = $this->_conn->query($query, null, 'DELETE'); + if ((isset($response['found']) && $response['found']) || (isset($response['result']) && $response['result'] == 'deleted')) { $this->_conn->affected_rows++; } } @@ -474,7 +474,7 @@ if (isset($_GET["elastic"])) { */ function drop_databases($databases) { global $connection; - return $connection->rootQuery(urlencode(implode(',', $databases)), array(), 'DELETE'); + return $connection->rootQuery(urlencode(implode(',', $databases)), null, 'DELETE'); } /** Alter type @@ -505,7 +505,7 @@ if (isset($_GET["elastic"])) { global $connection; $return = true; foreach ($tables as $table) { //! convert to bulk api - $return = $return && $connection->query(urlencode($table), array(), 'DELETE'); + $return = $return && $connection->query(urlencode($table), null, 'DELETE'); } return $return; } From ee42077e5415b22ac054470cc6ef381503112af9 Mon Sep 17 00:00:00 2001 From: Peter Knut Date: Sun, 17 Mar 2024 12:54:43 +0100 Subject: [PATCH 06/10] Improve code readability by using of empty lines --- adminer/drivers/elastic.inc.php | 92 +++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 21 deletions(-) diff --git a/adminer/drivers/elastic.inc.php b/adminer/drivers/elastic.inc.php index ec4fae1d..e3022715 100644 --- a/adminer/drivers/elastic.inc.php +++ b/adminer/drivers/elastic.inc.php @@ -16,6 +16,7 @@ if (isset($_GET["elastic"])) { */ function rootQuery($path, array $content = null, $method = 'GET') { @ini_set('track_errors', 1); // @ - may be disabled + $file = @file_get_contents("$this->_url/" . ltrim($path, '/'), false, stream_context_create(array('http' => array( 'method' => $method, 'content' => $content !== null ? json_encode($content) : null, @@ -63,6 +64,7 @@ if (isset($_GET["elastic"])) { return $driver->select($matches[1], array("*"), $where, null, array(), $matches[3]); } + return $this->rootQuery(($this->_db != "" ? "$this->_db/" : "/") . ltrim($path, '/'), $content, $method); } @@ -91,13 +93,13 @@ if (isset($_GET["elastic"])) { function select_db($database) { $this->_db = $database; + return true; } function quote($string) { return $string; } - } class Min_Result { @@ -106,12 +108,14 @@ if (isset($_GET["elastic"])) { function __construct($rows) { $this->num_rows = count($rows); $this->_rows = $rows; + reset($this->_rows); } function fetch_assoc() { $return = current($this->_rows); next($this->_rows); + return $return; } @@ -120,22 +124,19 @@ if (isset($_GET["elastic"])) { return $row ? array_values($row) : false; } - } - } - - class Min_Driver extends Min_SQL { function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) { global $adminer; + $data = array(); - $query = (min_version(7) ? "" : "$table/") . "_search"; if ($select != array("*")) { $data["fields"] = $select; } + if ($order) { $sort = array(); foreach ($order as $col) { @@ -144,12 +145,14 @@ if (isset($_GET["elastic"])) { } $data["sort"] = $sort; } + if ($limit) { $data["size"] = +$limit; if ($page) { $data["from"] = ($page * $limit); } } + foreach ($where as $val) { if (preg_match('~^\((.+ OR .+)\)$~', $val, $matches)) { $parts = explode(" OR ", $matches[1]); @@ -177,20 +180,25 @@ if (isset($_GET["elastic"])) { } } } + + $query = (min_version(7) ? "" : "$table/") . "_search"; $start = microtime(true); $search = $this->_conn->query($query, $data); + if ($print) { echo $adminer->selectQuery("$query: " . json_encode($data), $start, !$search); } if (!$search) { return false; } + $return = array(); foreach ($search['hits']['hits'] as $hit) { $row = array(); if ($select == array("*")) { $row["_id"] = $hit["_id"]; } + $fields = $hit['_source']; if ($select != array("*")) { $fields = array(); @@ -198,14 +206,17 @@ if (isset($_GET["elastic"])) { $fields[$key] = $key == "_id" ? [$hit["_id"]] : $hit['fields'][$key]; } } + foreach ($fields as $key => $val) { if ($data["fields"]) { $val = $val[0]; } $row[$key] = (is_array($val) ? json_encode($val) : $val); //! display JSON and others differently } + $return[] = $row; } + return new Min_Result($return); } @@ -215,8 +226,10 @@ if (isset($_GET["elastic"])) { if (count($parts) == 2) { $id = trim($parts[1]); $query = "$type/$id"; + return $this->_conn->query($query, $record, 'POST'); } + return false; } @@ -225,6 +238,7 @@ if (isset($_GET["elastic"])) { $query = "$type/$id"; $response = $this->_conn->query($query, $record, 'POST'); $this->_conn->last_id = $response['_id']; + return $response['created']; } @@ -242,7 +256,9 @@ if (isset($_GET["elastic"])) { } } } + $this->_conn->affected_rows = 0; + foreach ($ids as $id) { $query = "{$type}/{$id}"; $response = $this->_conn->query($query, null, 'DELETE'); @@ -250,6 +266,7 @@ if (isset($_GET["elastic"])) { $this->_conn->affected_rows++; } } + return $this->_conn->affected_rows; } @@ -258,18 +275,20 @@ if (isset($_GET["elastic"])) { } } - - function connect() { global $adminer; + $connection = new Min_DB; + list($server, $username, $password) = $adminer->credentials(); if ($password != "" && $connection->connect($server, $username, "")) { return lang('Database does not support password.'); } + if ($connection->connect($server, $username, $password)) { return $connection; } + return $connection->error; } @@ -279,17 +298,21 @@ if (isset($_GET["elastic"])) { function logged_user() { global $adminer; + $credentials = $adminer->credentials(); + return $credentials[1]; } function get_databases() { global $connection; + $return = $connection->rootQuery('_aliases'); if ($return) { $return = array_keys($return); sort($return, SORT_STRING); } + return $return; } @@ -302,6 +325,7 @@ if (isset($_GET["elastic"])) { } function db_collation($db, $collations) { + // } function engines() { @@ -310,8 +334,10 @@ if (isset($_GET["elastic"])) { function count_tables($databases) { global $connection; - $return = array(); + $result = $connection->query('_stats'); + + $return = array(); if ($result && $result['indices']) { $indices = $result['indices']; foreach ($indices as $indice => $stats) { @@ -319,6 +345,7 @@ if (isset($_GET["elastic"])) { $return[$indice] = $indexing['index_total']; } } + return $return; } @@ -333,11 +360,13 @@ if (isset($_GET["elastic"])) { if ($return) { $return = array_fill_keys(array_keys($return[$connection->_db]["mappings"]), 'table'); } + return $return; } function table_status($name = "", $fast = false) { global $connection; + $search = $connection->query("_search", array( "size" => 0, "aggregations" => array( @@ -348,25 +377,31 @@ if (isset($_GET["elastic"])) { ) ) ), "POST"); + $return = array(); + if ($search) { $tables = $search["aggregations"]["count_by_type"]["buckets"]; + foreach ($tables as $table) { $return[$table["key"]] = array( "Name" => $table["key"], "Engine" => "table", "Rows" => $table["doc_count"], ); + if ($name != "" && $name == $table["key"]) { return $return[$name]; } } } + return $return; } function error() { global $connection; + return h($connection->error); } @@ -386,6 +421,7 @@ if (isset($_GET["elastic"])) { global $connection; $mappings = array(); + if (min_version(7)) { $result = $connection->query("_mapping"); if ($result) { @@ -425,11 +461,13 @@ if (isset($_GET["elastic"])) { "order" => $field["type"] != "text" ?: null ), ); + if ($field["properties"]) { // only leaf fields can be edited unset($return[$name]["privileges"]["insert"]); unset($return[$name]["privileges"]["update"]); } } + return $return; } @@ -446,6 +484,7 @@ if (isset($_GET["elastic"])) { } function convert_field($field) { + // } function unconvert_field($field, $return) { @@ -453,6 +492,7 @@ if (isset($_GET["elastic"])) { } function fk_support($table_status) { + // } function found_rows($table_status, $where) { @@ -460,29 +500,32 @@ if (isset($_GET["elastic"])) { } /** Create index - * @param string - * @return mixed - */ + * @param string + * @return mixed + */ function create_database($db) { global $connection; + return $connection->rootQuery(urlencode($db), null, 'PUT'); } /** Remove index - * @param array - * @return mixed - */ + * @param array + * @return mixed + */ function drop_databases($databases) { global $connection; + return $connection->rootQuery(urlencode(implode(',', $databases)), null, 'DELETE'); } /** Alter type - * @param array - * @return mixed - */ + * @param array + * @return mixed + */ function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) { global $connection; + $properties = array(); foreach ($fields as $f) { $field_name = trim($f[1][0]); @@ -491,33 +534,39 @@ if (isset($_GET["elastic"])) { 'type' => $field_type ); } + if (!empty($properties)) { $properties = array('properties' => $properties); } + return $connection->query("_mapping/{$name}", $properties, 'PUT'); } /** Drop types - * @param array - * @return bool - */ + * @param array + * @return bool + */ function drop_tables($tables) { global $connection; + $return = true; foreach ($tables as $table) { //! convert to bulk api $return = $return && $connection->query(urlencode($table), null, 'DELETE'); } + return $return; } function last_id() { global $connection; + return $connection->last_id; } function driver_config() { $types = array(); $structured_types = array(); + foreach (array( lang('Numbers') => array("long" => 3, "integer" => 5, "short" => 8, "byte" => 10, "double" => 20, "float" => 66, "half_float" => 12, "scaled_float" => 21), lang('Date and time') => array("date" => 10), @@ -527,6 +576,7 @@ if (isset($_GET["elastic"])) { $types += $val; $structured_types[$key] = array_keys($val); } + return array( 'possible_drivers' => array("json + allow_url_fopen"), 'jush' => "elastic", From 6beb07a181989b9cbf69738683a6c0345dff74b1 Mon Sep 17 00:00:00 2001 From: Peter Knut Date: Sat, 3 Apr 2021 12:35:58 +0200 Subject: [PATCH 07/10] New Elasticsearch 7 plugin as a copy of the old one --- adminer/drivers/elastic7.inc.php | 591 +++++++++++++++++++++++++++++++ 1 file changed, 591 insertions(+) create mode 100644 adminer/drivers/elastic7.inc.php diff --git a/adminer/drivers/elastic7.inc.php b/adminer/drivers/elastic7.inc.php new file mode 100644 index 00000000..48b967c2 --- /dev/null +++ b/adminer/drivers/elastic7.inc.php @@ -0,0 +1,591 @@ +_url/" . ltrim($path, '/'), false, stream_context_create(array('http' => array( + 'method' => $method, + 'content' => $content !== null ? json_encode($content) : null, + 'header' => $content !== null ? 'Content-Type: application/json' : [], + 'ignore_errors' => 1, + 'follow_location' => 0, + 'max_redirects' => 0, + )))); + + if ($file === false) { + $this->error = lang('Invalid server or credentials.'); + return false; + } + + $return = json_decode($file, true); + if ($return === null) { + $this->error = lang('Invalid server or credentials.'); + return false; + } + + if (!preg_match('~^HTTP/[0-9.]+ 2~i', $http_response_header[0])) { + if (isset($return['error']['root_cause'][0]['type'])) { + $this->error = $return['error']['root_cause'][0]['type'] . ": " . $return['error']['root_cause'][0]['reason']; + } else { + $this->error = lang('Invalid server or credentials.'); + } + return false; + } + + return $return; + } + + /** Performs query relative to actual selected DB + * @param string $path + * @param array|null $content + * @param string $method + * @return array|false + */ + function query($path, array $content = null, $method = 'GET') { + // Support for global search through all tables + if ($path != "" && $path[0] == "S" && preg_match('/SELECT 1 FROM ([^ ]+) WHERE (.+) LIMIT ([0-9]+)/', $path, $matches)) { + global $driver; + + $where = explode(" AND ", $matches[2]); + + return $driver->select($matches[1], array("*"), $where, null, array(), $matches[3]); + } + + return $this->rootQuery(($this->_db != "" ? "$this->_db/" : "/") . ltrim($path, '/'), $content, $method); + } + + /** + * @param string $server + * @param string $username + * @param string $password + * @return bool + */ + function connect($server, $username, $password) { + $this->_url = build_http_url($server, $username, $password, "localhost", 9200); + + $return = $this->query(''); + if (!$return) { + return false; + } + + if (!isset($return['version']['number'])) { + $this->error = lang('Invalid server or credentials.'); + return false; + } + + $this->server_info = $return['version']['number']; + return true; + } + + function select_db($database) { + $this->_db = $database; + + return true; + } + + function quote($string) { + return $string; + } + } + + class Min_Result { + var $num_rows, $_rows; + + function __construct($rows) { + $this->num_rows = count($rows); + $this->_rows = $rows; + + reset($this->_rows); + } + + function fetch_assoc() { + $return = current($this->_rows); + next($this->_rows); + + return $return; + } + + function fetch_row() { + $row = $this->fetch_assoc(); + + return $row ? array_values($row) : false; + } + } + } + + class Min_Driver extends Min_SQL { + + function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) { + global $adminer; + + $data = array(); + if ($select != array("*")) { + $data["fields"] = $select; + } + + if ($order) { + $sort = array(); + foreach ($order as $col) { + $col = preg_replace('~ DESC$~', '', $col, 1, $count); + $sort[] = ($count ? array($col => "desc") : $col); + } + $data["sort"] = $sort; + } + + if ($limit) { + $data["size"] = +$limit; + if ($page) { + $data["from"] = ($page * $limit); + } + } + + foreach ($where as $val) { + if (preg_match('~^\((.+ OR .+)\)$~', $val, $matches)) { + $parts = explode(" OR ", $matches[1]); + $terms = array(); + foreach ($parts as $part) { + list($col, $op, $val) = explode(" ", $part, 3); + $term = array($col => $val); + if ($op == "=") { + $terms[] = array("term" => $term); + } elseif (in_array($op, array("must", "should", "must_not"))) { + $data["query"]["bool"][$op][]["match"] = $term; + } + } + + if (!empty($terms)) { + $data["query"]["bool"]["filter"][]["bool"]["should"] = $terms; + } + } else { + list($col, $op, $val) = explode(" ", $val, 3); + $term = array($col => $val); + if ($op == "=") { + $data["query"]["bool"]["filter"][] = array("term" => $term); + } elseif (in_array($op, array("must", "should", "must_not"))) { + $data["query"]["bool"][$op][]["match"] = $term; + } + } + } + + $query = (min_version(7) ? "" : "$table/") . "_search"; + $start = microtime(true); + $search = $this->_conn->query($query, $data); + + if ($print) { + echo $adminer->selectQuery("$query: " . json_encode($data), $start, !$search); + } + if (!$search) { + return false; + } + + $return = array(); + foreach ($search['hits']['hits'] as $hit) { + $row = array(); + if ($select == array("*")) { + $row["_id"] = $hit["_id"]; + } + + $fields = $hit['_source']; + if ($select != array("*")) { + $fields = array(); + foreach ($select as $key) { + $fields[$key] = $key == "_id" ? [$hit["_id"]] : $hit['fields'][$key]; + } + } + + foreach ($fields as $key => $val) { + if ($data["fields"]) { + $val = $val[0]; + } + $row[$key] = (is_array($val) ? json_encode($val) : $val); //! display JSON and others differently + } + + $return[] = $row; + } + + return new Min_Result($return); + } + + function update($type, $record, $queryWhere, $limit = 0, $separator = "\n") { + //! use $limit + $parts = preg_split('~ *= *~', $queryWhere); + if (count($parts) == 2) { + $id = trim($parts[1]); + $query = "$type/$id"; + + return $this->_conn->query($query, $record, 'POST'); + } + + return false; + } + + function insert($type, $record) { + $id = ""; //! user should be able to inform _id + $query = "$type/$id"; + $response = $this->_conn->query($query, $record, 'POST'); + $this->_conn->last_id = $response['_id']; + + return $response['created']; + } + + function delete($type, $queryWhere, $limit = 0) { + //! use $limit + $ids = array(); + if (isset($_GET["where"]["_id"]) && $_GET["where"]["_id"]) { + $ids[] = $_GET["where"]["_id"]; + } + if (isset($_POST['check'])) { + foreach ($_POST['check'] as $check) { + $parts = preg_split('~ *= *~', $check); + if (count($parts) == 2) { + $ids[] = trim($parts[1]); + } + } + } + + $this->_conn->affected_rows = 0; + + foreach ($ids as $id) { + $query = "{$type}/{$id}"; + $response = $this->_conn->query($query, null, 'DELETE'); + if (isset($response['result']) && $response['result'] == 'deleted') { + $this->_conn->affected_rows++; + } + } + + return $this->_conn->affected_rows; + } + + function convertOperator($operator) { + return $operator == "LIKE %%" ? "should" : $operator; + } + } + + function connect() { + global $adminer; + + $connection = new Min_DB; + + list($server, $username, $password) = $adminer->credentials(); + if ($password != "" && $connection->connect($server, $username, "")) { + return lang('Database does not support password.'); + } + + if ($connection->connect($server, $username, $password)) { + return $connection; + } + + return $connection->error; + } + + function support($feature) { + return preg_match("~database|table|columns~", $feature); + } + + function logged_user() { + global $adminer; + + $credentials = $adminer->credentials(); + + return $credentials[1]; + } + + function get_databases() { + global $connection; + + $return = $connection->rootQuery('_aliases'); + if ($return) { + $return = array_keys($return); + sort($return, SORT_STRING); + } + + return $return; + } + + function limit($query, $where, $limit, $offset = 0, $separator = " ") { + return " $query$where" . ($limit !== null ? $separator . "LIMIT $limit" . ($offset ? " OFFSET $offset" : "") : ""); + } + + function collations() { + return array(); + } + + function db_collation($db, $collations) { + // + } + + function engines() { + return array(); + } + + function count_tables($databases) { + global $connection; + + $result = $connection->query('_stats'); + + $return = array(); + if ($result && $result['indices']) { + $indices = $result['indices']; + foreach ($indices as $indice => $stats) { + $indexing = $stats['total']['indexing']; + $return[$indice] = $indexing['index_total']; + } + } + + return $return; + } + + function tables_list() { + global $connection; + + if (min_version(7)) { + return array('_doc' => 'table'); + } + + $return = $connection->query('_mapping'); + if ($return) { + $return = array_fill_keys(array_keys($return[$connection->_db]["mappings"]), 'table'); + } + + return $return; + } + + function table_status($name = "", $fast = false) { + global $connection; + + $search = $connection->query("_search", array( + "size" => 0, + "aggregations" => array( + "count_by_type" => array( + "terms" => array( + "field" => "_type" + ) + ) + ) + ), "POST"); + + $return = array(); + + if ($search) { + $tables = $search["aggregations"]["count_by_type"]["buckets"]; + + foreach ($tables as $table) { + $return[$table["key"]] = array( + "Name" => $table["key"], + "Engine" => "table", + "Rows" => $table["doc_count"], + ); + + if ($name != "" && $name == $table["key"]) { + return $return[$name]; + } + } + } + + return $return; + } + + function error() { + global $connection; + + return h($connection->error); + } + + function information_schema() { + } + + function is_view($table_status) { + } + + function indexes($table, $connection2 = null) { + return array( + array("type" => "PRIMARY", "columns" => array("_id")), + ); + } + + function fields($table) { + global $connection; + + $mappings = array(); + + if (min_version(7)) { + $result = $connection->query("_mapping"); + if ($result) { + $mappings = $result[$connection->_db]['mappings']['properties']; + } + } else { + $result = $connection->query("$table/_mapping"); + if ($result) { + $mappings = $result[$table]['properties']; + if (!$mappings) { + $mappings = $result[$connection->_db]['mappings'][$table]['properties']; + } + } + } + + $return = array( + "_id" => array( + "field" => "_id", + "full_type" => "text", + "type" => "text", + "privileges" => array("insert" => 1, "select" => 1, "where" => 1, "order" => 1), + ) + ); + + foreach ($mappings as $name => $field) { + if (isset($field["index"]) && !$field["index"]) continue; + + $return[$name] = array( + "field" => $name, + "full_type" => $field["type"], + "type" => $field["type"], + "privileges" => array( + "insert" => 1, + "select" => 1, + "update" => 1, + "where" => !isset($field["index"]) || $field["index"] ?: null, + "order" => $field["type"] != "text" ?: null + ), + ); + + if ($field["properties"]) { // only leaf fields can be edited + unset($return[$name]["privileges"]["insert"]); + unset($return[$name]["privileges"]["update"]); + } + } + + return $return; + } + + function foreign_keys($table) { + return array(); + } + + function table($idf) { + return $idf; + } + + function idf_escape($idf) { + return $idf; + } + + function convert_field($field) { + // + } + + function unconvert_field($field, $return) { + return $return; + } + + function fk_support($table_status) { + // + } + + function found_rows($table_status, $where) { + return null; + } + + /** Create index + * @param string + * @return mixed + */ + function create_database($db) { + global $connection; + + return $connection->rootQuery(urlencode($db), null, 'PUT'); + } + + /** Remove index + * @param array + * @return mixed + */ + function drop_databases($databases) { + global $connection; + + return $connection->rootQuery(urlencode(implode(',', $databases)), null, 'DELETE'); + } + + /** Alter type + * @param array + * @return mixed + */ + function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) { + global $connection; + + $properties = array(); + foreach ($fields as $f) { + $field_name = trim($f[1][0]); + $field_type = trim($f[1][1] ? $f[1][1] : "text"); + $properties[$field_name] = array( + 'type' => $field_type + ); + } + + if (!empty($properties)) { + $properties = array('properties' => $properties); + } + + return $connection->query("_mapping/{$name}", $properties, 'PUT'); + } + + /** Drop types + * @param array + * @return bool + */ + function drop_tables($tables) { + global $connection; + + $return = true; + foreach ($tables as $table) { //! convert to bulk api + $return = $return && $connection->query(urlencode($table), null, 'DELETE'); + } + + return $return; + } + + function last_id() { + global $connection; + + return $connection->last_id; + } + + function driver_config() { + $types = array(); + $structured_types = array(); + + foreach (array( + lang('Numbers') => array("long" => 3, "integer" => 5, "short" => 8, "byte" => 10, "double" => 20, "float" => 66, "half_float" => 12, "scaled_float" => 21), + lang('Date and time') => array("date" => 10), + lang('Strings') => array("string" => 65535, "text" => 65535), + lang('Binary') => array("binary" => 255), + ) as $key => $val) { + $types += $val; + $structured_types[$key] = array_keys($val); + } + + return array( + 'possible_drivers' => array("json + allow_url_fopen"), + 'jush' => "elastic", + 'operators' => array("=", "must", "should", "must_not"), + 'functions' => array(), + 'grouping' => array(), + 'edit_functions' => array(array("json")), + 'types' => $types, + 'structured_types' => $structured_types, + ); + } +} From 32160b48ae862647e6c248112a5902b7b680d4db Mon Sep 17 00:00:00 2001 From: Peter Knut Date: Sat, 3 Apr 2021 23:40:45 +0200 Subject: [PATCH 08/10] Modify tables hierarchy for Elasticsearch 7 - Properly display list of databases, indexes, aliases and fields. - Fix search and delete queries. --- adminer/drivers/elastic7.inc.php | 208 +++++++++++++++++-------------- 1 file changed, 117 insertions(+), 91 deletions(-) diff --git a/adminer/drivers/elastic7.inc.php b/adminer/drivers/elastic7.inc.php index 48b967c2..ffc9ba73 100644 --- a/adminer/drivers/elastic7.inc.php +++ b/adminer/drivers/elastic7.inc.php @@ -5,8 +5,10 @@ if (isset($_GET["elastic7"])) { define("DRIVER", "elastic7"); if (function_exists('json_decode') && ini_bool('allow_url_fopen')) { + define("ELASTIC_DB_NAME", "elastic"); + class Min_DB { - var $extension = "JSON", $server_info, $errno, $error, $_url, $_db; + var $extension = "JSON", $server_info, $errno, $error, $_url; /** * @param string $path @@ -40,9 +42,10 @@ if (isset($_GET["elastic7"])) { if (!preg_match('~^HTTP/[0-9.]+ 2~i', $http_response_header[0])) { if (isset($return['error']['root_cause'][0]['type'])) { $this->error = $return['error']['root_cause'][0]['type'] . ": " . $return['error']['root_cause'][0]['reason']; - } else { - $this->error = lang('Invalid server or credentials.'); + } elseif (isset($return['status']) && isset($return['error']) && is_string($return['error'])) { + $this->error = $return['error']; } + return false; } @@ -65,7 +68,7 @@ if (isset($_GET["elastic7"])) { return $driver->select($matches[1], array("*"), $where, null, array(), $matches[3]); } - return $this->rootQuery(($this->_db != "" ? "$this->_db/" : "/") . ltrim($path, '/'), $content, $method); + return $this->rootQuery($path, $content, $method); } /** @@ -92,8 +95,6 @@ if (isset($_GET["elastic7"])) { } function select_db($database) { - $this->_db = $database; - return true; } @@ -181,37 +182,34 @@ if (isset($_GET["elastic7"])) { } } - $query = (min_version(7) ? "" : "$table/") . "_search"; + $query = "$table/_search"; $start = microtime(true); - $search = $this->_conn->query($query, $data); + $search = $this->_conn->rootQuery($query, $data); if ($print) { echo $adminer->selectQuery("$query: " . json_encode($data), $start, !$search); } - if (!$search) { + if (empty($search)) { return false; } $return = array(); - foreach ($search['hits']['hits'] as $hit) { + foreach ($search["hits"]["hits"] as $hit) { $row = array(); if ($select == array("*")) { $row["_id"] = $hit["_id"]; } - $fields = $hit['_source']; if ($select != array("*")) { $fields = array(); foreach ($select as $key) { - $fields[$key] = $key == "_id" ? [$hit["_id"]] : $hit['fields'][$key]; + $fields[$key] = $key == "_id" ? $hit["_id"] : $hit["_source"][$key]; } + } else { + $fields = $hit["_source"]; } - foreach ($fields as $key => $val) { - if ($data["fields"]) { - $val = $val[0]; - } - $row[$key] = (is_array($val) ? json_encode($val) : $val); //! display JSON and others differently + $row[$key] = (is_array($val) ? json_encode($val) : $val); } $return[] = $row; @@ -242,7 +240,7 @@ if (isset($_GET["elastic7"])) { return $response['created']; } - function delete($type, $queryWhere, $limit = 0) { + function delete($table, $queryWhere, $limit = 0) { //! use $limit $ids = array(); if (isset($_GET["where"]["_id"]) && $_GET["where"]["_id"]) { @@ -260,7 +258,7 @@ if (isset($_GET["elastic7"])) { $this->_conn->affected_rows = 0; foreach ($ids as $id) { - $query = "{$type}/{$id}"; + $query = "$table/_doc/$id"; $response = $this->_conn->query($query, null, 'DELETE'); if (isset($response['result']) && $response['result'] == 'deleted') { $this->_conn->affected_rows++; @@ -293,7 +291,7 @@ if (isset($_GET["elastic7"])) { } function support($feature) { - return preg_match("~database|table|columns~", $feature); + return preg_match("~table|columns~", $feature); } function logged_user() { @@ -305,15 +303,7 @@ if (isset($_GET["elastic7"])) { } function get_databases() { - global $connection; - - $return = $connection->rootQuery('_aliases'); - if ($return) { - $return = array_keys($return); - sort($return, SORT_STRING); - } - - return $return; + return array(ELASTIC_DB_NAME); } function limit($query, $where, $limit, $offset = 0, $separator = " ") { @@ -335,68 +325,105 @@ if (isset($_GET["elastic7"])) { function count_tables($databases) { global $connection; - $result = $connection->query('_stats'); - - $return = array(); - if ($result && $result['indices']) { - $indices = $result['indices']; - foreach ($indices as $indice => $stats) { - $indexing = $stats['total']['indexing']; - $return[$indice] = $indexing['index_total']; - } + $return = $connection->rootQuery('_aliases'); + if (empty($return)) { + return array( + ELASTIC_DB_NAME => 0 + ); } - return $return; + return array( + ELASTIC_DB_NAME => count($return) + ); } function tables_list() { global $connection; - if (min_version(7)) { - return array('_doc' => 'table'); + $aliases = $connection->rootQuery('_aliases'); + if (empty($aliases)) { + return array(); } - $return = $connection->query('_mapping'); - if ($return) { - $return = array_fill_keys(array_keys($return[$connection->_db]["mappings"]), 'table'); + ksort($aliases); + + $tables = array(); + foreach ($aliases as $name => $index) { + $tables[$name] = "table"; + + ksort($index["aliases"]); + $tables += array_fill_keys(array_keys($index["aliases"]), "view"); } - return $return; + return $tables; } function table_status($name = "", $fast = false) { global $connection; - $search = $connection->query("_search", array( - "size" => 0, - "aggregations" => array( - "count_by_type" => array( - "terms" => array( - "field" => "_type" - ) - ) - ) - ), "POST"); + $stats = $connection->rootQuery('_stats'); + $aliases = $connection->rootQuery('_aliases'); - $return = array(); + if (empty($stats) || empty($aliases)) { + return array(); + } - if ($search) { - $tables = $search["aggregations"]["count_by_type"]["buckets"]; + $result = array(); - foreach ($tables as $table) { - $return[$table["key"]] = array( - "Name" => $table["key"], - "Engine" => "table", - "Rows" => $table["doc_count"], - ); - - if ($name != "" && $name == $table["key"]) { - return $return[$name]; + if ($name != "") { + if (isset($stats["indices"][$name])) { + return format_index_status($name, $stats["indices"][$name]); + } else foreach ($aliases as $index_name => $index) { + foreach ($index["aliases"] as $alias_name => $alias) { + if ($alias_name == $name) { + return format_alias_status($alias_name, $stats["indices"][$index_name]); + } } } } - return $return; + ksort($stats["indices"]); + foreach ($stats["indices"] as $name => $index) { + if ($name[0] == ".") { + continue; + } + + $result[$name] = format_index_status($name, $index); + + if (!empty($aliases[$name]["aliases"])) { + ksort($aliases[$name]["aliases"]); + foreach ($aliases[$name]["aliases"] as $alias_name => $alias) { + $result[$alias_name] = format_alias_status($alias_name, $stats["indices"][$name]); + } + } + } + + return $result; + } + + function format_index_status($name, $index) { + return array( + "Name" => $name, + "Engine" => "Lucene", + "Oid" => $index["uuid"], + "Rows" => $index["total"]["docs"]["count"], + "Auto_increment" => 0, + "Data_length" => $index["total"]["store"]["size_in_bytes"], + "Index_length" => 0, + "Data_free" => $index["total"]["store"]["reserved_in_bytes"], + ); + } + + function format_alias_status($name, $index) { + return array( + "Name" => $name, + "Engine" => "view", + "Rows" => $index["total"]["docs"]["count"], + ); + } + + function is_view($table_status) { + return $table_status["Engine"] == "view"; } function error() { @@ -406,9 +433,7 @@ if (isset($_GET["elastic7"])) { } function information_schema() { - } - - function is_view($table_status) { + // } function indexes($table, $connection2 = null) { @@ -421,23 +446,26 @@ if (isset($_GET["elastic7"])) { global $connection; $mappings = array(); + $mapping = $connection->rootQuery("_mapping"); - if (min_version(7)) { - $result = $connection->query("_mapping"); - if ($result) { - $mappings = $result[$connection->_db]['mappings']['properties']; - } - } else { - $result = $connection->query("$table/_mapping"); - if ($result) { - $mappings = $result[$table]['properties']; - if (!$mappings) { - $mappings = $result[$connection->_db]['mappings'][$table]['properties']; + if (!isset($mapping[$table])) { + $aliases = $connection->rootQuery('_aliases'); + + foreach ($aliases as $index_name => $index) { + foreach ($index["aliases"] as $alias_name => $alias) { + if ($alias_name == $table) { + $table = $index_name; + break; + } } } } - $return = array( + if (!empty($mapping)) { + $mappings = $mapping[$table]["mappings"]["properties"]; + } + + $result = array( "_id" => array( "field" => "_id", "full_type" => "text", @@ -447,9 +475,12 @@ if (isset($_GET["elastic7"])) { ); foreach ($mappings as $name => $field) { - if (isset($field["index"]) && !$field["index"]) continue; + $has_index = !isset($field["index"]) || $field["index"]; - $return[$name] = array( + // TODO: privileges: where => $has_index + // TODO: privileges: sort => $field["type"] != "text" + + $result[$name] = array( "field" => $name, "full_type" => $field["type"], "type" => $field["type"], @@ -461,14 +492,9 @@ if (isset($_GET["elastic7"])) { "order" => $field["type"] != "text" ?: null ), ); - - if ($field["properties"]) { // only leaf fields can be edited - unset($return[$name]["privileges"]["insert"]); - unset($return[$name]["privileges"]["update"]); - } } - return $return; + return $result; } function foreign_keys($table) { From 898dc9e25ee3f9c31b62cd53850dfaf670fbb3a0 Mon Sep 17 00:00:00 2001 From: Peter Knut Date: Sun, 19 Sep 2021 00:41:09 +0200 Subject: [PATCH 09/10] Move Elastic drivers to plugins, driver for Elastic 7+ is the default --- adminer/elastic.php | 13 ++++ adminer/include/bootstrap.inc.php | 1 - .../drivers/elastic.php | 64 +++++----------- .../drivers/elastic5.php | 75 ++++++------------- 4 files changed, 55 insertions(+), 98 deletions(-) create mode 100644 adminer/elastic.php rename adminer/drivers/elastic7.inc.php => plugins/drivers/elastic.php (90%) rename adminer/drivers/elastic.inc.php => plugins/drivers/elastic5.php (88%) diff --git a/adminer/elastic.php b/adminer/elastic.php new file mode 100644 index 00000000..ccfc5975 --- /dev/null +++ b/adminer/elastic.php @@ -0,0 +1,13 @@ +_conn->rootQuery($query, $data); if ($print) { - echo $adminer->selectQuery("$query: " . json_encode($data), $start, !$search); + echo adminer()->selectQuery("$query: " . json_encode($data), $start, !$search); } if (empty($search)) { return false; @@ -274,11 +272,9 @@ if (isset($_GET["elastic7"])) { } function connect() { - global $adminer; - $connection = new Min_DB; - list($server, $username, $password) = $adminer->credentials(); + list($server, $username, $password) = adminer()->credentials(); if ($password != "" && $connection->connect($server, $username, "")) { return lang('Database does not support password.'); } @@ -295,9 +291,7 @@ if (isset($_GET["elastic7"])) { } function logged_user() { - global $adminer; - - $credentials = $adminer->credentials(); + $credentials = adminer()->credentials(); return $credentials[1]; } @@ -323,9 +317,7 @@ if (isset($_GET["elastic7"])) { } function count_tables($databases) { - global $connection; - - $return = $connection->rootQuery('_aliases'); + $return = connection()->rootQuery('_aliases'); if (empty($return)) { return array( ELASTIC_DB_NAME => 0 @@ -338,9 +330,7 @@ if (isset($_GET["elastic7"])) { } function tables_list() { - global $connection; - - $aliases = $connection->rootQuery('_aliases'); + $aliases = connection()->rootQuery('_aliases'); if (empty($aliases)) { return array(); } @@ -359,10 +349,8 @@ if (isset($_GET["elastic7"])) { } function table_status($name = "", $fast = false) { - global $connection; - - $stats = $connection->rootQuery('_stats'); - $aliases = $connection->rootQuery('_aliases'); + $stats = connection()->rootQuery('_stats'); + $aliases = connection()->rootQuery('_aliases'); if (empty($stats) || empty($aliases)) { return array(); @@ -427,9 +415,7 @@ if (isset($_GET["elastic7"])) { } function error() { - global $connection; - - return h($connection->error); + return h(connection()->error); } function information_schema() { @@ -443,13 +429,11 @@ if (isset($_GET["elastic7"])) { } function fields($table) { - global $connection; - $mappings = array(); - $mapping = $connection->rootQuery("_mapping"); + $mapping = connection()->rootQuery("_mapping"); if (!isset($mapping[$table])) { - $aliases = $connection->rootQuery('_aliases'); + $aliases = connection()->rootQuery('_aliases'); foreach ($aliases as $index_name => $index) { foreach ($index["aliases"] as $alias_name => $alias) { @@ -530,9 +514,7 @@ if (isset($_GET["elastic7"])) { * @return mixed */ function create_database($db) { - global $connection; - - return $connection->rootQuery(urlencode($db), null, 'PUT'); + return connection()->rootQuery(urlencode($db), null, 'PUT'); } /** Remove index @@ -540,9 +522,7 @@ if (isset($_GET["elastic7"])) { * @return mixed */ function drop_databases($databases) { - global $connection; - - return $connection->rootQuery(urlencode(implode(',', $databases)), null, 'DELETE'); + return connection()->rootQuery(urlencode(implode(',', $databases)), null, 'DELETE'); } /** Alter type @@ -550,8 +530,6 @@ if (isset($_GET["elastic7"])) { * @return mixed */ function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) { - global $connection; - $properties = array(); foreach ($fields as $f) { $field_name = trim($f[1][0]); @@ -565,7 +543,7 @@ if (isset($_GET["elastic7"])) { $properties = array('properties' => $properties); } - return $connection->query("_mapping/{$name}", $properties, 'PUT'); + return connection()->query("_mapping/{$name}", $properties, 'PUT'); } /** Drop types @@ -573,20 +551,16 @@ if (isset($_GET["elastic7"])) { * @return bool */ function drop_tables($tables) { - global $connection; - $return = true; foreach ($tables as $table) { //! convert to bulk api - $return = $return && $connection->query(urlencode($table), null, 'DELETE'); + $return = $return && connection()->query(urlencode($table), null, 'DELETE'); } return $return; } function last_id() { - global $connection; - - return $connection->last_id; + return connection()->last_id; } function driver_config() { diff --git a/adminer/drivers/elastic.inc.php b/plugins/drivers/elastic5.php similarity index 88% rename from adminer/drivers/elastic.inc.php rename to plugins/drivers/elastic5.php index e3022715..1fdf79a6 100644 --- a/adminer/drivers/elastic.inc.php +++ b/plugins/drivers/elastic5.php @@ -1,10 +1,10 @@ _conn->query($query, $data); if ($print) { - echo $adminer->selectQuery("$query: " . json_encode($data), $start, !$search); + echo adminer()->selectQuery("$query: " . json_encode($data), $start, !$search); } if (!$search) { return false; @@ -276,11 +274,9 @@ if (isset($_GET["elastic"])) { } function connect() { - global $adminer; - $connection = new Min_DB; - list($server, $username, $password) = $adminer->credentials(); + list($server, $username, $password) = adminer()->credentials(); if ($password != "" && $connection->connect($server, $username, "")) { return lang('Database does not support password.'); } @@ -297,17 +293,13 @@ if (isset($_GET["elastic"])) { } function logged_user() { - global $adminer; - - $credentials = $adminer->credentials(); + $credentials = adminer()->credentials(); return $credentials[1]; } function get_databases() { - global $connection; - - $return = $connection->rootQuery('_aliases'); + $return = connection()->rootQuery('_aliases'); if ($return) { $return = array_keys($return); sort($return, SORT_STRING); @@ -333,11 +325,9 @@ if (isset($_GET["elastic"])) { } function count_tables($databases) { - global $connection; - - $result = $connection->query('_stats'); - $return = array(); + + $result = connection()->query('_stats'); if ($result && $result['indices']) { $indices = $result['indices']; foreach ($indices as $indice => $stats) { @@ -350,24 +340,20 @@ if (isset($_GET["elastic"])) { } function tables_list() { - global $connection; - if (min_version(7)) { return array('_doc' => 'table'); } - $return = $connection->query('_mapping'); + $return = connection()->query('_mapping'); if ($return) { - $return = array_fill_keys(array_keys($return[$connection->_db]["mappings"]), 'table'); + $return = array_fill_keys(array_keys($return[connection()->_db]["mappings"]), 'table'); } return $return; } function table_status($name = "", $fast = false) { - global $connection; - - $search = $connection->query("_search", array( + $search = connection()->query("_search", array( "size" => 0, "aggregations" => array( "count_by_type" => array( @@ -400,9 +386,7 @@ if (isset($_GET["elastic"])) { } function error() { - global $connection; - - return h($connection->error); + return h(connection()->error); } function information_schema() { @@ -418,21 +402,19 @@ if (isset($_GET["elastic"])) { } function fields($table) { - global $connection; - $mappings = array(); if (min_version(7)) { - $result = $connection->query("_mapping"); + $result = connection()->query("_mapping"); if ($result) { - $mappings = $result[$connection->_db]['mappings']['properties']; + $mappings = $result[connection()->_db]['mappings']['properties']; } } else { - $result = $connection->query("$table/_mapping"); + $result = connection()->query("$table/_mapping"); if ($result) { $mappings = $result[$table]['properties']; if (!$mappings) { - $mappings = $result[$connection->_db]['mappings'][$table]['properties']; + $mappings = $result[connection()->_db]['mappings'][$table]['properties']; } } } @@ -504,9 +486,7 @@ if (isset($_GET["elastic"])) { * @return mixed */ function create_database($db) { - global $connection; - - return $connection->rootQuery(urlencode($db), null, 'PUT'); + return connection()->rootQuery(urlencode($db), null, 'PUT'); } /** Remove index @@ -514,9 +494,7 @@ if (isset($_GET["elastic"])) { * @return mixed */ function drop_databases($databases) { - global $connection; - - return $connection->rootQuery(urlencode(implode(',', $databases)), null, 'DELETE'); + return connection()->rootQuery(urlencode(implode(',', $databases)), null, 'DELETE'); } /** Alter type @@ -524,8 +502,6 @@ if (isset($_GET["elastic"])) { * @return mixed */ function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) { - global $connection; - $properties = array(); foreach ($fields as $f) { $field_name = trim($f[1][0]); @@ -538,8 +514,7 @@ if (isset($_GET["elastic"])) { if (!empty($properties)) { $properties = array('properties' => $properties); } - - return $connection->query("_mapping/{$name}", $properties, 'PUT'); + return connection()->query("_mapping/{$name}", $properties, 'PUT'); } /** Drop types @@ -547,20 +522,16 @@ if (isset($_GET["elastic"])) { * @return bool */ function drop_tables($tables) { - global $connection; - $return = true; foreach ($tables as $table) { //! convert to bulk api - $return = $return && $connection->query(urlencode($table), null, 'DELETE'); + $return = $return && connection()->query(urlencode($table), null, 'DELETE'); } return $return; } function last_id() { - global $connection; - - return $connection->last_id; + return connection()->last_id; } function driver_config() { From fc5a46549e35257508bbf215736a8a43bd14c165 Mon Sep 17 00:00:00 2001 From: Peter Knut Date: Sun, 17 Mar 2024 13:11:06 +0100 Subject: [PATCH 10/10] Update changes.txt --- changes.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changes.txt b/changes.txt index 141bfa86..46695fdf 100644 --- a/changes.txt +++ b/changes.txt @@ -3,6 +3,8 @@ Adminer 4.9.0-dev: - Validate connection to server in HTTP based drivers. - Move dependencies from submodules to Composer. - Update hydra and pepa-lintha-dark themes. +- Elasticsearch 5: Make unusable driver usable again, move it to plugins. +- Add new Elasticsearch 7 driver. Adminer 4.8.2 (released 2024-03-16): Support multi-line table comments