]> git.joonet.de Git - adminer.git/commitdiff
ClickHouse support alpha version
authorSartor <sartor@syneforge.com>
Thu, 16 Aug 2018 09:07:09 +0000 (12:07 +0300)
committerJakub Vrana <jakub@vrana.cz>
Tue, 18 Sep 2018 11:09:46 +0000 (13:09 +0200)
adminer/drivers/clickhouse.inc.php [new file with mode: 0644]
adminer/include/bootstrap.inc.php
adminer/include/version.inc.php
changes.txt

diff --git a/adminer/drivers/clickhouse.inc.php b/adminer/drivers/clickhouse.inc.php
new file mode 100644 (file)
index 0000000..d2e50d8
--- /dev/null
@@ -0,0 +1,358 @@
+<?php
+$drivers["clickhouse"] = "ClickHouse (alpha)";
+
+if (isset($_GET["clickhouse"])) {
+       define("DRIVER", "clickhouse");
+
+       class Min_DB {
+               var $extension = "JSON", $server_info, $errno, $_result, $error, $_url;
+               var $_db = 'default';
+
+               function rootQuery($db, $query) {
+                       @ini_set('track_errors', 1); // @ - may be disabled
+                       $file = @file_get_contents("$this->_url/?database=$db", false, stream_context_create(array('http' => array(
+                               'method' => 'POST',
+                               'content' => stripos($query, 'insert') === 0 ? $query : "$query FORMAT JSONCompact",
+                               'header' => 'Content-type: application/x-www-form-urlencoded',
+                               'ignore_errors' => 1, // available since PHP 5.2.10
+                       ))));
+
+                       if (!$file) {
+                               $this->error = $php_errormsg;
+                               return $file;
+                       }
+                       if (!preg_match('~^HTTP/[0-9.]+ 2~i', $http_response_header[0])) {
+                               $this->error = $file;
+                               return false;
+                       }
+                       $return = json_decode($file, true);
+                       if ($return === null) {
+                               $this->errno = json_last_error();
+                               if (function_exists('json_last_error_msg')) {
+                                       $this->error = json_last_error_msg();
+                               } else {
+                                       $constants = get_defined_constants(true);
+                                       foreach ($constants['json'] as $name => $value) {
+                                               if ($value == $this->errno && preg_match('~^JSON_ERROR_~', $name)) {
+                                                       $this->error = $name;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+                       return new Min_Result($return);
+               }
+
+               function query($query) {
+                       return $this->rootQuery($this->_db, $query);
+               }
+
+               function connect($server, $username, $password) {
+                       preg_match('~^(https?://)?(.*)~', $server, $match);
+                       $this->_url = ($match[1] ? $match[1] : "http://") . "$username:$password@$match[2]";
+                       $return = $this->query('SELECT 1');
+                       if ($return) {
+                               //$this->server_info = $return['version']['number'];
+                       }
+                       return (bool) $return;
+               }
+
+               function select_db($database) {
+                       $this->_db = $database;
+                       return true;
+               }
+
+               function quote($string) {
+                       return "'$string'";
+               }
+
+               function multi_query($query) {
+                       return $this->_result = $this->query($query);
+               }
+
+               function store_result() {
+                       return $this->_result;
+               }
+
+               function next_result() {
+                       return false;
+               }
+
+               function result($query, $field = 0) {
+                       $result = $this->query($query);
+                       return $result['data'];
+               }
+       }
+
+       class Min_Result {
+               var $num_rows, $_rows, $columns, $meta, $_offset = 0;
+
+               function __construct($result) {
+                       $this->num_rows = $result['rows'];
+                       $this->_rows = $result['data'];
+                       $this->meta = $result['meta'];
+                       $this->columns = array_column($this->meta, 'name');
+                       reset($this->_rows);
+               }
+
+               function fetch_assoc() {
+                       $row = current($this->_rows);
+                       next($this->_rows);
+                       return $row === false ? false : array_combine($this->columns, $row);
+               }
+
+               function fetch_row() {
+                       $row = current($this->_rows);
+                       next($this->_rows);
+                       return $row;
+               }
+
+               function fetch_field() {
+                       $column = $this->_offset++;
+                       $return = new stdClass;
+                       if ($column < count($this->columns)) {
+                               $return->name = $this->meta[$column]['name'];
+                               $return->orgname = $return->name;
+                               $return->type = $this->meta[$column]['type'];
+                       }
+                       return $return;
+               }
+       }
+
+
+       class Min_Driver extends Min_SQL {
+       }
+
+       function idf_escape($idf) {
+               return "`" . str_replace("`", "``", $idf) . "`";
+       }
+
+       function table($idf) {
+               return idf_escape($idf);
+       }
+
+       function explain($connection, $query) {
+               return '';
+       }
+
+       function found_rows($table_status, $where) {
+               $rows = get_vals("SELECT COUNT(*) FROM " . idf_escape($table_status["Name"]) . ($where ? " WHERE " . implode(" AND ", $where) : ""));
+               return empty($rows) ? false : $rows[0];
+       }
+
+       function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
+               $alter = array();
+               foreach ($fields as $field) {
+                       if ($field[1][2] === " NULL") {
+                               $field[1][1] = " Nullable({$field[1][1]})";
+                       }
+                       unset($field[1][2]);
+                       $alter[] = ($field[1]
+                               ? ($table != "" ? ($field[0] != "" ? "CHANGE " . idf_escape($field[0]) : "ADD") : " ") . " " . implode($field[1])
+                               : "DROP " . idf_escape($field[0])
+                       );
+               }
+               $alter = array_merge($alter, $foreign);
+               $status = ($comment !== null ? " COMMENT=" . q($comment) : "")
+                       . ($engine ? " ENGINE=" . q($engine) : "")
+                       . ($collation ? " COLLATE " . q($collation) : "")
+                       . ($auto_increment != "" ? " AUTO_INCREMENT=$auto_increment" : "")
+               ;
+               if ($table == "") {
+                       return queries("CREATE TABLE " . table($name) . " (\n" . implode(",\n", $alter) . "\n)$status$partitioning");
+               }
+               if ($table != $name) {
+                       $alter[] = "RENAME TO " . table($name);
+               }
+               if ($status) {
+                       $alter[] = ltrim($status);
+               }
+               return ($alter || $partitioning ? queries("ALTER TABLE " . table($table) . "\n" . implode(",\n", $alter) . $partitioning) : true);
+       }
+
+       function truncate_tables($tables) {
+               return apply_queries("TRUNCATE TABLE", $tables);
+       }
+
+       function drop_views($views) {
+               return queries("DROP VIEW " . implode(", ", array_map('table', $views)));
+       }
+
+       function drop_tables($tables) {
+               return queries("DROP TABLE " . implode(", ", array_map('table', $tables)));
+       }
+
+       function connect() {
+               global $adminer;
+               $connection = new Min_DB;
+               $credentials = $adminer->credentials();
+               if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
+                       return $connection;
+               }
+               return $connection->error;
+       }
+
+       function get_databases($flush) {
+               global $connection;
+               $result = get_rows('SHOW DATABASES');
+
+               $return = array();
+               foreach ($result as $row) {
+                       $return[] = $row['name'];
+               }
+               sort($return);
+               return $return;
+       }
+
+       function limit($query, $where, $limit, $offset = 0, $separator = " ") {
+               return " $query$where" . ($limit !== null ? $separator . "LIMIT $limit" . ($offset ? ", $offset" : "") : "");
+       }
+
+       function limit1($table, $query, $where, $separator = "\n") {
+               return limit($query, $where, 1, 0, $separator);
+       }
+
+       function db_collation($db, $collations) {
+       }
+
+       function engines() {
+               return array('MergeTree');
+       }
+
+       function logged_user() {
+               global $adminer;
+               $credentials = $adminer->credentials();
+               return $credentials[1];
+       }
+
+       function tables_list() {
+               $result = get_rows('SHOW TABLES');
+               $return = array();
+               foreach ($result as $row) {
+                       $return[$row['name']] = 'table';
+               }
+               ksort($return);
+               return $return;
+       }
+
+       function count_tables($databases) {
+               return array();
+       }
+
+       function table_status($name = "", $fast = false) {
+               global $connection;
+               $return = array();
+               $tables = get_rows("SELECT name, engine FROM system.tables WHERE database = '{$connection->_db}'");
+               foreach ($tables as $table) {
+                       $return[$table['name']] = array(
+                               'Name' => $table['name'],
+                               'Engine' => $table['engine'],
+                       );
+                       if ($name === $table['name']) {
+                               return $return[$table['name']];
+                       }
+               }
+               return $return;
+       }
+
+       function is_view($table_status) {
+               return false;
+       }
+
+       function fk_support($table_status) {
+               return false;
+       }
+
+       function convert_field($field) {
+       }
+
+       function unconvert_field($field, $return) {
+               if (in_array($field['type'], ["Int8", "Int16", "Int32", "Int64", "UInt8", "UInt16", "UInt32", "UInt64", "Float32", "Float64"])) {
+                       return "to$field[type]($return)";
+               }
+               return $return;
+       }
+
+       function fields($table) {
+               $return = array();
+               $result = get_rows("SELECT name, type, default_expression FROM system.columns WHERE " . idf_escape('table') . " = " . q($table));
+               foreach($result as $row) {
+                       $type = trim($row['type']);
+                       $nullable = strpos($type, 'Nullable(') === 0;
+                       $return[trim($row['name'])] = array(
+                               "field" => trim($row['name']),
+                               "full_type" => $type,
+                               "type" => $type,
+                               "default" => trim($row['default_expression']),
+                               "null" => $nullable,
+                               "auto_increment" => '0',
+                               "privileges" => array("insert" => 1, "select" => 1, "update" => 0),
+                       );
+               }
+
+               return $return;
+       }
+
+       function indexes($table, $connection2 = null) {
+               return array();
+       }
+
+       function foreign_keys($table) {
+               return array();
+       }
+
+       function collations() {
+               return array();
+       }
+
+       function information_schema($db) {
+               return false;
+       }
+
+       function error() {
+               global $connection;
+               return h($connection->error);
+       }
+
+       function types() {
+               return array();
+       }
+
+       function schemas() {
+               return array();
+       }
+
+       function get_schema() {
+               return "";
+       }
+
+       function set_schema($schema) {
+               return true;
+       }
+
+       function auto_increment() {
+               return '';
+       }
+
+       function support($feature) {
+               return preg_match("~^(columns|sql|status|table)$~", $feature);
+       }
+
+       $jush = "clickhouse";
+       $types = array();
+       $structured_types = array();
+       foreach (array( //! arrays
+               lang('Numbers') => array("Int8" => 3, "Int16" => 5, "Int32" => 10, "Int64" => 19, "UInt8" => 3, "UInt16" => 5, "UInt32" => 10, "UInt64" => 20, "Float32" => 7, "Float64" => 16),
+               lang('Date and time') => array("Date" => 13, "DateTime" => 20),
+               lang('Strings') => array("String" => 0),
+               lang('Binary') => array("FixedString" => 0),
+       ) as $key => $val) {
+               $types += $val;
+               $structured_types[$key] = array_keys($val);
+       }
+       $unsigned = array();
+       $operators = array("=", "<", ">", "<=", ">=", "!=", "~", "!~", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL");
+       $functions = array();
+       $grouping = array("avg", "count", "count distinct", "max", "min", "sum");
+       $edit_functions = array();
+}
index 1db4e2edd08213e5e314bc0063413900c11567ff..9f09b3269875691947177b33d513e281852eb7a2 100644 (file)
@@ -79,6 +79,7 @@ include "../adminer/drivers/firebird.inc.php";
 include "../adminer/drivers/simpledb.inc.php";
 include "../adminer/drivers/mongo.inc.php";
 include "../adminer/drivers/elastic.inc.php";
+include "../adminer/drivers/clickhouse.inc.php";
 include "../adminer/drivers/mysql.inc.php"; // must be included as last driver
 
 define("SERVER", $_GET[DRIVER]); // read from pgsql=localhost
index 19a598c72b832a0a0f350794c039bb52f1ff8562..22e2182731326a1dd2b14a8a5542a235213b2ddc 100644 (file)
@@ -1,2 +1,2 @@
 <?php
-$VERSION = "4.6.4-dev";
+$VERSION = "4.7.0-dev";
index 08614c399786011651dd420fc58eb632f3676e6a..e02c9be0de078aa423e35d03879424dc12388533 100644 (file)
@@ -1,4 +1,4 @@
-Adminer 4.6.4-dev:
+Adminer 4.7.0-dev:
 Warn when using password with leading or trailing spaces
 Fix inline editing of empty cells (regression from 4.6.3)
 Allow adding more than two indexes and forign key columns at a time (regression from 4.4.0)
@@ -7,6 +7,7 @@ Increase username maxlength to 80 (bug #623)
 Make maxlength in all fields a soft limit
 MySQL: Support foreign keys created with ANSI quotes (bug #620)
 MSSQL: Pass database when connecting
+ClickHouse: Connect, databases list, tables list, select, SQL command
 
 Adminer 4.6.3 (released 2018-06-28):
 Disallow using password-less databases