From: Jakub Vrana Date: Mon, 8 Feb 2021 18:56:15 +0000 (+0100) Subject: SimpleDB, Firebird, ClickHouse: Move to plugin X-Git-Tag: v4.8.0~38 X-Git-Url: https://git.joonet.de/?a=commitdiff_plain;h=51abdcdab9b72231b20341adec54b4ee1d044635;p=adminer.git SimpleDB, Firebird, ClickHouse: Move to plugin --- diff --git a/adminer/drivers/clickhouse.inc.php b/adminer/drivers/clickhouse.inc.php deleted file mode 100644 index ec5db517..00000000 --- a/adminer/drivers/clickhouse.inc.php +++ /dev/null @@ -1,398 +0,0 @@ -_url/?database=$db", false, stream_context_create(array('http' => array( - 'method' => 'POST', - 'content' => $this->isQuerySelectLike($query) ? "$query FORMAT JSONCompact" : $query, - 'header' => 'Content-type: application/x-www-form-urlencoded', - 'ignore_errors' => 1, // available since PHP 5.2.10 - )))); - - if ($file === false) { - $this->error = $php_errormsg; - return $file; - } - if (!preg_match('~^HTTP/[0-9.]+ 2~i', $http_response_header[0])) { - $this->error = lang('Invalid credentials.') . " $http_response_header[0]"; - return false; - } - $return = json_decode($file, true); - if ($return === null) { - if (!$this->isQuerySelectLike($query) && $file === '') { - return true; - } - - $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 isQuerySelectLike($query) { - return (bool) preg_match('~^(select|show)~i', $query); - } - - 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'); - return (bool) $return; - } - - function select_db($database) { - $this->_db = $database; - return true; - } - - function quote($string) { - return "'" . addcslashes($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 delete($table, $queryWhere, $limit = 0) { - if ($queryWhere === '') { - $queryWhere = 'WHERE 1=1'; - } - return queries("ALTER TABLE " . table($table) . " DELETE $queryWhere"); - } - - function update($table, $set, $queryWhere, $limit = 0, $separator = "\n") { - $values = array(); - foreach ($set as $key => $val) { - $values[] = "$key = $val"; - } - $query = $separator . implode(",$separator", $values); - return queries("ALTER TABLE " . table($table) . " UPDATE $query$queryWhere"); - } - } - - 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 = $order = array(); - foreach ($fields as $field) { - if ($field[1][2] === " NULL") { - $field[1][1] = " Nullable({$field[1][1]})"; - } elseif ($field[1][2] === ' NOT NULL') { - $field[1][2] = ''; - } - - if ($field[1][3]) { - $field[1][3] = ''; - } - - $alter[] = ($field[1] - ? ($table != "" ? ($field[0] != "" ? "MODIFY COLUMN " : "ADD COLUMN ") : " ") . implode($field[1]) - : "DROP COLUMN " . idf_escape($field[0]) - ); - - $order[] = $field[1][0]; - } - - $alter = array_merge($alter, $foreign); - $status = ($engine ? " ENGINE " . $engine : ""); - if ($table == "") { - return queries("CREATE TABLE " . table($name) . " (\n" . implode(",\n", $alter) . "\n)$status$partitioning" . ' ORDER BY (' . implode(',', $order) . ')'); - } - if ($table != $name) { - $result = queries("RENAME TABLE " . table($table) . " TO " . table($name)); - if ($alter) { - $table = $name; - } else { - return $result; - } - } - 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 drop_tables($views); - } - - function drop_tables($tables) { - return apply_queries("DROP 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 = " . q($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'], array("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 last_id() { - return 0; // ClickHouse doesn't have it - } - - function support($feature) { - return preg_match("~^(columns|sql|status|table|drop_col)$~", $feature); - } - - function driver_config() { - $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, 'Decimal' => 38, 'Decimal32' => 9, 'Decimal64' => 18, 'Decimal128' => 38), - 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); - } - return array( - 'jush' => "clickhouse", - 'types' => $types, - 'structured_types' => $structured_types, - 'unsigned' => array(), - 'operators' => array("=", "<", ">", "<=", ">=", "!=", "~", "!~", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL", "SQL"), - 'functions' => array(), - 'grouping' => array("avg", "count", "count distinct", "max", "min", "sum"), - 'edit_functions' => array(), - ); - } -} diff --git a/adminer/drivers/firebird.inc.php b/adminer/drivers/firebird.inc.php deleted file mode 100644 index 7e62930c..00000000 --- a/adminer/drivers/firebird.inc.php +++ /dev/null @@ -1,324 +0,0 @@ -_link = ibase_connect($server, $username, $password); - if ($this->_link) { - $url_parts = explode(':', $server); - $this->service_link = ibase_service_attach($url_parts[0], $username, $password); - $this->server_info = ibase_server_info($this->service_link, IBASE_SVC_SERVER_VERSION); - } else { - $this->errno = ibase_errcode(); - $this->error = ibase_errmsg(); - } - return (bool) $this->_link; - } - - function quote($string) { - return "'" . str_replace("'", "''", $string) . "'"; - } - - function select_db($database) { - return ($database == "domain"); - } - - function query($query, $unbuffered = false) { - $result = ibase_query($query, $this->_link); - if (!$result) { - $this->errno = ibase_errcode(); - $this->error = ibase_errmsg(); - return false; - } - $this->error = ""; - if ($result === true) { - $this->affected_rows = ibase_affected_rows($this->_link); - return true; - } - return new Min_Result($result); - } - - 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); - if (!$result || !$result->num_rows) { - return false; - } - $row = $result->fetch_row(); - return $row[$field]; - } - } - - class Min_Result { - var $num_rows, $_result, $_offset = 0; - - function __construct($result) { - $this->_result = $result; - // $this->num_rows = ibase_num_rows($result); - } - - function fetch_assoc() { - return ibase_fetch_assoc($this->_result); - } - - function fetch_row() { - return ibase_fetch_row($this->_result); - } - - function fetch_field() { - $field = ibase_field_info($this->_result, $this->_offset++); - return (object) array( - 'name' => $field['name'], - 'orgname' => $field['name'], - 'type' => $field['type'], - 'charsetnr' => $field['length'], - ); - } - - function __destruct() { - ibase_free_result($this->_result); - } - } - - } - - - - class Min_Driver extends Min_SQL { - } - - - - function idf_escape($idf) { - return '"' . str_replace('"', '""', $idf) . '"'; - } - - function table($idf) { - return idf_escape($idf); - } - - 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) { - return array("domain"); - } - - function limit($query, $where, $limit, $offset = 0, $separator = " ") { - $return = ''; - $return .= ($limit !== null ? $separator . "FIRST $limit" . ($offset ? " SKIP $offset" : "") : ""); - $return .= " $query$where"; - return $return; - } - - function limit1($table, $query, $where, $separator = "\n") { - return limit($query, $where, 1, 0, $separator); - } - - function db_collation($db, $collations) { - } - - function engines() { - return array(); - } - - function logged_user() { - global $adminer; - $credentials = $adminer->credentials(); - return $credentials[1]; - } - - function tables_list() { - global $connection; - $query = 'SELECT RDB$RELATION_NAME FROM rdb$relations WHERE rdb$system_flag = 0'; - $result = ibase_query($connection->_link, $query); - $return = array(); - while ($row = ibase_fetch_assoc($result)) { - $return[$row['RDB$RELATION_NAME']] = 'table'; - } - ksort($return); - return $return; - } - - function count_tables($databases) { - return array(); - } - - function table_status($name = "", $fast = false) { - global $connection; - $return = array(); - $data = tables_list(); - foreach ($data as $index => $val) { - $index = trim($index); - $return[$index] = array( - 'Name' => $index, - 'Engine' => 'standard', - ); - if ($name == $index) { - return $return[$index]; - } - } - return $return; - } - - function is_view($table_status) { - return false; - } - - function fk_support($table_status) { - return preg_match('~InnoDB|IBMDB2I~i', $table_status["Engine"]); - } - - function fields($table) { - global $connection; - $return = array(); - $query = 'SELECT r.RDB$FIELD_NAME AS field_name, -r.RDB$DESCRIPTION AS field_description, -r.RDB$DEFAULT_VALUE AS field_default_value, -r.RDB$NULL_FLAG AS field_not_null_constraint, -f.RDB$FIELD_LENGTH AS field_length, -f.RDB$FIELD_PRECISION AS field_precision, -f.RDB$FIELD_SCALE AS field_scale, -CASE f.RDB$FIELD_TYPE -WHEN 261 THEN \'BLOB\' -WHEN 14 THEN \'CHAR\' -WHEN 40 THEN \'CSTRING\' -WHEN 11 THEN \'D_FLOAT\' -WHEN 27 THEN \'DOUBLE\' -WHEN 10 THEN \'FLOAT\' -WHEN 16 THEN \'INT64\' -WHEN 8 THEN \'INTEGER\' -WHEN 9 THEN \'QUAD\' -WHEN 7 THEN \'SMALLINT\' -WHEN 12 THEN \'DATE\' -WHEN 13 THEN \'TIME\' -WHEN 35 THEN \'TIMESTAMP\' -WHEN 37 THEN \'VARCHAR\' -ELSE \'UNKNOWN\' -END AS field_type, -f.RDB$FIELD_SUB_TYPE AS field_subtype, -coll.RDB$COLLATION_NAME AS field_collation, -cset.RDB$CHARACTER_SET_NAME AS field_charset -FROM RDB$RELATION_FIELDS r -LEFT JOIN RDB$FIELDS f ON r.RDB$FIELD_SOURCE = f.RDB$FIELD_NAME -LEFT JOIN RDB$COLLATIONS coll ON f.RDB$COLLATION_ID = coll.RDB$COLLATION_ID -LEFT JOIN RDB$CHARACTER_SETS cset ON f.RDB$CHARACTER_SET_ID = cset.RDB$CHARACTER_SET_ID -WHERE r.RDB$RELATION_NAME = ' . q($table) . ' -ORDER BY r.RDB$FIELD_POSITION'; - $result = ibase_query($connection->_link, $query); - while ($row = ibase_fetch_assoc($result)) { - $return[trim($row['FIELD_NAME'])] = array( - "field" => trim($row["FIELD_NAME"]), - "full_type" => trim($row["FIELD_TYPE"]), - "type" => trim($row["FIELD_SUB_TYPE"]), - "default" => trim($row['FIELD_DEFAULT_VALUE']), - "null" => (trim($row["FIELD_NOT_NULL_CONSTRAINT"]) == "YES"), - "auto_increment" => '0', - "collation" => trim($row["FIELD_COLLATION"]), - "privileges" => array("insert" => 1, "select" => 1, "update" => 1), - "comment" => trim($row["FIELD_DESCRIPTION"]), - ); - } - return $return; - } - - function indexes($table, $connection2 = null) { - $return = array(); - /* - $query = 'SELECT RDB$INDEX_SEGMENTS.RDB$FIELD_NAME AS field_name, -RDB$INDICES.RDB$DESCRIPTION AS description, -(RDB$INDEX_SEGMENTS.RDB$FIELD_POSITION + 1) AS field_position -FROM RDB$INDEX_SEGMENTS -LEFT JOIN RDB$INDICES ON RDB$INDICES.RDB$INDEX_NAME = RDB$INDEX_SEGMENTS.RDB$INDEX_NAME -LEFT JOIN RDB$RELATION_CONSTRAINTS ON RDB$RELATION_CONSTRAINTS.RDB$INDEX_NAME = RDB$INDEX_SEGMENTS.RDB$INDEX_NAME -WHERE UPPER(RDB$INDICES.RDB$RELATION_NAME) = ' . q($table) . ' -// AND UPPER(RDB$INDICES.RDB$INDEX_NAME) = \'TEST2_FIELD5_IDX\' -AND RDB$RELATION_CONSTRAINTS.RDB$CONSTRAINT_TYPE IS NULL -ORDER BY RDB$INDEX_SEGMENTS.RDB$FIELD_POSITION'; - */ - return $return; - } - - 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 support($feature) { - return preg_match("~^(columns|sql|status|table)$~", $feature); - } - - function driver_config() { - return array( - 'possible_drivers' => array("interbase"), - 'jush' => "firebird", - 'operators' => array("="), - 'functions' => array(), - 'grouping' => array(), - 'edit_functions' => array(), - ); - } -} diff --git a/adminer/drivers/simpledb.inc.php b/adminer/drivers/simpledb.inc.php deleted file mode 100644 index 4dce229d..00000000 --- a/adminer/drivers/simpledb.inc.php +++ /dev/null @@ -1,488 +0,0 @@ - $query, 'ConsistentRead' => 'true'); - if ($this->next) { - $params['NextToken'] = $this->next; - } - $result = sdb_request_all('Select', 'Item', $params, $this->timeout); //! respect $unbuffered - $this->timeout = 0; - if ($result === false) { - return $result; - } - if (preg_match('~^\s*SELECT\s+COUNT\(~i', $query)) { - $sum = 0; - foreach ($result as $item) { - $sum += $item->Attribute->Value; - } - $result = array((object) array('Attribute' => array((object) array( - 'Name' => 'Count', - 'Value' => $sum, - )))); - } - return new Min_Result($result); - } - - function multi_query($query) { - return $this->_result = $this->query($query); - } - - function store_result() { - return $this->_result; - } - - function next_result() { - return false; - } - - function quote($string) { - return "'" . str_replace("'", "''", $string) . "'"; - } - - } - - class Min_Result { - var $num_rows, $_rows = array(), $_offset = 0; - - function __construct($result) { - foreach ($result as $item) { - $row = array(); - if ($item->Name != '') { // SELECT COUNT(*) - $row['itemName()'] = (string) $item->Name; - } - foreach ($item->Attribute as $attribute) { - $name = $this->_processValue($attribute->Name); - $value = $this->_processValue($attribute->Value); - if (isset($row[$name])) { - $row[$name] = (array) $row[$name]; - $row[$name][] = $value; - } else { - $row[$name] = $value; - } - } - $this->_rows[] = $row; - foreach ($row as $key => $val) { - if (!isset($this->_rows[0][$key])) { - $this->_rows[0][$key] = null; - } - } - } - $this->num_rows = count($this->_rows); - } - - function _processValue($element) { - return (is_object($element) && $element['encoding'] == 'base64' ? base64_decode($element) : (string) $element); - } - - function fetch_assoc() { - $row = current($this->_rows); - if (!$row) { - return $row; - } - $return = array(); - foreach ($this->_rows[0] as $key => $val) { - $return[$key] = $row[$key]; - } - next($this->_rows); - return $return; - } - - function fetch_row() { - $return = $this->fetch_assoc(); - if (!$return) { - return $return; - } - return array_values($return); - } - - function fetch_field() { - $keys = array_keys($this->_rows[0]); - return (object) array('name' => $keys[$this->_offset++]); - } - - } - } - - - - class Min_Driver extends Min_SQL { - public $primary = "itemName()"; - - function _chunkRequest($ids, $action, $params, $expand = array()) { - global $connection; - foreach (array_chunk($ids, 25) as $chunk) { - $params2 = $params; - foreach ($chunk as $i => $id) { - $params2["Item.$i.ItemName"] = $id; - foreach ($expand as $key => $val) { - $params2["Item.$i.$key"] = $val; - } - } - if (!sdb_request($action, $params2)) { - return false; - } - } - $connection->affected_rows = count($ids); - return true; - } - - function _extractIds($table, $queryWhere, $limit) { - $return = array(); - if (preg_match_all("~itemName\(\) = (('[^']*+')+)~", $queryWhere, $matches)) { - $return = array_map('idf_unescape', $matches[1]); - } else { - foreach (sdb_request_all('Select', 'Item', array('SelectExpression' => 'SELECT itemName() FROM ' . table($table) . $queryWhere . ($limit ? " LIMIT 1" : ""))) as $item) { - $return[] = $item->Name; - } - } - return $return; - } - - function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) { - global $connection; - $connection->next = $_GET["next"]; - $return = parent::select($table, $select, $where, $group, $order, $limit, $page, $print); - $connection->next = 0; - return $return; - } - - function delete($table, $queryWhere, $limit = 0) { - return $this->_chunkRequest( - $this->_extractIds($table, $queryWhere, $limit), - 'BatchDeleteAttributes', - array('DomainName' => $table) - ); - } - - function update($table, $set, $queryWhere, $limit = 0, $separator = "\n") { - $delete = array(); - $insert = array(); - $i = 0; - $ids = $this->_extractIds($table, $queryWhere, $limit); - $id = idf_unescape($set["`itemName()`"]); - unset($set["`itemName()`"]); - foreach ($set as $key => $val) { - $key = idf_unescape($key); - if ($val == "NULL" || ($id != "" && array($id) != $ids)) { - $delete["Attribute." . count($delete) . ".Name"] = $key; - } - if ($val != "NULL") { - foreach ((array) $val as $k => $v) { - $insert["Attribute.$i.Name"] = $key; - $insert["Attribute.$i.Value"] = (is_array($val) ? $v : idf_unescape($v)); - if (!$k) { - $insert["Attribute.$i.Replace"] = "true"; - } - $i++; - } - } - } - $params = array('DomainName' => $table); - return (!$insert || $this->_chunkRequest(($id != "" ? array($id) : $ids), 'BatchPutAttributes', $params, $insert)) - && (!$delete || $this->_chunkRequest($ids, 'BatchDeleteAttributes', $params, $delete)) - ; - } - - function insert($table, $set) { - $params = array("DomainName" => $table); - $i = 0; - foreach ($set as $name => $value) { - if ($value != "NULL") { - $name = idf_unescape($name); - if ($name == "itemName()") { - $params["ItemName"] = idf_unescape($value); - } else { - foreach ((array) $value as $val) { - $params["Attribute.$i.Name"] = $name; - $params["Attribute.$i.Value"] = (is_array($value) ? $val : idf_unescape($value)); - $i++; - } - } - } - } - return sdb_request('PutAttributes', $params); - } - - function insertUpdate($table, $rows, $primary) { - //! use one batch request - foreach ($rows as $set) { - if (!$this->update($table, $set, "WHERE `itemName()` = " . q($set["`itemName()`"]))) { - return false; - } - } - return true; - } - - function begin() { - return false; - } - - function commit() { - return false; - } - - function rollback() { - return false; - } - - function slowQuery($query, $timeout) { - $this->_conn->timeout = $timeout; - return $query; - } - - } - - - - function connect() { - global $adminer; - list(, , $password) = $adminer->credentials(); - if ($password != "") { - return lang('Database does not support password.'); - } - return new Min_DB; - } - - function support($feature) { - return preg_match('~sql~', $feature); - } - - function logged_user() { - global $adminer; - $credentials = $adminer->credentials(); - return $credentials[1]; - } - - function get_databases() { - return array("domain"); - } - - function collations() { - return array(); - } - - function db_collation($db, $collations) { - } - - function tables_list() { - global $connection; - $return = array(); - foreach (sdb_request_all('ListDomains', 'DomainName') as $table) { - $return[(string) $table] = 'table'; - } - if ($connection->error && defined("PAGE_HEADER")) { - echo "

