adminerevo/adminer/drivers/mysql.inc.php

987 lines
30 KiB
PHP
Raw Normal View History

<?php
$drivers = array("server" => "MySQL") + $drivers;
if (!defined("DRIVER")) {
$possible_drivers = array("MySQLi", "MySQL", "PDO_MySQL");
define("DRIVER", "server"); // server - backwards compatibility
// MySQLi supports everything, MySQL doesn't support multiple result sets, PDO_MySQL doesn't support orgtable
if (extension_loaded("mysqli")) {
class Min_DB extends MySQLi {
var $extension = "MySQLi";
function Min_DB() {
parent::init();
}
function connect($server, $username, $password) {
2010-09-09 20:02:35 +00:00
mysqli_report(MYSQLI_REPORT_OFF); // stays between requests, not required since PHP 5.3.4
list($host, $port) = explode(":", $server, 2); // part after : is used for port or socket
$return = @$this->real_connect(
($server != "" ? $host : ini_get("mysqli.default_host")),
2011-06-22 13:06:46 +00:00
($server . $username != "" ? $username : ini_get("mysqli.default_user")),
($server . $username . $password != "" ? $password : ini_get("mysqli.default_pw")),
null,
(is_numeric($port) ? $port : ini_get("mysqli.default_port")),
(!is_numeric($port) ? $port : null)
);
if ($return) {
if (method_exists($this, 'set_charset')) {
$this->set_charset("utf8");
} else {
$this->query("SET NAMES utf8");
}
}
return $return;
}
function result($query, $field = 0) {
$result = $this->query($query);
if (!$result) {
return false;
}
$row = $result->fetch_array();
return $row[$field];
}
function quote($string) {
return "'" . $this->escape_string($string) . "'";
}
}
2011-08-25 15:46:25 +00:00
} elseif (extension_loaded("mysql") && !(ini_get("sql.safe_mode") && extension_loaded("pdo_mysql"))) {
class Min_DB {
var
$extension = "MySQL", ///< @var string extension name
$server_info, ///< @var string server version
$affected_rows, ///< @var int number of affected rows
$error, ///< @var string last error message
$_link, $_result ///< @access private
;
/** Connect to server
* @param string
* @param string
* @param string
* @return bool
*/
function connect($server, $username, $password) {
$this->_link = @mysql_connect(
($server != "" ? $server : ini_get("mysql.default_host")),
("$server$username" != "" ? $username : ini_get("mysql.default_user")),
("$server$username$password" != "" ? $password : ini_get("mysql.default_password")),
true,
131072 // CLIENT_MULTI_RESULTS for CALL
);
if ($this->_link) {
$this->server_info = mysql_get_server_info($this->_link);
if (function_exists('mysql_set_charset')) {
mysql_set_charset("utf8", $this->_link);
} else {
$this->query("SET NAMES utf8");
}
} else {
$this->error = mysql_error();
}
return (bool) $this->_link;
}
/** Quote string to use in SQL
* @param string
* @return string escaped string enclosed in '
*/
function quote($string) {
return "'" . mysql_real_escape_string($string, $this->_link) . "'";
}
/** Select database
* @param string
* @return bool
*/
function select_db($database) {
return mysql_select_db($database, $this->_link);
}
/** Send query
* @param string
* @param bool
* @return mixed bool or Min_Result
*/
function query($query, $unbuffered = false) {
$result = @($unbuffered ? mysql_unbuffered_query($query, $this->_link) : mysql_query($query, $this->_link)); // @ - mute mysql.trace_mode
2012-07-15 16:21:22 +00:00
$this->error = "";
if (!$result) {
$this->error = mysql_error($this->_link);
return false;
}
if ($result === true) {
$this->affected_rows = mysql_affected_rows($this->_link);
$this->info = mysql_info($this->_link);
return true;
}
return new Min_Result($result);
}
/** Send query with more resultsets
* @param string
* @return bool
*/
function multi_query($query) {
return $this->_result = $this->query($query);
}
/** Get current resultset
* @return Min_Result
*/
function store_result() {
return $this->_result;
}
/** Fetch next resultset
* @return bool
*/
function next_result() {
// MySQL extension doesn't support multiple results
return false;
}
/** Get single field from result
* @param string
* @param int
* @return string
*/
function result($query, $field = 0) {
$result = $this->query($query);
2011-02-01 15:26:21 +00:00
if (!$result || !$result->num_rows) {
return false;
}
return mysql_result($result->_result, 0, $field);
}
}
class Min_Result {
var
$num_rows, ///< @var int number of rows in the result
$_result, $_offset = 0 ///< @access private
;
/** Constructor
* @param resource
*/
function Min_Result($result) {
$this->_result = $result;
$this->num_rows = mysql_num_rows($result);
}
/** Fetch next row as associative array
* @return array
*/
function fetch_assoc() {
return mysql_fetch_assoc($this->_result);
}
/** Fetch next row as numbered array
* @return array
*/
function fetch_row() {
return mysql_fetch_row($this->_result);
}
/** Fetch next field
* @return object properties: name, type, orgtable, orgname, charsetnr
*/
function fetch_field() {
$return = mysql_fetch_field($this->_result, $this->_offset++); // offset required under certain conditions
$return->orgtable = $return->table;
$return->orgname = $return->name;
$return->charsetnr = ($return->blob ? 63 : 0);
return $return;
}
/** Free result set
*/
function __destruct() {
mysql_free_result($this->_result); //! not called in PHP 4 which is a problem with mysql.trace_mode
}
}
} elseif (extension_loaded("pdo_mysql")) {
class Min_DB extends Min_PDO {
var $extension = "PDO_MySQL";
function connect($server, $username, $password) {
2010-10-22 22:02:24 +00:00
$this->dsn("mysql:host=" . str_replace(":", ";unix_socket=", preg_replace('~:(\\d)~', ';port=\\1', $server)), $username, $password);
$this->query("SET NAMES utf8"); // charset in DSN is ignored
return true;
}
function select_db($database) {
// database selection is separated from the connection so dbname in DSN can't be used
return $this->query("USE " . idf_escape($database));
}
function query($query, $unbuffered = false) {
$this->setAttribute(1000, !$unbuffered); // 1000 - PDO::MYSQL_ATTR_USE_BUFFERED_QUERY
return parent::query($query, $unbuffered);
}
}
}
/** Escape database identifier
* @param string
* @return string
*/
function idf_escape($idf) {
return "`" . str_replace("`", "``", $idf) . "`";
}
2010-05-11 14:45:04 +00:00
/** Get escaped table name
* @param string
* @return string
*/
function table($idf) {
return idf_escape($idf);
}
/** Connect to the database
* @return mixed Min_DB or string for error
*/
function connect() {
global $adminer;
$connection = new Min_DB;
$credentials = $adminer->credentials();
if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
2011-09-27 00:24:20 +00:00
$connection->query("SET sql_quote_show_create = 1, autocommit = 1");
return $connection;
}
2011-08-09 09:51:18 +00:00
$return = $connection->error;
if (function_exists('iconv') && !is_utf8($return) && strlen($s = iconv("windows-1250", "utf-8", $return)) > strlen($return)) { // windows-1250 - most common Windows encoding
$return = $s;
}
return $return;
}
/** Get cached list of databases
* @param bool
* @return array
*/
2012-08-19 16:43:31 +00:00
function get_databases($flush) {
global $connection;
// SHOW DATABASES can take a very long time so it is cached
$return = &get_session("dbs");
2012-05-14 06:54:07 +00:00
if ($return === null) {
if ($flush) {
ob_flush();
flush();
}
2012-08-19 20:42:13 +00:00
$databases = get_vals($connection->server_info >= 5 ? "SELECT SCHEMA_NAME FROM information_schema.SCHEMATA" : "SHOW DATABASES"); // SHOW DATABASES can be disabled by skip_show_database
restart_session();
$return = $databases;
stop_session();
}
return $return;
}
/** Formulate SQL query with limit
* @param string everything after SELECT
2010-05-14 13:51:54 +00:00
* @param string including WHERE
* @param int
* @param int
* @param string
* @return string
*/
2010-05-14 13:51:54 +00:00
function limit($query, $where, $limit, $offset = 0, $separator = " ") {
2012-05-14 06:54:07 +00:00
return " $query$where" . ($limit !== null ? $separator . "LIMIT $limit" . ($offset ? " OFFSET $offset" : "") : "");
}
/** Formulate SQL modification query with limit 1
* @param string everything after UPDATE or DELETE
* @return string
*/
2010-05-14 13:51:54 +00:00
function limit1($query, $where) {
return limit($query, $where, 1);
}
/** Get database collation
* @param string
* @param array result of collations()
* @return string
*/
function db_collation($db, $collations) {
global $connection;
$return = null;
$create = $connection->result("SHOW CREATE DATABASE " . idf_escape($db), 1);
if (preg_match('~ COLLATE ([^ ]+)~', $create, $match)) {
$return = $match[1];
} elseif (preg_match('~ CHARACTER SET ([^ ]+)~', $create, $match)) {
// default collation
$return = $collations[$match[1]][-1];
}
return $return;
}
/** Get supported engines
* @return array
*/
function engines() {
$return = array();
2010-10-13 15:53:59 +00:00
foreach (get_rows("SHOW ENGINES") as $row) {
if (ereg("YES|DEFAULT", $row["Support"])) {
$return[] = $row["Engine"];
}
}
return $return;
}
/** Get logged user
* @return string
*/
function logged_user() {
global $connection;
return $connection->result("SELECT USER()");
}
/** Get tables list
2011-07-27 18:06:50 +00:00
* @return array array($name => $type)
*/
function tables_list() {
global $connection;
return get_key_vals("SHOW" . ($connection->server_info >= 5 ? " FULL" : "") . " TABLES");
}
/** Count tables in all databases
* @param array
* @return array array($db => $tables)
*/
function count_tables($databases) {
$return = array();
foreach ($databases as $db) {
$return[$db] = count(get_vals("SHOW TABLES IN " . idf_escape($db)));
}
return $return;
}
/** Get table status
* @param string
2011-07-29 14:41:52 +00:00
* @return array array($name => array("Name" => , "Engine" => , "Comment" => , "Oid" => , "Rows" => , "Collation" => , "Auto_increment" => , "Data_length" => , "Index_length" => , "Data_free" => )) or only inner array with $name
*/
function table_status($name = "") {
$return = array();
foreach (get_rows("SHOW TABLE STATUS" . ($name != "" ? " LIKE " . q(addcslashes($name, "%_")) : "")) as $row) {
if ($row["Engine"] == "InnoDB") {
// ignore internal comment, unnecessary since MySQL 5.1.21
$row["Comment"] = preg_replace('~(?:(.+); )?InnoDB free: .*~', '\\1', $row["Comment"]);
}
if (!isset($row["Rows"])) {
$row["Comment"] = "";
}
if ($name != "") {
return $row;
}
$return[$row["Name"]] = $row;
}
return $return;
}
2010-05-27 11:31:08 +00:00
/** Find out whether the identifier is view
* @param array
* @return bool
*/
function is_view($table_status) {
return !isset($table_status["Rows"]);
}
/** Check if table supports foreign keys
* @param array result of table_status
* @return bool
*/
function fk_support($table_status) {
2011-05-17 15:20:32 +00:00
return eregi("InnoDB|IBMDB2I", $table_status["Engine"]);
}
/** Get information about fields
* @param string
* @return array array($name => array("field" => , "full_type" => , "type" => , "length" => , "unsigned" => , "default" => , "null" => , "auto_increment" => , "on_update" => , "collation" => , "privileges" => , "comment" => , "primary" => ))
*/
function fields($table) {
$return = array();
2010-10-13 15:53:59 +00:00
foreach (get_rows("SHOW FULL COLUMNS FROM " . table($table)) as $row) {
preg_match('~^([^( ]+)(?:\\((.+)\\))?( unsigned)?( zerofill)?$~', $row["Type"], $match);
$return[$row["Field"]] = array(
"field" => $row["Field"],
"full_type" => $row["Type"],
"type" => $match[1],
"length" => $match[2],
"unsigned" => ltrim($match[3] . $match[4]),
"default" => ($row["Default"] != "" || ereg("char", $match[1]) ? $row["Default"] : null),
"null" => ($row["Null"] == "YES"),
"auto_increment" => ($row["Extra"] == "auto_increment"),
"on_update" => (eregi('^on update (.+)', $row["Extra"], $match) ? $match[1] : ""), //! available since MySQL 5.1.23
"collation" => $row["Collation"],
"privileges" => array_flip(explode(",", $row["Privileges"])),
"comment" => $row["Comment"],
"primary" => ($row["Key"] == "PRI"),
);
}
return $return;
}
/** Get table indexes
* @param string
* @param string Min_DB to use
* @return array array($key_name => array("type" => , "columns" => array(), "lengths" => array()))
*/
function indexes($table, $connection2 = null) {
$return = array();
2010-10-13 15:53:59 +00:00
foreach (get_rows("SHOW INDEX FROM " . table($table), $connection2) as $row) {
$return[$row["Key_name"]]["type"] = ($row["Key_name"] == "PRIMARY" ? "PRIMARY" : ($row["Index_type"] == "FULLTEXT" ? "FULLTEXT" : ($row["Non_unique"] ? "INDEX" : "UNIQUE")));
$return[$row["Key_name"]]["columns"][] = $row["Column_name"];
$return[$row["Key_name"]]["lengths"][] = $row["Sub_part"];
}
return $return;
}
/** Get foreign keys in table
* @param string
* @return array array($name => array("db" => , "ns" => , "table" => , "source" => array(), "target" => array(), "on_delete" => , "on_update" => ))
*/
function foreign_keys($table) {
global $connection, $on_actions;
static $pattern = '`(?:[^`]|``)+`';
$return = array();
2010-05-11 14:45:04 +00:00
$create_table = $connection->result("SHOW CREATE TABLE " . table($table), 1);
if ($create_table) {
2011-08-02 15:46:13 +00:00
preg_match_all("~CONSTRAINT ($pattern) FOREIGN KEY \\(((?:$pattern,? ?)+)\\) REFERENCES ($pattern)(?:\\.($pattern))? \\(((?:$pattern,? ?)+)\\)(?: ON DELETE ($on_actions))?(?: ON UPDATE ($on_actions))?~", $create_table, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
preg_match_all("~$pattern~", $match[2], $source);
preg_match_all("~$pattern~", $match[5], $target);
$return[idf_unescape($match[1])] = array(
"db" => idf_unescape($match[4] != "" ? $match[3] : $match[4]),
"table" => idf_unescape($match[4] != "" ? $match[4] : $match[3]),
"source" => array_map('idf_unescape', $source[0]),
"target" => array_map('idf_unescape', $target[0]),
"on_delete" => ($match[6] ? $match[6] : "RESTRICT"),
"on_update" => ($match[7] ? $match[7] : "RESTRICT"),
);
}
}
return $return;
}
/** Get view SELECT
* @param string
* @return array array("select" => )
*/
function view($name) {
global $connection;
2010-05-11 14:45:04 +00:00
return array("select" => preg_replace('~^(?:[^`]|`[^`]*`)*\\s+AS\\s+~isU', '', $connection->result("SHOW CREATE VIEW " . table($name), 1)));
}
/** Get sorted grouped list of collations
* @return array
*/
function collations() {
$return = array();
2010-10-13 15:53:59 +00:00
foreach (get_rows("SHOW COLLATION") as $row) {
if ($row["Default"]) {
$return[$row["Charset"]][-1] = $row["Collation"];
} else {
$return[$row["Charset"]][] = $row["Collation"];
}
}
ksort($return);
foreach ($return as $key => $val) {
asort($return[$key]);
}
return $return;
}
/** Find out if database is information_schema
* @param string
* @return bool
*/
function information_schema($db) {
global $connection;
return ($connection->server_info >= 5 && $db == "information_schema");
}
/** Get escaped error message
* @return string
*/
function error() {
global $connection;
return h(preg_replace('~^You have an error.*syntax to use~U', "Syntax error", $connection->error));
}
/** Get line of error
* @return int 0 for first line
*/
function error_line() {
global $connection;
if (ereg(' at line ([0-9]+)$', $connection->error, $regs)) {
return $regs[1] - 1;
}
}
/** Return expression for binary comparison
* @param string
* @return string
*/
function exact_value($val) {
return q($val) . " COLLATE utf8_bin";
}
/** Create database
* @param string
* @return string
*/
function create_database($db, $collation) {
set_session("dbs", null);
return queries("CREATE DATABASE " . idf_escape($db) . ($collation ? " COLLATE " . q($collation) : ""));
}
/** Drop databases
* @param array
* @return bool
*/
function drop_databases($databases) {
set_session("dbs", null);
2010-06-01 20:39:44 +00:00
return apply_queries("DROP DATABASE", $databases, 'idf_escape');
}
/** Rename database from DB
* @param string new name
* @return string
* @return bool
*/
function rename_database($name, $collation) {
if (create_database($name, $collation)) {
//! move triggers
2010-06-18 14:38:06 +00:00
$rename = array();
foreach (tables_list() as $table => $type) {
$rename[] = table($table) . " TO " . idf_escape($name) . "." . table($table);
}
2010-06-18 14:38:06 +00:00
if (!$rename || queries("RENAME TABLE " . implode(", ", $rename))) {
queries("DROP DATABASE " . idf_escape(DB));
2010-06-18 14:38:06 +00:00
return true;
}
}
2010-06-18 14:38:06 +00:00
return false;
}
/** Generate modifier for auto increment column
* @return string
*/
function auto_increment() {
$auto_increment_index = " PRIMARY KEY";
// don't overwrite primary key by auto_increment
if ($_GET["create"] != "" && $_POST["auto_increment_col"]) {
foreach (indexes($_GET["create"]) as $index) {
if (in_array($_POST["fields"][$_POST["auto_increment_col"]]["orig"], $index["columns"], true)) {
$auto_increment_index = "";
break;
}
if ($index["type"] == "PRIMARY") {
$auto_increment_index = " UNIQUE";
}
}
}
return " AUTO_INCREMENT$auto_increment_index";
}
/** Run commands to create or alter table
* @param string "" to create
* @param string new name
* @param array of array($orig, $process_field, $after)
* @param array of strings
* @param string
* @param string
* @param string
* @param int
* @param string
* @return bool
*/
function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
$alter = array();
foreach ($fields as $field) {
$alter[] = ($field[1]
2012-07-15 21:38:45 +00:00
? ($table != "" ? ($field[0] != "" ? "CHANGE " . idf_escape($field[0]) : "ADD") : " ") . " " . implode($field[1]) . ($table != "" ? $field[2] : "")
: "DROP " . idf_escape($field[0])
);
}
$alter = array_merge($alter, $foreign);
$status = "COMMENT=" . q($comment)
. ($engine ? " ENGINE=" . q($engine) : "")
. ($collation ? " COLLATE " . q($collation) : "")
. ($auto_increment != "" ? " AUTO_INCREMENT=$auto_increment" : "")
. $partitioning
;
if ($table == "") {
2010-05-11 14:45:04 +00:00
return queries("CREATE TABLE " . table($name) . " (\n" . implode(",\n", $alter) . "\n) $status");
}
if ($table != $name) {
2010-05-11 14:45:04 +00:00
$alter[] = "RENAME TO " . table($name);
}
$alter[] = $status;
2010-05-11 14:45:04 +00:00
return queries("ALTER TABLE " . table($table) . "\n" . implode(",\n", $alter));
}
/** Run commands to alter indexes
* @param string escaped table name
2011-07-13 13:13:00 +00:00
* @param array of array("index type", "name", "(columns definition)") or array("index type", "name", "DROP")
* @return bool
*/
function alter_indexes($table, $alter) {
foreach ($alter as $key => $val) {
2011-07-13 13:13:00 +00:00
$alter[$key] = ($val[2] == "DROP"
? "\nDROP INDEX " . idf_escape($val[1])
: "\nADD $val[0] " . ($val[0] == "PRIMARY" ? "KEY " : "") . ($val[1] != "" ? idf_escape($val[1]) . " " : "") . $val[2]
);
}
2010-05-11 14:45:04 +00:00
return queries("ALTER TABLE " . table($table) . implode(",", $alter));
}
/** Run commands to truncate tables
* @param array
* @return bool
*/
function truncate_tables($tables) {
2010-05-17 16:18:32 +00:00
return apply_queries("TRUNCATE TABLE", $tables);
}
/** Drop views
* @param array
* @return bool
*/
function drop_views($views) {
2010-05-11 14:45:04 +00:00
return queries("DROP VIEW " . implode(", ", array_map('table', $views)));
}
/** Drop tables
* @param array
* @return bool
*/
function drop_tables($tables) {
2010-05-11 14:45:04 +00:00
return queries("DROP TABLE " . implode(", ", array_map('table', $tables)));
}
2010-05-05 20:11:24 +00:00
/** Move tables to other schema
* @param array
2011-02-01 13:12:22 +00:00
* @param array
2010-05-05 20:11:24 +00:00
* @param string
* @return bool
*/
function move_tables($tables, $views, $target) {
$rename = array();
foreach (array_merge($tables, $views) as $table) { // views will report SQL error
2010-05-11 14:45:04 +00:00
$rename[] = table($table) . " TO " . idf_escape($target) . "." . table($table);
2010-05-05 20:11:24 +00:00
}
return queries("RENAME TABLE " . implode(", ", $rename));
//! move triggers
}
2011-02-01 13:12:22 +00:00
/** Copy tables to other schema
* @param array
* @param array
* @param string
* @return bool
*/
function copy_tables($tables, $views, $target) {
queries("SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'");
2011-02-01 13:12:22 +00:00
foreach ($tables as $table) {
$name = ($target == DB ? table("copy_$table") : idf_escape($target) . "." . table($table));
if (!queries("DROP TABLE IF EXISTS $name")
|| !queries("CREATE TABLE $name LIKE " . table($table))
|| !queries("INSERT INTO $name SELECT * FROM " . table($table))
) {
return false;
}
}
foreach ($views as $table) {
$name = ($target == DB ? table("copy_$table") : idf_escape($target) . "." . table($table));
$view = view($table);
if (!queries("DROP VIEW IF EXISTS $name")
|| !queries("CREATE VIEW $name AS $view[select]") //! USE to avoid db.table
) {
return false;
}
}
return true;
}
/** Get information about trigger
* @param string trigger name
2012-07-15 19:04:04 +00:00
* @return array array("Trigger" => , "Timing" => , "Event" => , "Type" => , "Statement" => )
*/
function trigger($name) {
2011-08-08 16:18:16 +00:00
if ($name == "") {
return array();
}
$rows = get_rows("SHOW TRIGGERS WHERE `Trigger` = " . q($name));
2010-10-13 15:53:59 +00:00
return reset($rows);
}
/** Get defined triggers
* @param string
* @return array array($name => array($timing, $event))
*/
function triggers($table) {
$return = array();
foreach (get_rows("SHOW TRIGGERS LIKE " . q(addcslashes($table, "%_"))) as $row) {
$return[$row["Trigger"]] = array($row["Timing"], $row["Event"]);
}
return $return;
}
/** Get trigger options
* @return array ("Timing" => array(), "Type" => array())
*/
function trigger_options() {
return array(
"Timing" => array("BEFORE", "AFTER"),
// Event is always INSERT, UPDATE, DELETE
"Type" => array("FOR EACH ROW"),
);
}
/** Get information about stored routine
* @param string
2011-06-03 13:45:33 +00:00
* @param string "FUNCTION" or "PROCEDURE"
* @return array ("fields" => array("field" => , "type" => , "length" => , "unsigned" => , "inout" => , "collation" => ), "returns" => , "definition" => , "language" => )
*/
function routine($name, $type) {
global $connection, $enum_length, $inout, $types;
2010-05-25 11:29:53 +00:00
$aliases = array("bool", "boolean", "integer", "double precision", "real", "dec", "numeric", "fixed", "national char", "national varchar");
$type_pattern = "((" . implode("|", array_merge(array_keys($types), $aliases)) . ")\\b(?:\\s*\\(((?:[^'\")]*|$enum_length)+)\\))?\\s*(zerofill\\s*)?(unsigned(?:\\s+zerofill)?)?)(?:\\s*(?:CHARSET|CHARACTER\\s+SET)\\s*['\"]?([^'\"\\s]+)['\"]?)?";
2011-07-11 14:35:17 +00:00
$pattern = "\\s*(" . ($type == "FUNCTION" ? "" : $inout) . ")?\\s*(?:`((?:[^`]|``)*)`\\s*|\\b(\\S+)\\s+)$type_pattern";
$create = $connection->result("SHOW CREATE $type " . idf_escape($name), 2);
preg_match("~\\(((?:$pattern\\s*,?)*)\\)\\s*" . ($type == "FUNCTION" ? "RETURNS\\s+$type_pattern\\s+" : "") . "(.*)~is", $create, $match);
$fields = array();
preg_match_all("~$pattern\\s*,?~is", $match[1], $matches, PREG_SET_ORDER);
foreach ($matches as $param) {
$name = str_replace("``", "`", $param[2]) . $param[3];
$fields[] = array(
"field" => $name,
2010-05-25 11:29:53 +00:00
"type" => strtolower($param[5]),
"length" => preg_replace_callback("~$enum_length~s", 'normalize_enum', $param[6]),
"unsigned" => strtolower(preg_replace('~\\s+~', ' ', trim("$param[8] $param[7]"))),
"full_type" => $param[4],
"inout" => strtoupper($param[1]),
"collation" => strtolower($param[9]),
);
}
if ($type != "FUNCTION") {
return array("fields" => $fields, "definition" => $match[11]);
}
return array(
"fields" => $fields,
"returns" => array("type" => $match[12], "length" => $match[13], "unsigned" => $match[15], "collation" => $match[16]),
"definition" => $match[17],
2011-06-03 13:45:33 +00:00
"language" => "SQL", // available in information_schema.ROUTINES.PARAMETER_STYLE
);
}
2011-05-31 05:43:08 +00:00
/** Get list of routines
* @return array ("ROUTINE_TYPE" => , "ROUTINE_NAME" => , "DTD_IDENTIFIER" => )
*/
function routines() {
return get_rows("SELECT * FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = " . q(DB));
}
2011-06-03 13:45:33 +00:00
/** Get list of available routine languages
* @return array
*/
function routine_languages() {
2011-06-04 01:37:43 +00:00
return array(); // "SQL" not required
2011-06-03 13:45:33 +00:00
}
/** Begin transaction
* @return bool
*/
function begin() {
return queries("BEGIN");
}
/** Insert data into table
* @param string
* @param array
* @return bool
*/
function insert_into($table, $set) {
2010-05-11 14:45:04 +00:00
return queries("INSERT INTO " . table($table) . " (" . implode(", ", array_keys($set)) . ")\nVALUES (" . implode(", ", $set) . ")");
}
2010-05-27 14:10:17 +00:00
/** Insert or update data in the table
* @param string
* @param array
* @param array columns in keys
2010-05-27 14:10:17 +00:00
* @return bool
*/
function insert_update($table, $set, $primary) {
2010-05-27 14:10:17 +00:00
foreach ($set as $key => $val) {
$set[$key] = "$key = $val";
}
$update = implode(", ", $set);
return queries("INSERT INTO " . table($table) . " SET $update ON DUPLICATE KEY UPDATE $update");
}
/** Get last auto increment ID
* @return string
*/
function last_id() {
global $connection;
return $connection->result("SELECT LAST_INSERT_ID()"); // mysql_insert_id() truncates bigint
}
/** Explain select
* @param Min_DB
* @param string
* @return Min_Result
*/
function explain($connection, $query) {
return $connection->query("EXPLAIN $query");
}
/** Get approximate number of rows
* @param array
* @param array
* @return int or null if approximate number can't be retrieved
*/
function found_rows($table_status, $where) {
return ($where || $table_status["Engine"] != "InnoDB" ? null : $table_status["Rows"]);
}
2010-05-21 14:07:22 +00:00
/** Get user defined types
* @return array
*/
function types() {
return array();
}
/** Get existing schemas
* @return array
*/
function schemas() {
return array();
}
/** Get current schema
* @return string
*/
function get_schema() {
return "";
}
/** Set current schema
* @param string
* @return bool
*/
function set_schema($schema) {
return true;
}
/** Get SQL command to create table
* @param string
* @param bool
* @return string
*/
function create_sql($table, $auto_increment) {
global $connection;
$return = $connection->result("SHOW CREATE TABLE " . table($table), 1);
if (!$auto_increment) {
2010-10-22 22:02:24 +00:00
$return = preg_replace('~ AUTO_INCREMENT=\\d+~', '', $return); //! skip comments
}
return $return;
}
2010-05-27 14:10:17 +00:00
/** Get SQL command to truncate table
* @param string
* @return string
*/
function truncate_sql($table) {
return "TRUNCATE " . table($table);
}
/** Get SQL command to change database
* @param string
* @return string
*/
function use_sql($database) {
return "USE " . idf_escape($database);
}
/** Get SQL commands to create triggers
* @param string
* @param string
* @return string
*/
function trigger_sql($table, $style) {
$return = "";
2010-10-13 16:59:15 +00:00
foreach (get_rows("SHOW TRIGGERS LIKE " . q(addcslashes($table, "%_")), null, "-- ") as $row) {
2010-10-13 15:53:59 +00:00
$return .= "\n" . ($style == 'CREATE+ALTER' ? "DROP TRIGGER IF EXISTS " . idf_escape($row["Trigger"]) . ";;\n" : "")
. "CREATE TRIGGER " . idf_escape($row["Trigger"]) . " $row[Timing] $row[Event] ON " . table($row["Table"]) . " FOR EACH ROW\n$row[Statement];;\n";
}
return $return;
}
/** Get server variables
* @return array ($name => $value)
*/
function show_variables() {
return get_key_vals("SHOW VARIABLES");
}
2011-05-11 09:48:51 +00:00
/** Get process list
* @return array ($row)
*/
function process_list() {
return get_rows("SHOW FULL PROCESSLIST");
}
/** Get status variables
* @return array ($name => $value)
*/
function show_status() {
return get_key_vals("SHOW STATUS");
}
/** Check whether a feature is supported
2011-05-11 09:48:51 +00:00
* @param string "comment", "copy", "drop_col", "dump", "event", "kill", "partitioning", "privileges", "procedure", "processlist", "routine", "scheme", "sequence", "status", "trigger", "type", "variables", "view"
* @return bool
*/
function support($feature) {
global $connection;
2010-05-21 14:07:22 +00:00
return !ereg("scheme|sequence|type" . ($connection->server_info < 5.1 ? "|event|partitioning" . ($connection->server_info < 5 ? "|view|routine|trigger" : "") : ""), $feature);
}
2010-05-07 13:44:22 +00:00
$jush = "sql"; ///< @var string JUSH identifier
$types = array(); ///< @var array ($type => $maximum_unsigned_length, ...)
$structured_types = array(); ///< @var array ($description => array($type, ...), ...)
foreach (array(
lang('Numbers') => array("tinyint" => 3, "smallint" => 5, "mediumint" => 8, "int" => 10, "bigint" => 20, "decimal" => 66, "float" => 12, "double" => 21),
lang('Date and time') => array("date" => 10, "datetime" => 19, "timestamp" => 19, "time" => 10, "year" => 4),
lang('Strings') => array("char" => 255, "varchar" => 65535, "tinytext" => 255, "text" => 65535, "mediumtext" => 16777215, "longtext" => 4294967295),
lang('Binary') => array("bit" => 20, "binary" => 255, "varbinary" => 65535, "tinyblob" => 255, "blob" => 65535, "mediumblob" => 16777215, "longblob" => 4294967295),
lang('Lists') => array("enum" => 65535, "set" => 64),
) as $key => $val) {
$types += $val;
$structured_types[$key] = array_keys($val);
}
$unsigned = array("unsigned", "zerofill", "unsigned zerofill"); ///< @var array number variants
$operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "REGEXP", "IN", "IS NULL", "NOT LIKE", "NOT REGEXP", "NOT IN", "IS NOT NULL", ""); ///< @var array operators used in select
$functions = array("char_length", "date", "from_unixtime", "hex", "lower", "round", "sec_to_time", "time_to_sec", "upper"); ///< @var array functions used in select
$grouping = array("avg", "count", "count distinct", "group_concat", "max", "min", "sum"); ///< @var array grouping functions used in select
$edit_functions = array( ///< @var array of array("$type|$type2" => "$function/$function2") functions used in editing, [0] - edit and insert, [1] - edit only
array(
"char" => "md5/sha1/password/encrypt/uuid", //! JavaScript for disabling maxlength
2010-09-28 08:02:55 +00:00
"binary" => "md5/sha1/hex",
"date|time" => "now",
), array(
"int|float|double|decimal" => "+/-",
"date" => "+ interval/- interval",
"time" => "addtime/subtime",
"char|text" => "concat",
)
);
}