" . error() . "\n"; - } - return $return; - } - - function table_status($name = "", $fast = false) { - $return = array(); - foreach (($name != "" ? array($name => true) : tables_list()) as $table => $type) { - $row = array("Name" => $table, "Auto_increment" => ""); - if (!$fast) { - $meta = sdb_request('DomainMetadata', array('DomainName' => $table)); - if ($meta) { - foreach (array( - "Rows" => "ItemCount", - "Data_length" => "ItemNamesSizeBytes", - "Index_length" => "AttributeValuesSizeBytes", - "Data_free" => "AttributeNamesSizeBytes", - ) as $key => $val) { - $row[$key] = (string) $meta->$val; - } - } - } - if ($name != "") { - return $row; - } - $return[$table] = $row; - } - return $return; - } - - function explain($connection, $query) { - } - - 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("itemName()")), - ); - } - - function fields($table) { - return fields_from_edit(); - } - - function foreign_keys($table) { - return array(); - } - - function table($idf) { - return idf_escape($idf); - } - - function idf_escape($idf) { - return "`" . str_replace("`", "``", $idf) . "`"; - } - - function limit($query, $where, $limit, $offset = 0, $separator = " ") { - return " $query$where" . ($limit !== null ? $separator . "LIMIT $limit" : ""); - } - - function unconvert_field($field, $return) { - return $return; - } - - function fk_support($table_status) { - } - - function engines() { - return array(); - } - - function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) { - return ($table == "" && sdb_request('CreateDomain', array('DomainName' => $name))); - } - - function drop_tables($tables) { - foreach ($tables as $table) { - if (!sdb_request('DeleteDomain', array('DomainName' => $table))) { - return false; - } - } - return true; - } - - function count_tables($databases) { - foreach ($databases as $db) { - return array($db => count(tables_list())); - } - } - - function found_rows($table_status, $where) { - return ($where ? null : $table_status["Rows"]); - } - - function last_id() { - } - - function hmac($algo, $data, $key, $raw_output = false) { - // can use hash_hmac() since PHP 5.1.2 - $blocksize = 64; - if (strlen($key) > $blocksize) { - $key = pack("H*", $algo($key)); - } - $key = str_pad($key, $blocksize, "\0"); - $k_ipad = $key ^ str_repeat("\x36", $blocksize); - $k_opad = $key ^ str_repeat("\x5C", $blocksize); - $return = $algo($k_opad . pack("H*", $algo($k_ipad . $data))); - if ($raw_output) { - $return = pack("H*", $return); - } - return $return; - } - - function sdb_request($action, $params = array()) { - global $adminer, $connection; - list($host, $params['AWSAccessKeyId'], $secret) = $adminer->credentials(); - $params['Action'] = $action; - $params['Timestamp'] = gmdate('Y-m-d\TH:i:s+00:00'); - $params['Version'] = '2009-04-15'; - $params['SignatureVersion'] = 2; - $params['SignatureMethod'] = 'HmacSHA1'; - ksort($params); - $query = ''; - foreach ($params as $key => $val) { - $query .= '&' . rawurlencode($key) . '=' . rawurlencode($val); - } - $query = str_replace('%7E', '~', substr($query, 1)); - $query .= "&Signature=" . urlencode(base64_encode(hmac('sha1', "POST\n" . preg_replace('~^https?://~', '', $host) . "\n/\n$query", $secret, true))); - @ini_set('track_errors', 1); // @ - may be disabled - $file = @file_get_contents((preg_match('~^https?://~', $host) ? $host : "http://$host"), false, stream_context_create(array('http' => array( - 'method' => 'POST', // may not fit in URL with GET - 'content' => $query, - 'ignore_errors' => 1, // available since PHP 5.2.10 - )))); - if (!$file) { - $connection->error = $php_errormsg; - return false; - } - libxml_use_internal_errors(true); - $xml = simplexml_load_string($file); - if (!$xml) { - $error = libxml_get_last_error(); - $connection->error = $error->message; - return false; - } - if ($xml->Errors) { - $error = $xml->Errors->Error; - $connection->error = "$error->Message ($error->Code)"; - return false; - } - $connection->error = ''; - $tag = $action . "Result"; - return ($xml->$tag ? $xml->$tag : true); - } - - function sdb_request_all($action, $tag, $params = array(), $timeout = 0) { - $return = array(); - $start = ($timeout ? microtime(true) : 0); - $limit = (preg_match('~LIMIT\s+(\d+)\s*$~i', $params['SelectExpression'], $match) ? $match[1] : 0); - do { - $xml = sdb_request($action, $params); - if (!$xml) { - break; - } - foreach ($xml->$tag as $element) { - $return[] = $element; - } - if ($limit && count($return) >= $limit) { - $_GET["next"] = $xml->NextToken; - break; - } - if ($timeout && microtime(true) - $start > $timeout) { - return false; - } - $params['NextToken'] = $xml->NextToken; - if ($limit) { - $params['SelectExpression'] = preg_replace('~\d+\s*$~', $limit - count($return), $params['SelectExpression']); - } - } while ($xml->NextToken); - return $return; - } - - function driver_config() { - return array( - 'possible_drivers' => array("SimpleXML + allow_url_fopen"), - 'jush' => "simpledb", - 'operators' => array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "IS NOT NULL"), - 'functions' => array(), - 'grouping' => array("count"), - 'edit_functions' => array(array("json")), - ); - } -} diff --git a/adminer/include/bootstrap.inc.php b/adminer/include/bootstrap.inc.php index 114b4ca4..9349d42c 100644 --- a/adminer/include/bootstrap.inc.php +++ b/adminer/include/bootstrap.inc.php @@ -80,11 +80,9 @@ include "../adminer/drivers/sqlite.inc.php"; include "../adminer/drivers/pgsql.inc.php"; include "../adminer/drivers/oracle.inc.php"; include "../adminer/drivers/mssql.inc.php"; -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 "./include/adminer.inc.php"; include "../adminer/drivers/mysql.inc.php"; // must be included as last driver $config = driver_config(); @@ -108,7 +106,6 @@ define("ME", preg_replace('~\?.*~', '', relative_uri()) . '?' ); include "../adminer/include/version.inc.php"; -include "./include/adminer.inc.php"; include "../adminer/include/design.inc.php"; include "../adminer/include/xxtea.inc.php"; include "../adminer/include/auth.inc.php"; diff --git a/adminer/include/driver.inc.php b/adminer/include/driver.inc.php index 893d1667..99582bd4 100644 --- a/adminer/include/driver.inc.php +++ b/adminer/include/driver.inc.php @@ -1,4 +1,15 @@ diff --git a/plugins/drivers/clickhouse.inc.php b/plugins/drivers/clickhouse.inc.php new file mode 100644 index 00000000..60bb0b45 --- /dev/null +++ b/plugins/drivers/clickhouse.inc.php @@ -0,0 +1,398 @@ +_url/?database=$db", false, stream_context_create(array('http' => array( + 'method' => 'POST', + 'content' => $this->isQuerySelectLike($query) ? "$query FORMAT JSONCompact" : $query, + 'header' => 'Content-type: application/x-www-form-urlencoded', + 'ignore_errors' => 1, // available since PHP 5.2.10 + )))); + + if ($file === false) { + $this->error = $php_errormsg; + return $file; + } + if (!preg_match('~^HTTP/[0-9.]+ 2~i', $http_response_header[0])) { + $this->error = lang('Invalid credentials.') . " $http_response_header[0]"; + return false; + } + $return = json_decode($file, true); + if ($return === null) { + if (!$this->isQuerySelectLike($query) && $file === '') { + return true; + } + + $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 isQuerySelectLike($query) { + return (bool) preg_match('~^(select|show)~i', $query); + } + + 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'); + return (bool) $return; + } + + function select_db($database) { + $this->_db = $database; + return true; + } + + function quote($string) { + return "'" . addcslashes($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 delete($table, $queryWhere, $limit = 0) { + if ($queryWhere === '') { + $queryWhere = 'WHERE 1=1'; + } + return queries("ALTER TABLE " . table($table) . " DELETE $queryWhere"); + } + + function update($table, $set, $queryWhere, $limit = 0, $separator = "\n") { + $values = array(); + foreach ($set as $key => $val) { + $values[] = "$key = $val"; + } + $query = $separator . implode(",$separator", $values); + return queries("ALTER TABLE " . table($table) . " UPDATE $query$queryWhere"); + } + } + + 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 = $order = array(); + foreach ($fields as $field) { + if ($field[1][2] === " NULL") { + $field[1][1] = " Nullable({$field[1][1]})"; + } elseif ($field[1][2] === ' NOT NULL') { + $field[1][2] = ''; + } + + if ($field[1][3]) { + $field[1][3] = ''; + } + + $alter[] = ($field[1] + ? ($table != "" ? ($field[0] != "" ? "MODIFY COLUMN " : "ADD COLUMN ") : " ") . implode($field[1]) + : "DROP COLUMN " . idf_escape($field[0]) + ); + + $order[] = $field[1][0]; + } + + $alter = array_merge($alter, $foreign); + $status = ($engine ? " ENGINE " . $engine : ""); + if ($table == "") { + return queries("CREATE TABLE " . table($name) . " (\n" . implode(",\n", $alter) . "\n)$status$partitioning" . ' ORDER BY (' . implode(',', $order) . ')'); + } + if ($table != $name) { + $result = queries("RENAME TABLE " . table($table) . " TO " . table($name)); + if ($alter) { + $table = $name; + } else { + return $result; + } + } + 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 drop_tables($views); + } + + function drop_tables($tables) { + return apply_queries("DROP 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 = " . q($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'], array("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 last_id() { + return 0; // ClickHouse doesn't have it + } + + function support($feature) { + return preg_match("~^(columns|sql|status|table|drop_col)$~", $feature); + } + + function driver_config() { + $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, 'Decimal' => 38, 'Decimal32' => 9, 'Decimal64' => 18, 'Decimal128' => 38), + 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); + } + return array( + 'jush' => "clickhouse", + 'types' => $types, + 'structured_types' => $structured_types, + 'unsigned' => array(), + 'operators' => array("=", "<", ">", "<=", ">=", "!=", "~", "!~", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL", "SQL"), + 'functions' => array(), + 'grouping' => array("avg", "count", "count distinct", "max", "min", "sum"), + 'edit_functions' => array(), + ); + } +} diff --git a/plugins/drivers/firebird.inc.php b/plugins/drivers/firebird.inc.php new file mode 100644 index 00000000..fc46f3a7 --- /dev/null +++ b/plugins/drivers/firebird.inc.php @@ -0,0 +1,324 @@ +_link = ibase_connect($server, $username, $password); + if ($this->_link) { + $url_parts = explode(':', $server); + $this->service_link = ibase_service_attach($url_parts[0], $username, $password); + $this->server_info = ibase_server_info($this->service_link, IBASE_SVC_SERVER_VERSION); + } else { + $this->errno = ibase_errcode(); + $this->error = ibase_errmsg(); + } + return (bool) $this->_link; + } + + function quote($string) { + return "'" . str_replace("'", "''", $string) . "'"; + } + + function select_db($database) { + return ($database == "domain"); + } + + function query($query, $unbuffered = false) { + $result = ibase_query($query, $this->_link); + if (!$result) { + $this->errno = ibase_errcode(); + $this->error = ibase_errmsg(); + return false; + } + $this->error = ""; + if ($result === true) { + $this->affected_rows = ibase_affected_rows($this->_link); + return true; + } + return new Min_Result($result); + } + + 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); + if (!$result || !$result->num_rows) { + return false; + } + $row = $result->fetch_row(); + return $row[$field]; + } + } + + class Min_Result { + var $num_rows, $_result, $_offset = 0; + + function __construct($result) { + $this->_result = $result; + // $this->num_rows = ibase_num_rows($result); + } + + function fetch_assoc() { + return ibase_fetch_assoc($this->_result); + } + + function fetch_row() { + return ibase_fetch_row($this->_result); + } + + function fetch_field() { + $field = ibase_field_info($this->_result, $this->_offset++); + return (object) array( + 'name' => $field['name'], + 'orgname' => $field['name'], + 'type' => $field['type'], + 'charsetnr' => $field['length'], + ); + } + + function __destruct() { + ibase_free_result($this->_result); + } + } + + } + + + + class Min_Driver extends Min_SQL { + } + + + + function idf_escape($idf) { + return '"' . str_replace('"', '""', $idf) . '"'; + } + + function table($idf) { + return idf_escape($idf); + } + + 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) { + return array("domain"); + } + + function limit($query, $where, $limit, $offset = 0, $separator = " ") { + $return = ''; + $return .= ($limit !== null ? $separator . "FIRST $limit" . ($offset ? " SKIP $offset" : "") : ""); + $return .= " $query$where"; + return $return; + } + + function limit1($table, $query, $where, $separator = "\n") { + return limit($query, $where, 1, 0, $separator); + } + + function db_collation($db, $collations) { + } + + function engines() { + return array(); + } + + function logged_user() { + global $adminer; + $credentials = $adminer->credentials(); + return $credentials[1]; + } + + function tables_list() { + global $connection; + $query = 'SELECT RDB$RELATION_NAME FROM rdb$relations WHERE rdb$system_flag = 0'; + $result = ibase_query($connection->_link, $query); + $return = array(); + while ($row = ibase_fetch_assoc($result)) { + $return[$row['RDB$RELATION_NAME']] = 'table'; + } + ksort($return); + return $return; + } + + function count_tables($databases) { + return array(); + } + + function table_status($name = "", $fast = false) { + global $connection; + $return = array(); + $data = tables_list(); + foreach ($data as $index => $val) { + $index = trim($index); + $return[$index] = array( + 'Name' => $index, + 'Engine' => 'standard', + ); + if ($name == $index) { + return $return[$index]; + } + } + return $return; + } + + function is_view($table_status) { + return false; + } + + function fk_support($table_status) { + return preg_match('~InnoDB|IBMDB2I~i', $table_status["Engine"]); + } + + function fields($table) { + global $connection; + $return = array(); + $query = 'SELECT r.RDB$FIELD_NAME AS field_name, +r.RDB$DESCRIPTION AS field_description, +r.RDB$DEFAULT_VALUE AS field_default_value, +r.RDB$NULL_FLAG AS field_not_null_constraint, +f.RDB$FIELD_LENGTH AS field_length, +f.RDB$FIELD_PRECISION AS field_precision, +f.RDB$FIELD_SCALE AS field_scale, +CASE f.RDB$FIELD_TYPE +WHEN 261 THEN \'BLOB\' +WHEN 14 THEN \'CHAR\' +WHEN 40 THEN \'CSTRING\' +WHEN 11 THEN \'D_FLOAT\' +WHEN 27 THEN \'DOUBLE\' +WHEN 10 THEN \'FLOAT\' +WHEN 16 THEN \'INT64\' +WHEN 8 THEN \'INTEGER\' +WHEN 9 THEN \'QUAD\' +WHEN 7 THEN \'SMALLINT\' +WHEN 12 THEN \'DATE\' +WHEN 13 THEN \'TIME\' +WHEN 35 THEN \'TIMESTAMP\' +WHEN 37 THEN \'VARCHAR\' +ELSE \'UNKNOWN\' +END AS field_type, +f.RDB$FIELD_SUB_TYPE AS field_subtype, +coll.RDB$COLLATION_NAME AS field_collation, +cset.RDB$CHARACTER_SET_NAME AS field_charset +FROM RDB$RELATION_FIELDS r +LEFT JOIN RDB$FIELDS f ON r.RDB$FIELD_SOURCE = f.RDB$FIELD_NAME +LEFT JOIN RDB$COLLATIONS coll ON f.RDB$COLLATION_ID = coll.RDB$COLLATION_ID +LEFT JOIN RDB$CHARACTER_SETS cset ON f.RDB$CHARACTER_SET_ID = cset.RDB$CHARACTER_SET_ID +WHERE r.RDB$RELATION_NAME = ' . q($table) . ' +ORDER BY r.RDB$FIELD_POSITION'; + $result = ibase_query($connection->_link, $query); + while ($row = ibase_fetch_assoc($result)) { + $return[trim($row['FIELD_NAME'])] = array( + "field" => trim($row["FIELD_NAME"]), + "full_type" => trim($row["FIELD_TYPE"]), + "type" => trim($row["FIELD_SUB_TYPE"]), + "default" => trim($row['FIELD_DEFAULT_VALUE']), + "null" => (trim($row["FIELD_NOT_NULL_CONSTRAINT"]) == "YES"), + "auto_increment" => '0', + "collation" => trim($row["FIELD_COLLATION"]), + "privileges" => array("insert" => 1, "select" => 1, "update" => 1), + "comment" => trim($row["FIELD_DESCRIPTION"]), + ); + } + return $return; + } + + function indexes($table, $connection2 = null) { + $return = array(); + /* + $query = 'SELECT RDB$INDEX_SEGMENTS.RDB$FIELD_NAME AS field_name, +RDB$INDICES.RDB$DESCRIPTION AS description, +(RDB$INDEX_SEGMENTS.RDB$FIELD_POSITION + 1) AS field_position +FROM RDB$INDEX_SEGMENTS +LEFT JOIN RDB$INDICES ON RDB$INDICES.RDB$INDEX_NAME = RDB$INDEX_SEGMENTS.RDB$INDEX_NAME +LEFT JOIN RDB$RELATION_CONSTRAINTS ON RDB$RELATION_CONSTRAINTS.RDB$INDEX_NAME = RDB$INDEX_SEGMENTS.RDB$INDEX_NAME +WHERE UPPER(RDB$INDICES.RDB$RELATION_NAME) = ' . q($table) . ' +// AND UPPER(RDB$INDICES.RDB$INDEX_NAME) = \'TEST2_FIELD5_IDX\' +AND RDB$RELATION_CONSTRAINTS.RDB$CONSTRAINT_TYPE IS NULL +ORDER BY RDB$INDEX_SEGMENTS.RDB$FIELD_POSITION'; + */ + return $return; + } + + 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 support($feature) { + return preg_match("~^(columns|sql|status|table)$~", $feature); + } + + function driver_config() { + return array( + 'possible_drivers' => array("interbase"), + 'jush' => "firebird", + 'operators' => array("="), + 'functions' => array(), + 'grouping' => array(), + 'edit_functions' => array(), + ); + } +} diff --git a/plugins/drivers/simpledb.inc.php b/plugins/drivers/simpledb.inc.php new file mode 100644 index 00000000..9fafe884 --- /dev/null +++ b/plugins/drivers/simpledb.inc.php @@ -0,0 +1,488 @@ + $query, 'ConsistentRead' => 'true'); + if ($this->next) { + $params['NextToken'] = $this->next; + } + $result = sdb_request_all('Select', 'Item', $params, $this->timeout); //! respect $unbuffered + $this->timeout = 0; + if ($result === false) { + return $result; + } + if (preg_match('~^\s*SELECT\s+COUNT\(~i', $query)) { + $sum = 0; + foreach ($result as $item) { + $sum += $item->Attribute->Value; + } + $result = array((object) array('Attribute' => array((object) array( + 'Name' => 'Count', + 'Value' => $sum, + )))); + } + return new Min_Result($result); + } + + function multi_query($query) { + return $this->_result = $this->query($query); + } + + function store_result() { + return $this->_result; + } + + function next_result() { + return false; + } + + function quote($string) { + return "'" . str_replace("'", "''", $string) . "'"; + } + + } + + class Min_Result { + var $num_rows, $_rows = array(), $_offset = 0; + + function __construct($result) { + foreach ($result as $item) { + $row = array(); + if ($item->Name != '') { // SELECT COUNT(*) + $row['itemName()'] = (string) $item->Name; + } + foreach ($item->Attribute as $attribute) { + $name = $this->_processValue($attribute->Name); + $value = $this->_processValue($attribute->Value); + if (isset($row[$name])) { + $row[$name] = (array) $row[$name]; + $row[$name][] = $value; + } else { + $row[$name] = $value; + } + } + $this->_rows[] = $row; + foreach ($row as $key => $val) { + if (!isset($this->_rows[0][$key])) { + $this->_rows[0][$key] = null; + } + } + } + $this->num_rows = count($this->_rows); + } + + function _processValue($element) { + return (is_object($element) && $element['encoding'] == 'base64' ? base64_decode($element) : (string) $element); + } + + function fetch_assoc() { + $row = current($this->_rows); + if (!$row) { + return $row; + } + $return = array(); + foreach ($this->_rows[0] as $key => $val) { + $return[$key] = $row[$key]; + } + next($this->_rows); + return $return; + } + + function fetch_row() { + $return = $this->fetch_assoc(); + if (!$return) { + return $return; + } + return array_values($return); + } + + function fetch_field() { + $keys = array_keys($this->_rows[0]); + return (object) array('name' => $keys[$this->_offset++]); + } + + } + } + + + + class Min_Driver extends Min_SQL { + public $primary = "itemName()"; + + function _chunkRequest($ids, $action, $params, $expand = array()) { + global $connection; + foreach (array_chunk($ids, 25) as $chunk) { + $params2 = $params; + foreach ($chunk as $i => $id) { + $params2["Item.$i.ItemName"] = $id; + foreach ($expand as $key => $val) { + $params2["Item.$i.$key"] = $val; + } + } + if (!sdb_request($action, $params2)) { + return false; + } + } + $connection->affected_rows = count($ids); + return true; + } + + function _extractIds($table, $queryWhere, $limit) { + $return = array(); + if (preg_match_all("~itemName\(\) = (('[^']*+')+)~", $queryWhere, $matches)) { + $return = array_map('idf_unescape', $matches[1]); + } else { + foreach (sdb_request_all('Select', 'Item', array('SelectExpression' => 'SELECT itemName() FROM ' . table($table) . $queryWhere . ($limit ? " LIMIT 1" : ""))) as $item) { + $return[] = $item->Name; + } + } + return $return; + } + + function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) { + global $connection; + $connection->next = $_GET["next"]; + $return = parent::select($table, $select, $where, $group, $order, $limit, $page, $print); + $connection->next = 0; + return $return; + } + + function delete($table, $queryWhere, $limit = 0) { + return $this->_chunkRequest( + $this->_extractIds($table, $queryWhere, $limit), + 'BatchDeleteAttributes', + array('DomainName' => $table) + ); + } + + function update($table, $set, $queryWhere, $limit = 0, $separator = "\n") { + $delete = array(); + $insert = array(); + $i = 0; + $ids = $this->_extractIds($table, $queryWhere, $limit); + $id = idf_unescape($set["`itemName()`"]); + unset($set["`itemName()`"]); + foreach ($set as $key => $val) { + $key = idf_unescape($key); + if ($val == "NULL" || ($id != "" && array($id) != $ids)) { + $delete["Attribute." . count($delete) . ".Name"] = $key; + } + if ($val != "NULL") { + foreach ((array) $val as $k => $v) { + $insert["Attribute.$i.Name"] = $key; + $insert["Attribute.$i.Value"] = (is_array($val) ? $v : idf_unescape($v)); + if (!$k) { + $insert["Attribute.$i.Replace"] = "true"; + } + $i++; + } + } + } + $params = array('DomainName' => $table); + return (!$insert || $this->_chunkRequest(($id != "" ? array($id) : $ids), 'BatchPutAttributes', $params, $insert)) + && (!$delete || $this->_chunkRequest($ids, 'BatchDeleteAttributes', $params, $delete)) + ; + } + + function insert($table, $set) { + $params = array("DomainName" => $table); + $i = 0; + foreach ($set as $name => $value) { + if ($value != "NULL") { + $name = idf_unescape($name); + if ($name == "itemName()") { + $params["ItemName"] = idf_unescape($value); + } else { + foreach ((array) $value as $val) { + $params["Attribute.$i.Name"] = $name; + $params["Attribute.$i.Value"] = (is_array($value) ? $val : idf_unescape($value)); + $i++; + } + } + } + } + return sdb_request('PutAttributes', $params); + } + + function insertUpdate($table, $rows, $primary) { + //! use one batch request + foreach ($rows as $set) { + if (!$this->update($table, $set, "WHERE `itemName()` = " . q($set["`itemName()`"]))) { + return false; + } + } + return true; + } + + function begin() { + return false; + } + + function commit() { + return false; + } + + function rollback() { + return false; + } + + function slowQuery($query, $timeout) { + $this->_conn->timeout = $timeout; + return $query; + } + + } + + + + function connect() { + global $adminer; + list(, , $password) = $adminer->credentials(); + if ($password != "") { + return lang('Database does not support password.'); + } + return new Min_DB; + } + + function support($feature) { + return preg_match('~sql~', $feature); + } + + function logged_user() { + global $adminer; + $credentials = $adminer->credentials(); + return $credentials[1]; + } + + function get_databases() { + return array("domain"); + } + + function collations() { + return array(); + } + + function db_collation($db, $collations) { + } + + function tables_list() { + global $connection; + $return = array(); + foreach (sdb_request_all('ListDomains', 'DomainName') as $table) { + $return[(string) $table] = 'table'; + } + if ($connection->error && defined("PAGE_HEADER")) { + echo "

" . error() . "\n"; + } + return $return; + } + + function table_status($name = "", $fast = false) { + $return = array(); + foreach (($name != "" ? array($name => true) : tables_list()) as $table => $type) { + $row = array("Name" => $table, "Auto_increment" => ""); + if (!$fast) { + $meta = sdb_request('DomainMetadata', array('DomainName' => $table)); + if ($meta) { + foreach (array( + "Rows" => "ItemCount", + "Data_length" => "ItemNamesSizeBytes", + "Index_length" => "AttributeValuesSizeBytes", + "Data_free" => "AttributeNamesSizeBytes", + ) as $key => $val) { + $row[$key] = (string) $meta->$val; + } + } + } + if ($name != "") { + return $row; + } + $return[$table] = $row; + } + return $return; + } + + function explain($connection, $query) { + } + + 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("itemName()")), + ); + } + + function fields($table) { + return fields_from_edit(); + } + + function foreign_keys($table) { + return array(); + } + + function table($idf) { + return idf_escape($idf); + } + + function idf_escape($idf) { + return "`" . str_replace("`", "``", $idf) . "`"; + } + + function limit($query, $where, $limit, $offset = 0, $separator = " ") { + return " $query$where" . ($limit !== null ? $separator . "LIMIT $limit" : ""); + } + + function unconvert_field($field, $return) { + return $return; + } + + function fk_support($table_status) { + } + + function engines() { + return array(); + } + + function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) { + return ($table == "" && sdb_request('CreateDomain', array('DomainName' => $name))); + } + + function drop_tables($tables) { + foreach ($tables as $table) { + if (!sdb_request('DeleteDomain', array('DomainName' => $table))) { + return false; + } + } + return true; + } + + function count_tables($databases) { + foreach ($databases as $db) { + return array($db => count(tables_list())); + } + } + + function found_rows($table_status, $where) { + return ($where ? null : $table_status["Rows"]); + } + + function last_id() { + } + + function hmac($algo, $data, $key, $raw_output = false) { + // can use hash_hmac() since PHP 5.1.2 + $blocksize = 64; + if (strlen($key) > $blocksize) { + $key = pack("H*", $algo($key)); + } + $key = str_pad($key, $blocksize, "\0"); + $k_ipad = $key ^ str_repeat("\x36", $blocksize); + $k_opad = $key ^ str_repeat("\x5C", $blocksize); + $return = $algo($k_opad . pack("H*", $algo($k_ipad . $data))); + if ($raw_output) { + $return = pack("H*", $return); + } + return $return; + } + + function sdb_request($action, $params = array()) { + global $adminer, $connection; + list($host, $params['AWSAccessKeyId'], $secret) = $adminer->credentials(); + $params['Action'] = $action; + $params['Timestamp'] = gmdate('Y-m-d\TH:i:s+00:00'); + $params['Version'] = '2009-04-15'; + $params['SignatureVersion'] = 2; + $params['SignatureMethod'] = 'HmacSHA1'; + ksort($params); + $query = ''; + foreach ($params as $key => $val) { + $query .= '&' . rawurlencode($key) . '=' . rawurlencode($val); + } + $query = str_replace('%7E', '~', substr($query, 1)); + $query .= "&Signature=" . urlencode(base64_encode(hmac('sha1', "POST\n" . preg_replace('~^https?://~', '', $host) . "\n/\n$query", $secret, true))); + @ini_set('track_errors', 1); // @ - may be disabled + $file = @file_get_contents((preg_match('~^https?://~', $host) ? $host : "http://$host"), false, stream_context_create(array('http' => array( + 'method' => 'POST', // may not fit in URL with GET + 'content' => $query, + 'ignore_errors' => 1, // available since PHP 5.2.10 + )))); + if (!$file) { + $connection->error = $php_errormsg; + return false; + } + libxml_use_internal_errors(true); + $xml = simplexml_load_string($file); + if (!$xml) { + $error = libxml_get_last_error(); + $connection->error = $error->message; + return false; + } + if ($xml->Errors) { + $error = $xml->Errors->Error; + $connection->error = "$error->Message ($error->Code)"; + return false; + } + $connection->error = ''; + $tag = $action . "Result"; + return ($xml->$tag ? $xml->$tag : true); + } + + function sdb_request_all($action, $tag, $params = array(), $timeout = 0) { + $return = array(); + $start = ($timeout ? microtime(true) : 0); + $limit = (preg_match('~LIMIT\s+(\d+)\s*$~i', $params['SelectExpression'], $match) ? $match[1] : 0); + do { + $xml = sdb_request($action, $params); + if (!$xml) { + break; + } + foreach ($xml->$tag as $element) { + $return[] = $element; + } + if ($limit && count($return) >= $limit) { + $_GET["next"] = $xml->NextToken; + break; + } + if ($timeout && microtime(true) - $start > $timeout) { + return false; + } + $params['NextToken'] = $xml->NextToken; + if ($limit) { + $params['SelectExpression'] = preg_replace('~\d+\s*$~', $limit - count($return), $params['SelectExpression']); + } + } while ($xml->NextToken); + return $return; + } + + function driver_config() { + return array( + 'possible_drivers' => array("SimpleXML + allow_url_fopen"), + 'jush' => "simpledb", + 'operators' => array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "IS NOT NULL"), + 'functions' => array(), + 'grouping' => array("count"), + 'edit_functions' => array(array("json")), + ); + } +}