Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/phpmyadmin/phpmyadmin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Foellmann <foellmann@foe-services.de>2014-12-23 14:48:13 +0300
committerChristian Foellmann <foellmann@foe-services.de>2014-12-23 14:48:13 +0300
commit2bfb20e57418ebf396149782be9f98e868fe8608 (patch)
treea5ec4011410970603d3f462a535a5a359057fa77 /libraries/DatabaseInterface.class.php
parent20f1bf77c8281efc675a14e0f6bf52f657dabd9a (diff)
UPDATE 4.3.34.3.3
Diffstat (limited to 'libraries/DatabaseInterface.class.php')
-rw-r--r--libraries/DatabaseInterface.class.php1474
1 files changed, 994 insertions, 480 deletions
diff --git a/libraries/DatabaseInterface.class.php b/libraries/DatabaseInterface.class.php
index c7c5171420..507c63e349 100644
--- a/libraries/DatabaseInterface.class.php
+++ b/libraries/DatabaseInterface.class.php
@@ -9,6 +9,9 @@ if (! defined('PHPMYADMIN')) {
exit;
}
+require_once './libraries/logging.lib.php';
+require_once './libraries/Index.class.php';
+
/**
* Main interface for database interactions
*
@@ -100,7 +103,7 @@ class PMA_DatabaseInterface
// entry for Comment when changing the storage engine in Operations)
// Note 2: Instead of array_merge(), simply use the + operator because
// array_merge() renumbers numeric keys starting with 0, therefore
- // we would lose a db name thats consists only of numbers
+ // we would lose a db name that consists only of numbers
foreach ($tables as $one_database => $its_tables) {
if (isset(PMA_Table::$cache[$one_database])) {
@@ -122,10 +125,10 @@ class PMA_DatabaseInterface
/**
* Stores query data into session data for debugging purposes
*
- * @param string $query Query text
- * @param resource $link database link
- * @param resource $result Query result
- * @param integer $time Time to execute query
+ * @param string $query Query text
+ * @param object $link database link
+ * @param object $result Query result
+ * @param integer $time Time to execute query
*
* @return void
*/
@@ -137,58 +140,40 @@ class PMA_DatabaseInterface
$_SESSION['debug']['queries'][$hash]['count']++;
} else {
$_SESSION['debug']['queries'][$hash] = array();
- if ($result == false) {
+ $error_message = $this->getError($link);
+ if ($result == false && is_string($error_message)) {
$_SESSION['debug']['queries'][$hash]['error']
= '<b style="color:red">'
- . htmlspecialchars(mysqli_error($link)) . '</b>';
+ . htmlspecialchars($error_message) . '</b>';
}
$_SESSION['debug']['queries'][$hash]['count'] = 1;
$_SESSION['debug']['queries'][$hash]['query'] = htmlspecialchars($query);
$_SESSION['debug']['queries'][$hash]['time'] = $time;
}
- $trace = array();
- foreach (debug_backtrace() as $trace_step) {
- $trace[]
- = (isset($trace_step['file'])
- ? PMA_Error::relPath($trace_step['file'])
- : '')
- . (isset($trace_step['line'])
- ? '#' . $trace_step['line'] . ': '
- : '')
- . (isset($trace_step['class']) ? $trace_step['class'] : '')
- . (isset($trace_step['type']) ? $trace_step['type'] : '')
- . (isset($trace_step['function']) ? $trace_step['function'] : '')
- . '('
- . (isset($trace_step['params'])
- ? implode(', ', $trace_step['params'])
- : ''
- )
- . ')'
- ;
- }
- $_SESSION['debug']['queries'][$hash]['trace'][] = $trace;
+ $_SESSION['debug']['queries'][$hash]['trace'][] = PMA_Error::formatBacktrace(
+ debug_backtrace(),
+ " ",
+ "\n"
+ );
}
/**
* runs a query and returns the result
*
- * @param string $query query to run
- * @param resource $link mysql link resource
- * @param integer $options query options
- * @param bool $cache_affected_rows whether to cache affected row
+ * @param string $query query to run
+ * @param object $link mysql link resource
+ * @param integer $options query options
+ * @param bool $cache_affected_rows whether to cache affected row
*
* @return mixed
*/
public function tryQuery($query, $link = null, $options = 0,
$cache_affected_rows = true
) {
- if (empty($link)) {
- if (isset($GLOBALS['userlink'])) {
- $link = $GLOBALS['userlink'];
- } else {
- return false;
- }
+ $link = $this->getLink($link);
+ if ($link === false) {
+ return false;
}
if ($GLOBALS['cfg']['DBG']['sql']) {
@@ -222,12 +207,9 @@ class PMA_DatabaseInterface
*/
public function tryMultiQuery($multi_query = '', $link = null)
{
- if (empty($link)) {
- if (isset($GLOBALS['userlink'])) {
- $link = $GLOBALS['userlink'];
- } else {
- return false;
- }
+ $link = $this->getLink($link);
+ if ($link === false) {
+ return false;
}
return $this->_extension->realMultiQuery($link, $multi_query);
@@ -324,14 +306,14 @@ class PMA_DatabaseInterface
*
* @param string|bool $table table or false
* @param boolean $tbl_is_group $table is a table group
- * @param string $tble_type whether table or view
+ * @param string $table_type whether table or view
*
* @return string a segment of the WHERE clause
*/
- private function _getTableCondition($table, $tbl_is_group, $tble_type)
+ private function _getTableCondition($table, $tbl_is_group, $table_type)
{
// get table information from information_schema
- if ($table) {
+ if ($table && is_string($table)) {
if (true === $tbl_is_group) {
$sql_where_table = 'AND t.`TABLE_NAME` LIKE \''
. PMA_Util::escapeMysqlWildcards(
@@ -346,14 +328,14 @@ class PMA_DatabaseInterface
$sql_where_table = '';
}
- if ($tble_type) {
- if ($tble_type == 'view') {
+ if ($table_type) {
+ if ($table_type == 'view') {
if (PMA_DRIZZLE) {
$sql_where_table .= " AND t.`TABLE_TYPE` != 'BASE'";
} else {
$sql_where_table .= " AND t.`TABLE_TYPE` != 'BASE TABLE'";
}
- } else if ($tble_type == 'table') {
+ } else if ($table_type == 'table') {
if (PMA_DRIZZLE) {
$sql_where_table .= " AND t.`TABLE_TYPE` = 'BASE'";
} else {
@@ -367,23 +349,15 @@ class PMA_DatabaseInterface
/**
* returns the beginning of the SQL statement to fetch the list of tables
*
- * @param array $this_databases databases to list
- * @param string $sql_where_table additional condition
+ * @param string[] $this_databases databases to list
+ * @param string $sql_where_table additional condition
*
* @return string the SQL statement
*/
private function _getSqlForTablesFull($this_databases, $sql_where_table)
{
if (PMA_DRIZZLE) {
- $engine_info = PMA_Util::cacheGet('drizzle_engines', null);
- $stats_join = "LEFT JOIN (SELECT 0 NUM_ROWS) AS stat ON false";
- if (isset($engine_info['InnoDB'])
- && $engine_info['InnoDB']['module_library'] == 'innobase'
- ) {
- $stats_join = "LEFT JOIN data_dictionary.INNODB_SYS_TABLESTATS"
- . " stat ON (t.ENGINE = 'InnoDB' AND stat.NAME"
- . " = (t.TABLE_SCHEMA || '/') || t.TABLE_NAME)";
- }
+ $stats_join = $this->_getDrizzeStatsJoin();
// data_dictionary.table_cache may not contain any data
// for some tables, it's just a table cache
@@ -478,7 +452,7 @@ class PMA_DatabaseInterface
* @param boolean|integer $limit_count number of tables to return
* @param string $sort_by table attribute to sort by
* @param string $sort_order direction to sort (ASC or DESC)
- * @param string $tble_type whether table or view
+ * @param string $table_type whether table or view
*
* @todo move into PMA_Table
*
@@ -487,7 +461,7 @@ class PMA_DatabaseInterface
public function getTablesFull($database, $table = false,
$tbl_is_group = false, $link = null, $limit_offset = 0,
$limit_count = false, $sort_by = 'Name', $sort_order = 'ASC',
- $tble_type = null
+ $table_type = null
) {
if (true === $limit_count) {
$limit_count = $GLOBALS['cfg']['MaxTableList'];
@@ -501,84 +475,83 @@ class PMA_DatabaseInterface
$tables = array();
- $sql_where_table = $this->_getTableCondition(
- $table, $tbl_is_group, $tble_type
- );
+ if (! $GLOBALS['cfg']['Server']['DisableIS']) {
+ $sql_where_table = $this->_getTableCondition(
+ $table, $tbl_is_group, $table_type
+ );
- // for PMA bc:
- // `SCHEMA_FIELD_NAME` AS `SHOW_TABLE_STATUS_FIELD_NAME`
- //
- // on non-Windows servers,
- // added BINARY in the WHERE clause to force a case sensitive
- // comparison (if we are looking for the db Aa we don't want
- // to find the db aa)
- $this_databases = array_map('PMA_Util::sqlAddSlashes', $databases);
+ // for PMA bc:
+ // `SCHEMA_FIELD_NAME` AS `SHOW_TABLE_STATUS_FIELD_NAME`
+ //
+ // on non-Windows servers,
+ // added BINARY in the WHERE clause to force a case sensitive
+ // comparison (if we are looking for the db Aa we don't want
+ // to find the db aa)
+ $this_databases = array_map('PMA_Util::sqlAddSlashes', $databases);
- $sql = $this->_getSqlForTablesFull($this_databases, $sql_where_table);
- unset($sql_where_table);
+ $sql = $this->_getSqlForTablesFull($this_databases, $sql_where_table);
- // Sort the tables
- $sql .= " ORDER BY $sort_by $sort_order";
+ // Sort the tables
+ $sql .= " ORDER BY $sort_by $sort_order";
- if ($limit_count) {
- $sql .= ' LIMIT ' . $limit_count . ' OFFSET ' . $limit_offset;
- }
+ if ($limit_count) {
+ $sql .= ' LIMIT ' . $limit_count . ' OFFSET ' . $limit_offset;
+ }
- $tables = $this->fetchResult(
- $sql, array('TABLE_SCHEMA', 'TABLE_NAME'), null, $link
- );
- unset($sql);
+ $tables = $this->fetchResult(
+ $sql, array('TABLE_SCHEMA', 'TABLE_NAME'), null, $link
+ );
- if (PMA_DRIZZLE) {
- // correct I_S and D_D names returned by D_D.TABLES -
- // Drizzle generally uses lower case for them,
- // but TABLES returns uppercase
- foreach ((array)$database as $db) {
- $db_upper = strtoupper($db);
- if (!isset($tables[$db]) && isset($tables[$db_upper])) {
- $tables[$db] = $tables[$db_upper];
- unset($tables[$db_upper]);
+ if (PMA_DRIZZLE) {
+ // correct I_S and D_D names returned by D_D.TABLES -
+ // Drizzle generally uses lower case for them,
+ // but TABLES returns uppercase
+ foreach ((array)$database as $db) {
+ $db_upper = /*overload*/mb_strtoupper($db);
+ if (!isset($tables[$db]) && isset($tables[$db_upper])) {
+ $tables[$db] = $tables[$db_upper];
+ unset($tables[$db_upper]);
+ }
}
}
- }
- if ($sort_by == 'Name' && $GLOBALS['cfg']['NaturalOrder']) {
- // here, the array's first key is by schema name
- foreach ($tables as $one_database_name => $one_database_tables) {
- uksort($one_database_tables, 'strnatcasecmp');
+ if ($sort_by == 'Name' && $GLOBALS['cfg']['NaturalOrder']) {
+ // here, the array's first key is by schema name
+ foreach ($tables as $one_database_name => $one_database_tables) {
+ uksort($one_database_tables, 'strnatcasecmp');
- if ($sort_order == 'DESC') {
- $one_database_tables = array_reverse($one_database_tables);
- }
- $tables[$one_database_name] = $one_database_tables;
- }
- } else if ($sort_by == 'Data_length') { // Size = Data_length + Index_length
- foreach ($tables as $one_database_name => $one_database_tables) {
- uasort(
- $one_database_tables,
- function ($a, $b) {
- $aLength = $a['Data_length'] + $a['Index_length'];
- $bLength = $b['Data_length'] + $b['Index_length'];
- return ($aLength == $bLength)
- ? 0
- : ($aLength < $bLength) ? -1 : 1;
+ if ($sort_order == 'DESC') {
+ $one_database_tables = array_reverse($one_database_tables);
}
- );
+ $tables[$one_database_name] = $one_database_tables;
+ }
+ } else if ($sort_by == 'Data_length') { // Size = Data_length + Index_length
+ foreach ($tables as $one_database_name => $one_database_tables) {
+ uasort(
+ $one_database_tables,
+ function ($a, $b) {
+ $aLength = $a['Data_length'] + $a['Index_length'];
+ $bLength = $b['Data_length'] + $b['Index_length'];
+ return ($aLength == $bLength)
+ ? 0
+ : ($aLength < $bLength) ? -1 : 1;
+ }
+ );
- if ($sort_order == 'DESC') {
- $one_database_tables = array_reverse($one_database_tables);
+ if ($sort_order == 'DESC') {
+ $one_database_tables = array_reverse($one_database_tables);
+ }
+ $tables[$one_database_name] = $one_database_tables;
}
- $tables[$one_database_name] = $one_database_tables;
}
- }
- // end (get information from table schema)
+ } // end (get information from table schema)
// If permissions are wrong on even one database directory,
// information_schema does not return any table info for any database
// this is why we fall back to SHOW TABLE STATUS even for MySQL >= 50002
if (empty($tables) && !PMA_DRIZZLE) {
foreach ($databases as $each_database) {
- if ($table || (true === $tbl_is_group) || $tble_type) {
+ if ($table || (true === $tbl_is_group) || $table_type) {
$sql = 'SHOW TABLE STATUS FROM '
. PMA_Util::backquote($each_database)
. ' WHERE';
@@ -591,13 +564,13 @@ class PMA_DatabaseInterface
. "%'";
$needAnd = true;
}
- if ($tble_type) {
+ if ($table_type) {
if ($needAnd) {
$sql .= " AND";
}
- if ($tble_type == 'view') {
+ if ($table_type == 'view') {
$sql .= " `Comment` = 'VIEW'";
- } else if ($tble_type == 'table') {
+ } else if ($table_type == 'table') {
$sql .= " `Comment` != 'VIEW'";
}
}
@@ -655,8 +628,7 @@ class PMA_DatabaseInterface
if ($sort_by == 'Data_length') {
foreach ($each_tables as $table_name => $table_data) {
${$sort_by}[$table_name] = strtolower(
- $table_data['Data_length']
- + $table_data['Index_length']
+ $table_data['Data_length'] + $table_data['Index_length']
);
}
} else {
@@ -682,40 +654,118 @@ class PMA_DatabaseInterface
);
}
- $tables[$each_database] = $this->copyTableProperties(
- $each_tables, $each_database
- );
+ foreach ($each_tables as $table_name => $each_table) {
+ if (! isset($each_tables[$table_name]['Type'])
+ && isset($each_tables[$table_name]['Engine'])
+ ) {
+ // pma BC, same parts of PMA still uses 'Type'
+ $each_tables[$table_name]['Type']
+ =& $each_tables[$table_name]['Engine'];
+ } elseif (! isset($each_tables[$table_name]['Engine'])
+ && isset($each_tables[$table_name]['Type'])
+ ) {
+ // old MySQL reports Type, newer MySQL reports Engine
+ $each_tables[$table_name]['Engine']
+ =& $each_tables[$table_name]['Type'];
+ }
+
+ // MySQL forward compatibility
+ // so pma could use this array as if every server
+ // is of version >5.0
+ // todo : remove and check usage in the rest of the code,
+ // MySQL 5.0 is required by current PMA version
+ $each_tables[$table_name]['TABLE_SCHEMA']
+ = $each_database;
+ $each_tables[$table_name]['TABLE_NAME']
+ =& $each_tables[$table_name]['Name'];
+ $each_tables[$table_name]['ENGINE']
+ =& $each_tables[$table_name]['Engine'];
+ $each_tables[$table_name]['VERSION']
+ =& $each_tables[$table_name]['Version'];
+ $each_tables[$table_name]['ROW_FORMAT']
+ =& $each_tables[$table_name]['Row_format'];
+ $each_tables[$table_name]['TABLE_ROWS']
+ =& $each_tables[$table_name]['Rows'];
+ $each_tables[$table_name]['AVG_ROW_LENGTH']
+ =& $each_tables[$table_name]['Avg_row_length'];
+ $each_tables[$table_name]['DATA_LENGTH']
+ =& $each_tables[$table_name]['Data_length'];
+ $each_tables[$table_name]['MAX_DATA_LENGTH']
+ =& $each_tables[$table_name]['Max_data_length'];
+ $each_tables[$table_name]['INDEX_LENGTH']
+ =& $each_tables[$table_name]['Index_length'];
+ $each_tables[$table_name]['DATA_FREE']
+ =& $each_tables[$table_name]['Data_free'];
+ $each_tables[$table_name]['AUTO_INCREMENT']
+ =& $each_tables[$table_name]['Auto_increment'];
+ $each_tables[$table_name]['CREATE_TIME']
+ =& $each_tables[$table_name]['Create_time'];
+ $each_tables[$table_name]['UPDATE_TIME']
+ =& $each_tables[$table_name]['Update_time'];
+ $each_tables[$table_name]['CHECK_TIME']
+ =& $each_tables[$table_name]['Check_time'];
+ $each_tables[$table_name]['TABLE_COLLATION']
+ =& $each_tables[$table_name]['Collation'];
+ $each_tables[$table_name]['CHECKSUM']
+ =& $each_tables[$table_name]['Checksum'];
+ $each_tables[$table_name]['CREATE_OPTIONS']
+ =& $each_tables[$table_name]['Create_options'];
+ $each_tables[$table_name]['TABLE_COMMENT']
+ =& $each_tables[$table_name]['Comment'];
+
+ if (strtoupper($each_tables[$table_name]['Comment']) === 'VIEW'
+ && $each_tables[$table_name]['Engine'] == null
+ ) {
+ $each_tables[$table_name]['TABLE_TYPE'] = 'VIEW';
+ } elseif ($each_database == 'information_schema') {
+ $each_tables[$table_name]['TABLE_TYPE'] = 'SYSTEM VIEW';
+ } else {
+ /**
+ * @todo difference between 'TEMPORARY' and 'BASE TABLE'
+ * but how to detect?
+ */
+ $each_tables[$table_name]['TABLE_TYPE'] = 'BASE TABLE';
+ }
+ }
+
+ $tables[$each_database] = $each_tables;
}
}
+ // cache table data
+ // so PMA_Table does not require to issue SHOW TABLE STATUS again
$this->_cacheTableData($tables, $table);
- if (! is_array($database)) {
- if (isset($tables[$database])) {
- return $tables[$database];
- } elseif (isset($tables[strtolower($database)])) {
- // on windows with lower_case_table_names = 1
- // MySQL returns
- // with SHOW DATABASES or information_schema.SCHEMATA: `Test`
- // but information_schema.TABLES gives `test`
- // bug #2036
- // https://sourceforge.net/p/phpmyadmin/bugs/2036/
- return $tables[strtolower($database)];
- } else {
- // one database but inexact letter case match
- // as Drizzle is always case insensitive,
- // we can safely return the only result
- if (PMA_DRIZZLE && count($tables) == 1) {
- $keys = array_keys($tables);
- if (strlen(array_pop($keys)) == strlen($database)) {
- return array_pop($tables);
- }
- }
- return $tables;
- }
- } else {
+ if (is_array($database)) {
+ return $tables;
+ }
+
+ if (isset($tables[$database])) {
+ return $tables[$database];
+ }
+
+ if (isset($tables[/*overload*/mb_strtolower($database)])) {
+ // on windows with lower_case_table_names = 1
+ // MySQL returns
+ // with SHOW DATABASES or information_schema.SCHEMATA: `Test`
+ // but information_schema.TABLES gives `test`
+ // bug #2036
+ // https://sourceforge.net/p/phpmyadmin/bugs/2036/
+ return $tables[/*overload*/mb_strtolower($database)];
+ }
+
+ // one database but inexact letter case match
+ // as Drizzle is always case insensitive,
+ // we can safely return the only result
+ if (!PMA_DRIZZLE || !count($tables) == 1) {
return $tables;
}
+
+ $keys = array_keys($tables);
+ if (/*overload*/mb_strlen(array_pop($keys)) == /*overload*/mb_strlen($database)) {
+ return array_pop($tables);
+ }
+ return $tables;
}
/**
@@ -787,7 +837,10 @@ class PMA_DatabaseInterface
$tables[$table_name]['TABLE_COMMENT']
=& $tables[$table_name]['Comment'];
- if (strtoupper($tables[$table_name]['Comment']) === 'VIEW'
+ $commentUpper = /*overload*/mb_strtoupper(
+ $tables[$table_name]['Comment']
+ );
+ if ($commentUpper === 'VIEW'
&& $tables[$table_name]['Engine'] == null
) {
$tables[$table_name]['TABLE_TYPE'] = 'VIEW';
@@ -833,7 +886,7 @@ class PMA_DatabaseInterface
*
* @param string $database database
* @param boolean $force_stats retrieve stats also for MySQL < 5
- * @param resource $link mysql link
+ * @param object $link mysql link
* @param string $sort_by column to order by
* @param string $sort_order ASC or DESC
* @param integer $limit_offset starting offset for LIMIT
@@ -856,112 +909,154 @@ class PMA_DatabaseInterface
$apply_limit_and_order_manual = true;
- /**
- * if $GLOBALS['cfg']['NaturalOrder'] is enabled, we cannot use LIMIT
- * cause MySQL does not support natural ordering,
- * we have to do it afterward
- */
- $limit = '';
- if (! $GLOBALS['cfg']['NaturalOrder']) {
- if ($limit_count) {
- $limit = ' LIMIT ' . $limit_count . ' OFFSET ' . $limit_offset;
- }
-
- $apply_limit_and_order_manual = false;
- }
-
- // get table information from information_schema
- if ($database) {
- $sql_where_schema = 'WHERE `SCHEMA_NAME` LIKE \''
- . PMA_Util::sqlAddSlashes($database) . '\'';
- } else {
- $sql_where_schema = '';
- }
-
- if (PMA_DRIZZLE) {
- // data_dictionary.table_cache may not contain any data for some
- // tables, it's just a table cache
- $sql = 'SELECT
- s.SCHEMA_NAME,
- s.DEFAULT_COLLATION_NAME';
- if ($force_stats) {
- // no TABLE_CACHE data, stable results are better than
- // constantly changing
- $sql .= ',
- COUNT(t.TABLE_SCHEMA) AS SCHEMA_TABLES,
- SUM(stat.NUM_ROWS) AS SCHEMA_TABLE_ROWS';
- }
- $sql .= '
- FROM data_dictionary.SCHEMAS s';
- if ($force_stats) {
- $engine_info = PMA_Util::cacheGet('drizzle_engines', null);
- $stats_join = "LEFT JOIN (SELECT 0 NUM_ROWS) AS stat ON false";
- if (isset($engine_info['InnoDB'])
- && $engine_info['InnoDB']['module_library'] == 'innobase'
- ) {
- $stats_join
- = "LEFT JOIN data_dictionary.INNODB_SYS_TABLESTATS stat"
- . " ON (t.ENGINE = 'InnoDB' AND stat.NAME"
- . " = (t.TABLE_SCHEMA || '/') || t.TABLE_NAME)";
+ if (! $GLOBALS['cfg']['Server']['DisableIS']) {
+ /**
+ * if $GLOBALS['cfg']['NaturalOrder'] is enabled, we cannot use LIMIT
+ * cause MySQL does not support natural ordering,
+ * we have to do it afterward
+ */
+ $limit = '';
+ if (! $GLOBALS['cfg']['NaturalOrder']) {
+ if ($limit_count) {
+ $limit = ' LIMIT ' . $limit_count . ' OFFSET ' . $limit_offset;
}
- $sql .= "
- LEFT JOIN data_dictionary.TABLES t
- ON t.TABLE_SCHEMA = s.SCHEMA_NAME
- $stats_join";
+ $apply_limit_and_order_manual = false;
}
- $sql .= $sql_where_schema . '
- GROUP BY s.SCHEMA_NAME
- ORDER BY ' . PMA_Util::backquote($sort_by) . ' ' . $sort_order
- . $limit;
- } else {
- $sql = 'SELECT
- s.SCHEMA_NAME,
- s.DEFAULT_COLLATION_NAME';
- if ($force_stats) {
- $sql .= ',
- COUNT(t.TABLE_SCHEMA) AS SCHEMA_TABLES,
- SUM(t.TABLE_ROWS) AS SCHEMA_TABLE_ROWS,
- SUM(t.DATA_LENGTH) AS SCHEMA_DATA_LENGTH,
- SUM(t.MAX_DATA_LENGTH) AS SCHEMA_MAX_DATA_LENGTH,
- SUM(t.INDEX_LENGTH) AS SCHEMA_INDEX_LENGTH,
- SUM(t.DATA_LENGTH + t.INDEX_LENGTH)
- AS SCHEMA_LENGTH,
- SUM(t.DATA_FREE) AS SCHEMA_DATA_FREE';
+
+ // get table information from information_schema
+ if ($database) {
+ $sql_where_schema = 'WHERE `SCHEMA_NAME` LIKE \''
+ . PMA_Util::sqlAddSlashes($database) . '\'';
+ } else {
+ $sql_where_schema = '';
}
- $sql .= '
- FROM `information_schema`.SCHEMATA s';
- if ($force_stats) {
+
+ if (PMA_DRIZZLE) {
+ // data_dictionary.table_cache may not contain any data for some
+ // tables, it's just a table cache
+ $sql = 'SELECT
+ s.SCHEMA_NAME,
+ s.DEFAULT_COLLATION_NAME';
+ if ($force_stats) {
+ // no TABLE_CACHE data, stable results are better than
+ // constantly changing
+ $sql .= ',
+ COUNT(t.TABLE_SCHEMA) AS SCHEMA_TABLES,
+ SUM(stat.NUM_ROWS) AS SCHEMA_TABLE_ROWS';
+ }
$sql .= '
- LEFT JOIN `information_schema`.TABLES t
- ON BINARY t.TABLE_SCHEMA = BINARY s.SCHEMA_NAME';
+ FROM data_dictionary.SCHEMAS s';
+ if ($force_stats) {
+ $stats_join = $this->_getDrizzeStatsJoin();
+
+ $sql .= "
+ LEFT JOIN data_dictionary.TABLES t
+ ON t.TABLE_SCHEMA = s.SCHEMA_NAME
+ $stats_join";
+ }
+ $sql .= $sql_where_schema . '
+ GROUP BY s.SCHEMA_NAME
+ ORDER BY ' . PMA_Util::backquote($sort_by) . ' ' . $sort_order
+ . $limit;
+ } else {
+ $sql = 'SELECT
+ s.SCHEMA_NAME,
+ s.DEFAULT_COLLATION_NAME';
+ if ($force_stats) {
+ $sql .= ',
+ COUNT(t.TABLE_SCHEMA) AS SCHEMA_TABLES,
+ SUM(t.TABLE_ROWS) AS SCHEMA_TABLE_ROWS,
+ SUM(t.DATA_LENGTH) AS SCHEMA_DATA_LENGTH,
+ SUM(t.MAX_DATA_LENGTH) AS SCHEMA_MAX_DATA_LENGTH,
+ SUM(t.INDEX_LENGTH) AS SCHEMA_INDEX_LENGTH,
+ SUM(t.DATA_LENGTH + t.INDEX_LENGTH)
+ AS SCHEMA_LENGTH,
+ SUM(t.DATA_FREE) AS SCHEMA_DATA_FREE';
+ }
+ $sql .= '
+ FROM `information_schema`.SCHEMATA s';
+ if ($force_stats) {
+ $sql .= '
+ LEFT JOIN `information_schema`.TABLES t
+ ON BINARY t.TABLE_SCHEMA = BINARY s.SCHEMA_NAME';
+ }
+ $sql .= $sql_where_schema . '
+ GROUP BY BINARY s.SCHEMA_NAME
+ ORDER BY BINARY ' . PMA_Util::backquote($sort_by)
+ . ' ' . $sort_order
+ . $limit;
}
- $sql .= $sql_where_schema . '
- GROUP BY BINARY s.SCHEMA_NAME
- ORDER BY BINARY ' . PMA_Util::backquote($sort_by)
- . ' ' . $sort_order
- . $limit;
- }
- $databases = $this->fetchResult($sql, 'SCHEMA_NAME', null, $link);
+ $databases = $this->fetchResult($sql, 'SCHEMA_NAME', null, $link);
- $mysql_error = $this->getError($link);
- if (! count($databases) && $GLOBALS['errno']) {
- PMA_Util::mysqlDie($mysql_error, $sql);
- }
+ $mysql_error = $this->getError($link);
+ if (! count($databases) && $GLOBALS['errno']) {
+ PMA_Util::mysqlDie($mysql_error, $sql);
+ }
- // display only databases also in official database list
- // f.e. to apply hide_db and only_db
- $drops = array_diff(
- array_keys($databases), (array) $GLOBALS['pma']->databases
- );
- if (count($drops)) {
+ // display only databases also in official database list
+ // f.e. to apply hide_db and only_db
+ $drops = array_diff(
+ array_keys($databases), (array) $GLOBALS['pma']->databases
+ );
foreach ($drops as $drop) {
unset($databases[$drop]);
}
- unset($drop);
+ } else {
+ $databases = array();
+ foreach ($GLOBALS['pma']->databases as $database_name) {
+ // MySQL forward compatibility
+ // so pma could use this array as if every server is of version >5.0
+ // todo : remove and check the rest of the code for usage,
+ // MySQL 5.0 or higher is required for current PMA version
+ $databases[$database_name]['SCHEMA_NAME'] = $database_name;
+
+ if ($force_stats) {
+ include_once './libraries/mysql_charsets.inc.php';
+
+ $databases[$database_name]['DEFAULT_COLLATION_NAME']
+ = PMA_getDbCollation($database_name);
+
+ // get additional info about tables
+ $databases[$database_name]['SCHEMA_TABLES'] = 0;
+ $databases[$database_name]['SCHEMA_TABLE_ROWS'] = 0;
+ $databases[$database_name]['SCHEMA_DATA_LENGTH'] = 0;
+ $databases[$database_name]['SCHEMA_MAX_DATA_LENGTH'] = 0;
+ $databases[$database_name]['SCHEMA_INDEX_LENGTH'] = 0;
+ $databases[$database_name]['SCHEMA_LENGTH'] = 0;
+ $databases[$database_name]['SCHEMA_DATA_FREE'] = 0;
+
+ $res = $this->query(
+ 'SHOW TABLE STATUS FROM '
+ . PMA_Util::backquote($database_name) . ';'
+ );
+
+ while ($row = $this->fetchAssoc($res)) {
+ $databases[$database_name]['SCHEMA_TABLES']++;
+ $databases[$database_name]['SCHEMA_TABLE_ROWS']
+ += $row['Rows'];
+ $databases[$database_name]['SCHEMA_DATA_LENGTH']
+ += $row['Data_length'];
+ $databases[$database_name]['SCHEMA_MAX_DATA_LENGTH']
+ += $row['Max_data_length'];
+ $databases[$database_name]['SCHEMA_INDEX_LENGTH']
+ += $row['Index_length'];
+
+ // for InnoDB, this does not contain the number of
+ // overhead bytes but the total free space
+ if ('InnoDB' != $row['Engine']) {
+ $databases[$database_name]['SCHEMA_DATA_FREE']
+ += $row['Data_free'];
+ }
+ $databases[$database_name]['SCHEMA_LENGTH']
+ += $row['Data_length'] + $row['Index_length'];
+ }
+ $this->freeResult($res);
+ unset($res);
+ }
+ }
}
- unset($sql_where_schema, $sql, $drops);
/**
* apply limit and order manually now
@@ -987,6 +1082,28 @@ class PMA_DatabaseInterface
return $databases;
}
+
+ /**
+ * Generates JOIN part for the Drizzle query to get database/table stats.
+ *
+ * @return string
+ */
+ private function _getDrizzeStatsJoin()
+ {
+ $engine_info = PMA_Util::cacheGet('drizzle_engines');
+ $stats_join = "LEFT JOIN (SELECT 0 NUM_ROWS) AS stat ON false";
+ if (isset($engine_info['InnoDB'])
+ && $engine_info['InnoDB']['module_library'] == 'innobase'
+ ) {
+ $stats_join
+ = "LEFT JOIN data_dictionary.INNODB_SYS_TABLESTATS stat"
+ . " ON (t.ENGINE = 'InnoDB' AND stat.NAME"
+ . " = (t.TABLE_SCHEMA || '/') || t.TABLE_NAME)";
+ }
+ return $stats_join;
+ }
+
+
/**
* usort comparison callback
*
@@ -1032,80 +1149,167 @@ class PMA_DatabaseInterface
public function getColumnsFull($database = null, $table = null,
$column = null, $link = null
) {
- $columns = array();
-
- $sql_wheres = array();
- $array_keys = array();
+ if (! $GLOBALS['cfg']['Server']['DisableIS']) {
+ $sql_wheres = array();
+ $array_keys = array();
+
+ // get columns information from information_schema
+ if (null !== $database) {
+ $sql_wheres[] = '`TABLE_SCHEMA` = \''
+ . PMA_Util::sqlAddSlashes($database) . '\' ';
+ } else {
+ $array_keys[] = 'TABLE_SCHEMA';
+ }
+ if (null !== $table) {
+ $sql_wheres[] = '`TABLE_NAME` = \''
+ . PMA_Util::sqlAddSlashes($table) . '\' ';
+ } else {
+ $array_keys[] = 'TABLE_NAME';
+ }
+ if (null !== $column) {
+ $sql_wheres[] = '`COLUMN_NAME` = \''
+ . PMA_Util::sqlAddSlashes($column) . '\' ';
+ } else {
+ $array_keys[] = 'COLUMN_NAME';
+ }
- // get columns information from information_schema
- if (null !== $database) {
- $sql_wheres[] = '`TABLE_SCHEMA` = \''
- . PMA_Util::sqlAddSlashes($database) . '\' ';
- } else {
- $array_keys[] = 'TABLE_SCHEMA';
- }
- if (null !== $table) {
- $sql_wheres[] = '`TABLE_NAME` = \''
- . PMA_Util::sqlAddSlashes($table) . '\' ';
- } else {
- $array_keys[] = 'TABLE_NAME';
- }
- if (null !== $column) {
- $sql_wheres[] = '`COLUMN_NAME` = \''
- . PMA_Util::sqlAddSlashes($column) . '\' ';
+ // for PMA bc:
+ // `[SCHEMA_FIELD_NAME]` AS `[SHOW_FULL_COLUMNS_FIELD_NAME]`
+ if (PMA_DRIZZLE) {
+ $sql = "SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME,
+ column_name AS `Field`,
+ (CASE
+ WHEN character_maximum_length > 0
+ THEN concat(lower(data_type), '(', character_maximum_length, ')')
+ WHEN numeric_precision > 0 OR numeric_scale > 0
+ THEN concat(lower(data_type), '(', numeric_precision,
+ ',', numeric_scale, ')')
+ WHEN enum_values IS NOT NULL
+ THEN concat(lower(data_type), '(', enum_values, ')')
+ ELSE lower(data_type) END)
+ AS `Type`,
+ collation_name AS `Collation`,
+ (CASE is_nullable
+ WHEN 1 THEN 'YES'
+ ELSE 'NO' END) AS `Null`,
+ (CASE
+ WHEN is_used_in_primary THEN 'PRI'
+ ELSE '' END) AS `Key`,
+ column_default AS `Default`,
+ (CASE
+ WHEN is_auto_increment THEN 'auto_increment'
+ WHEN column_default_update
+ THEN 'on update ' || column_default_update
+ ELSE '' END) AS `Extra`,
+ NULL AS `Privileges`,
+ column_comment AS `Comment`
+ FROM data_dictionary.columns";
+ } else {
+ $sql = '
+ SELECT *,
+ `COLUMN_NAME` AS `Field`,
+ `COLUMN_TYPE` AS `Type`,
+ `COLLATION_NAME` AS `Collation`,
+ `IS_NULLABLE` AS `Null`,
+ `COLUMN_KEY` AS `Key`,
+ `COLUMN_DEFAULT` AS `Default`,
+ `EXTRA` AS `Extra`,
+ `PRIVILEGES` AS `Privileges`,
+ `COLUMN_COMMENT` AS `Comment`
+ FROM `information_schema`.`COLUMNS`';
+ }
+ if (count($sql_wheres)) {
+ $sql .= "\n" . ' WHERE ' . implode(' AND ', $sql_wheres);
+ }
+ return $this->fetchResult($sql, $array_keys, null, $link);
} else {
- $array_keys[] = 'COLUMN_NAME';
- }
+ $columns = array();
+ if (null === $database) {
+ foreach ($GLOBALS['pma']->databases as $database) {
+ $columns[$database] = $this->getColumnsFull(
+ $database, null, null, $link
+ );
+ }
+ return $columns;
+ } elseif (null === $table) {
+ $tables = $this->getTables($database);
+ foreach ($tables as $table) {
+ $columns[$table] = $this->getColumnsFull(
+ $database, $table, null, $link
+ );
+ }
+ return $columns;
+ }
+ $sql = 'SHOW FULL COLUMNS FROM '
+ . PMA_Util::backquote($database) . '.' . PMA_Util::backquote($table);
+ if (null !== $column) {
+ $sql .= " LIKE '" . PMA_Util::sqlAddSlashes($column, true) . "'";
+ }
- // for PMA bc:
- // `[SCHEMA_FIELD_NAME]` AS `[SHOW_FULL_COLUMNS_FIELD_NAME]`
- if (PMA_DRIZZLE) {
- $sql = "SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME,
- column_name AS `Field`,
- (CASE
- WHEN character_maximum_length > 0
- THEN concat(lower(data_type), '(', character_maximum_length, ')')
- WHEN numeric_precision > 0 OR numeric_scale > 0
- THEN concat(lower(data_type), '(', numeric_precision,
- ',', numeric_scale, ')')
- WHEN enum_values IS NOT NULL
- THEN concat(lower(data_type), '(', enum_values, ')')
- ELSE lower(data_type) END)
- AS `Type`,
- collation_name AS `Collation`,
- (CASE is_nullable
- WHEN 1 THEN 'YES'
- ELSE 'NO' END) AS `Null`,
- (CASE
- WHEN is_used_in_primary THEN 'PRI'
- ELSE '' END) AS `Key`,
- column_default AS `Default`,
- (CASE
- WHEN is_auto_increment THEN 'auto_increment'
- WHEN column_default_update
- THEN 'on update ' || column_default_update
- ELSE '' END) AS `Extra`,
- NULL AS `Privileges`,
- column_comment AS `Comment`
- FROM data_dictionary.columns";
- } else {
- $sql = '
- SELECT *,
- `COLUMN_NAME` AS `Field`,
- `COLUMN_TYPE` AS `Type`,
- `COLLATION_NAME` AS `Collation`,
- `IS_NULLABLE` AS `Null`,
- `COLUMN_KEY` AS `Key`,
- `COLUMN_DEFAULT` AS `Default`,
- `EXTRA` AS `Extra`,
- `PRIVILEGES` AS `Privileges`,
- `COLUMN_COMMENT` AS `Comment`
- FROM `information_schema`.`COLUMNS`';
- }
- if (count($sql_wheres)) {
- $sql .= "\n" . ' WHERE ' . implode(' AND ', $sql_wheres);
+ $columns = $this->fetchResult($sql, 'Field', null, $link);
+ $ordinal_position = 1;
+ foreach ($columns as $column_name => $each_column) {
+
+ // MySQL forward compatibility
+ // so pma could use this array as if every server is of version >5.0
+ // todo : remove and check the rest of the code for usage,
+ // MySQL 5.0 or higher is required for current PMA version
+ $columns[$column_name]['COLUMN_NAME']
+ =& $columns[$column_name]['Field'];
+ $columns[$column_name]['COLUMN_TYPE']
+ =& $columns[$column_name]['Type'];
+ $columns[$column_name]['COLLATION_NAME']
+ =& $columns[$column_name]['Collation'];
+ $columns[$column_name]['IS_NULLABLE']
+ =& $columns[$column_name]['Null'];
+ $columns[$column_name]['COLUMN_KEY']
+ =& $columns[$column_name]['Key'];
+ $columns[$column_name]['COLUMN_DEFAULT']
+ =& $columns[$column_name]['Default'];
+ $columns[$column_name]['EXTRA']
+ =& $columns[$column_name]['Extra'];
+ $columns[$column_name]['PRIVILEGES']
+ =& $columns[$column_name]['Privileges'];
+ $columns[$column_name]['COLUMN_COMMENT']
+ =& $columns[$column_name]['Comment'];
+
+ $columns[$column_name]['TABLE_CATALOG'] = null;
+ $columns[$column_name]['TABLE_SCHEMA'] = $database;
+ $columns[$column_name]['TABLE_NAME'] = $table;
+ $columns[$column_name]['ORDINAL_POSITION'] = $ordinal_position;
+ $columns[$column_name]['DATA_TYPE']
+ = substr(
+ $columns[$column_name]['COLUMN_TYPE'],
+ 0,
+ strpos($columns[$column_name]['COLUMN_TYPE'], '(')
+ );
+ /**
+ * @todo guess CHARACTER_MAXIMUM_LENGTH from COLUMN_TYPE
+ */
+ $columns[$column_name]['CHARACTER_MAXIMUM_LENGTH'] = null;
+ /**
+ * @todo guess CHARACTER_OCTET_LENGTH from CHARACTER_MAXIMUM_LENGTH
+ */
+ $columns[$column_name]['CHARACTER_OCTET_LENGTH'] = null;
+ $columns[$column_name]['NUMERIC_PRECISION'] = null;
+ $columns[$column_name]['NUMERIC_SCALE'] = null;
+ $columns[$column_name]['CHARACTER_SET_NAME']
+ = substr(
+ $columns[$column_name]['COLLATION_NAME'],
+ 0,
+ strpos($columns[$column_name]['COLLATION_NAME'], '_')
+ );
+
+ $ordinal_position++;
+ }
+
+ if (null !== $column) {
+ reset($columns);
+ $columns = current($columns);
+ }
+
+ return $columns;
}
- return $this->fetchResult($sql, $array_keys, null, $link);
}
/**
@@ -1130,7 +1334,7 @@ class PMA_DatabaseInterface
// * used in primary key => PRI
// * unique one-column => UNI
// * indexed, one-column or first in multi-column => MUL
- // Promotion of UNI to PRI in case no promary index exists
+ // Promotion of UNI to PRI in case no primary index exists
// is done after query is executed
$sql = "SELECT
column_name AS `Field`,
@@ -1205,6 +1409,29 @@ class PMA_DatabaseInterface
if (! is_array($fields) || count($fields) == 0) {
return null;
}
+ // Check if column is a part of multiple-column index and set its 'Key'.
+ $indexes = PMA_Index::getFromTable($table, $database);
+ foreach ($fields as $field => $field_data) {
+ if (!empty($field_data['Key'])) {
+ continue;
+ }
+
+ foreach ($indexes as $index) {
+ /** @var PMA_Index $index */
+ if (!$index->hasColumn($field)) {
+ continue;
+ }
+
+ $index_columns = $index->getColumns();
+ if ($index_columns[$field]->getSeqInIndex() > 1) {
+ if ($index->isUnique()) {
+ $fields[$field]['Key'] = 'UNI';
+ } else {
+ $fields[$field]['Key'] = 'MUL';
+ }
+ }
+ }
+ }
if (PMA_DRIZZLE) {
// fix Key column, it's much simpler in PHP than in SQL
$has_pk = false;
@@ -1268,10 +1495,10 @@ class PMA_DatabaseInterface
* Returns SQL for fetching information on table indexes (SHOW INDEXES)
*
* @param string $database name of database
- * @param string $table name of the table whose indexes are to be retreived
+ * @param string $table name of the table whose indexes are to be retrieved
* @param string $where additional conditions for WHERE
*
- * @return array $indexes
+ * @return string SQL for getting indexes
*/
public function getTableIndexesSql($database, $table, $where = null)
{
@@ -1344,12 +1571,9 @@ class PMA_DatabaseInterface
public function getVariable(
$var, $type = self::GETVAR_SESSION, $link = null
) {
- if ($link === null) {
- if (isset($GLOBALS['userlink'])) {
- $link = $GLOBALS['userlink'];
- } else {
- return false;
- }
+ $link = $this->getLink($link);
+ if ($link === false) {
+ return false;
}
switch ($type) {
@@ -1372,41 +1596,33 @@ class PMA_DatabaseInterface
* been established. It sets the connection collation, and determines the
* version of MySQL which is running.
*
- * @param mixed $link mysql link resource|object
- * @param boolean $is_controluser whether link is for control user
+ * @param mixed $link mysql link resource|object
*
* @return void
*/
- public function postConnect($link, $is_controluser = false)
+ public function postConnect($link)
{
- if ($is_controluser) {
- /*
- * FIXME: Not sure if this is right approach, but we can not
- * define constants multiple time.
- */
- return;
- }
if (! defined('PMA_MYSQL_INT_VERSION')) {
- if (PMA_Util::cacheExists('PMA_MYSQL_INT_VERSION', null)) {
+ if (PMA_Util::cacheExists('PMA_MYSQL_INT_VERSION')) {
define(
'PMA_MYSQL_INT_VERSION',
- PMA_Util::cacheGet('PMA_MYSQL_INT_VERSION', null)
+ PMA_Util::cacheGet('PMA_MYSQL_INT_VERSION')
);
define(
'PMA_MYSQL_MAJOR_VERSION',
- PMA_Util::cacheGet('PMA_MYSQL_MAJOR_VERSION', null)
+ PMA_Util::cacheGet('PMA_MYSQL_MAJOR_VERSION')
);
define(
'PMA_MYSQL_STR_VERSION',
- PMA_Util::cacheGet('PMA_MYSQL_STR_VERSION', null)
+ PMA_Util::cacheGet('PMA_MYSQL_STR_VERSION')
);
define(
'PMA_MYSQL_VERSION_COMMENT',
- PMA_Util::cacheGet('PMA_MYSQL_VERSION_COMMENT', null)
+ PMA_Util::cacheGet('PMA_MYSQL_VERSION_COMMENT')
);
define(
'PMA_DRIZZLE',
- PMA_Util::cacheGet('PMA_DRIZZLE', null)
+ PMA_Util::cacheGet('PMA_DRIZZLE')
);
} else {
$version = $this->fetchSingleRow(
@@ -1430,30 +1646,26 @@ class PMA_DatabaseInterface
$version['@@version_comment']
);
} else {
- define('PMA_MYSQL_INT_VERSION', 50015);
+ define('PMA_MYSQL_INT_VERSION', 50501);
define('PMA_MYSQL_MAJOR_VERSION', 5);
- define('PMA_MYSQL_STR_VERSION', '5.00.15');
+ define('PMA_MYSQL_STR_VERSION', '5.05.01');
define('PMA_MYSQL_VERSION_COMMENT', '');
}
PMA_Util::cacheSet(
'PMA_MYSQL_INT_VERSION',
- PMA_MYSQL_INT_VERSION,
- null
+ PMA_MYSQL_INT_VERSION
);
PMA_Util::cacheSet(
'PMA_MYSQL_MAJOR_VERSION',
- PMA_MYSQL_MAJOR_VERSION,
- null
+ PMA_MYSQL_MAJOR_VERSION
);
PMA_Util::cacheSet(
'PMA_MYSQL_STR_VERSION',
- PMA_MYSQL_STR_VERSION,
- null
+ PMA_MYSQL_STR_VERSION
);
PMA_Util::cacheSet(
'PMA_MYSQL_VERSION_COMMENT',
- PMA_MYSQL_VERSION_COMMENT,
- null
+ PMA_MYSQL_VERSION_COMMENT
);
/* Detect Drizzle - it does not support charsets */
@@ -1470,8 +1682,7 @@ class PMA_DatabaseInterface
PMA_Util::cacheSet(
'PMA_DRIZZLE',
- PMA_DRIZZLE,
- null
+ PMA_DRIZZLE
);
}
}
@@ -1517,7 +1728,7 @@ class PMA_DatabaseInterface
}
// Cache plugin list for Drizzle
- if (PMA_DRIZZLE && !PMA_Util::cacheExists('drizzle_engines', null)) {
+ if (PMA_DRIZZLE && !PMA_Util::cacheExists('drizzle_engines')) {
$sql = "SELECT p.plugin_name, m.module_library
FROM data_dictionary.plugins p
JOIN data_dictionary.modules m USING (module_name)
@@ -1525,7 +1736,7 @@ class PMA_DatabaseInterface
AND p.plugin_name NOT IN ('FunctionEngine', 'schema')
AND p.is_active = 'YES'";
$engines = $this->fetchResult($sql, 'plugin_name', null, $link);
- PMA_Util::cacheSet('drizzle_engines', $engines, null);
+ PMA_Util::cacheSet('drizzle_engines', $engines);
}
}
@@ -1541,27 +1752,28 @@ class PMA_DatabaseInterface
* // $user_name = 'John Doe'
* </code>
*
- * @param string|mysql_result $result query or mysql result
- * @param integer $row_number row to fetch the value from,
- * starting at 0, with 0 being default
- * @param integer|string $field field to fetch the value from,
- * starting at 0, with 0 being default
- * @param resource $link mysql link
+ * @param string $query The query to execute
+ * @param integer $row_number row to fetch the value from,
+ * starting at 0, with 0 being default
+ * @param integer|string $field field to fetch the value from,
+ * starting at 0, with 0 being default
+ * @param object $link mysql link
*
* @return mixed value of first field in first row from result
* or false if not found
*/
- public function fetchValue($result, $row_number = 0, $field = 0, $link = null)
+ public function fetchValue($query, $row_number = 0, $field = 0, $link = null)
{
$value = false;
- if (is_string($result)) {
- $result = $this->tryQuery(
- $result,
- $link,
- self::QUERY_STORE,
- false
- );
+ $result = $this->tryQuery(
+ $query,
+ $link,
+ self::QUERY_STORE,
+ false
+ );
+ if ($result === false) {
+ return false;
}
// return false if result is empty or false
@@ -1587,7 +1799,6 @@ class PMA_DatabaseInterface
if (isset($row[$field])) {
$value = $row[$field];
}
- unset($row);
return $value;
}
@@ -1602,27 +1813,27 @@ class PMA_DatabaseInterface
* // $user = array('id' => 123, 'name' => 'John Doe')
* </code>
*
- * @param string|mysql_result $result query or mysql result
- * @param string $type NUM|ASSOC|BOTH
- * returned array should either numeric
- * associativ or booth
- * @param resource $link mysql link
+ * @param string $query The query to execute
+ * @param string $type NUM|ASSOC|BOTH returned array should either
+ * numeric associative or both
+ * @param object $link mysql link
*
* @return array|boolean first row from result
* or false if result is empty
*/
- public function fetchSingleRow($result, $type = 'ASSOC', $link = null)
+ public function fetchSingleRow($query, $type = 'ASSOC', $link = null)
{
- if (is_string($result)) {
- $result = $this->tryQuery(
- $result,
- $link,
- self::QUERY_STORE,
- false
- );
+ $result = $this->tryQuery(
+ $query,
+ $link,
+ self::QUERY_STORE,
+ false
+ );
+ if ($result === false) {
+ return false;
}
- // return null if result is empty or false
+ // return false if result is empty or false
if (! $this->numRows($result)) {
return false;
}
@@ -1646,6 +1857,23 @@ class PMA_DatabaseInterface
}
/**
+ * Returns row or element of a row
+ *
+ * @param array $row Row to process
+ * @param string|null $value Which column to return
+ *
+ * @return mixed
+ */
+ private function _fetchValue($row, $value)
+ {
+ if (is_null($value)) {
+ return $row;
+ } else {
+ return $row[$value];
+ }
+ }
+
+ /**
* returns all rows in the resultset in one array
*
* <code>
@@ -1687,27 +1915,26 @@ class PMA_DatabaseInterface
* // $users['admin']['John Doe'] = '123'
* </code>
*
- * @param string|mysql_result $result query or mysql result
+ * @param string $query query to execute
* @param string|integer|array $key field-name or offset
* used as key for array
+ * or array of those
* @param string|integer $value value-name or offset
* used as value for array
- * @param resource $link mysql link
- * @param mixed $options query options
+ * @param object $link mysql link
+ * @param integer $options query options
*
* @return array resultrows or values indexed by $key
*/
- public function fetchResult($result, $key = null, $value = null,
+ public function fetchResult($query, $key = null, $value = null,
$link = null, $options = 0
) {
$resultrows = array();
- if (is_string($result)) {
- $result = $this->tryQuery($result, $link, $options, false);
- }
+ $result = $this->tryQuery($query, $link, $options, false);
// return empty array if result is empty or false
- if (! $result) {
+ if ($result === false) {
return $resultrows;
}
@@ -1724,35 +1951,9 @@ class PMA_DatabaseInterface
$fetch_function = 'fetchRow';
}
- if (null === $key && null === $value) {
- while ($row = $this->$fetch_function($result)) {
- $resultrows[] = $row;
- }
- } elseif (null === $key) {
+ if (null === $key) {
while ($row = $this->$fetch_function($result)) {
- $resultrows[] = $row[$value];
- }
- } elseif (null === $value) {
- if (is_array($key)) {
- while ($row = $this->$fetch_function($result)) {
- $result_target =& $resultrows;
- foreach ($key as $key_index) {
- if (null === $key_index) {
- $result_target =& $result_target[];
- continue;
- }
-
- if (! isset($result_target[$row[$key_index]])) {
- $result_target[$row[$key_index]] = array();
- }
- $result_target =& $result_target[$row[$key_index]];
- }
- $result_target = $row;
- }
- } else {
- while ($row = $this->$fetch_function($result)) {
- $resultrows[$row[$key]] = $row;
- }
+ $resultrows[] = $this->_fetchValue($row, $value);
}
} else {
if (is_array($key)) {
@@ -1769,11 +1970,11 @@ class PMA_DatabaseInterface
}
$result_target =& $result_target[$row[$key_index]];
}
- $result_target = $row[$value];
+ $result_target = $this->_fetchValue($row, $value);
}
} else {
while ($row = $this->$fetch_function($result)) {
- $resultrows[$row[$key]] = $row[$value];
+ $resultrows[$row[$key]] = $this->_fetchValue($row, $value);
}
}
}
@@ -1813,18 +2014,15 @@ class PMA_DatabaseInterface
/**
* returns warnings for last query
*
- * @param resource $link mysql link resource
+ * @param object $link mysql link resource
*
* @return array warnings
*/
public function getWarnings($link = null)
{
- if (empty($link)) {
- if (isset($GLOBALS['userlink'])) {
- $link = $GLOBALS['userlink'];
- } else {
- return array();
- }
+ $link = $this->getLink($link);
+ if ($link === false) {
+ return false;
}
return $this->fetchResult('SHOW WARNINGS', null, null, $link);
@@ -1833,9 +2031,9 @@ class PMA_DatabaseInterface
/**
* returns an array of PROCEDURE or FUNCTION names for a db
*
- * @param string $db db name
- * @param string $which PROCEDURE | FUNCTION
- * @param resource $link mysql link
+ * @param string $db db name
+ * @param string $which PROCEDURE | FUNCTION
+ * @param object $link mysql link
*
* @return array the procedure names or function names
*/
@@ -1897,22 +2095,38 @@ class PMA_DatabaseInterface
}
$result = array();
- // Note: in http://dev.mysql.com/doc/refman/5.0/en/faqs-triggers.html
- // their example uses WHERE TRIGGER_SCHEMA='dbname' so let's use this
- // instead of WHERE EVENT_OBJECT_SCHEMA='dbname'
- $query = 'SELECT TRIGGER_SCHEMA, TRIGGER_NAME, EVENT_MANIPULATION'
- . ', EVENT_OBJECT_TABLE, ACTION_TIMING, ACTION_STATEMENT'
- . ', EVENT_OBJECT_SCHEMA, EVENT_OBJECT_TABLE, DEFINER'
- . ' FROM information_schema.TRIGGERS'
- . ' WHERE TRIGGER_SCHEMA= \'' . PMA_Util::sqlAddSlashes($db) . '\'';
-
- if (! empty($table)) {
- $query .= " AND EVENT_OBJECT_TABLE = '"
- . PMA_Util::sqlAddSlashes($table) . "';";
+ if (! $GLOBALS['cfg']['Server']['DisableIS']) {
+ // Note: in http://dev.mysql.com/doc/refman/5.0/en/faqs-triggers.html
+ // their example uses WHERE TRIGGER_SCHEMA='dbname' so let's use this
+ // instead of WHERE EVENT_OBJECT_SCHEMA='dbname'
+ $query = 'SELECT TRIGGER_SCHEMA, TRIGGER_NAME, EVENT_MANIPULATION'
+ . ', EVENT_OBJECT_TABLE, ACTION_TIMING, ACTION_STATEMENT'
+ . ', EVENT_OBJECT_SCHEMA, EVENT_OBJECT_TABLE, DEFINER'
+ . ' FROM information_schema.TRIGGERS'
+ . ' WHERE TRIGGER_SCHEMA ' . PMA_Util::getCollateForIS() . '='
+ . ' \'' . PMA_Util::sqlAddSlashes($db) . '\'';
+
+ if (! empty($table)) {
+ $query .= " AND EVENT_OBJECT_TABLE = '"
+ . PMA_Util::sqlAddSlashes($table) . "';";
+ }
+ } else {
+ $query = "SHOW TRIGGERS FROM " . PMA_Util::backquote($db);
+ if (! empty($table)) {
+ $query .= " LIKE '" . PMA_Util::sqlAddSlashes($table, true) . "';";
+ }
}
if ($triggers = $this->fetchResult($query)) {
foreach ($triggers as $trigger) {
+ if ($GLOBALS['cfg']['Server']['DisableIS']) {
+ $trigger['TRIGGER_NAME'] = $trigger['Trigger'];
+ $trigger['ACTION_TIMING'] = $trigger['Timing'];
+ $trigger['EVENT_MANIPULATION'] = $trigger['Event'];
+ $trigger['EVENT_OBJECT_TABLE'] = $trigger['Table'];
+ $trigger['ACTION_STATEMENT'] = $trigger['Statement'];
+ $trigger['DEFINER'] = $trigger['Definer'];
+ }
$one_result = array();
$one_result['name'] = $trigger['TRIGGER_NAME'];
$one_result['table'] = $trigger['EVENT_OBJECT_TABLE'];
@@ -1986,7 +2200,7 @@ class PMA_DatabaseInterface
$error .= '<br />'
. __('Please check privileges of directory containing database.');
} else {
- /* InnoDB contraints, see
+ /* InnoDB constraints, see
* http://dev.mysql.com/doc/refman/5.0/en/
* innodb-foreign-key-constraints.html
*/
@@ -2004,40 +2218,163 @@ class PMA_DatabaseInterface
}
/**
- * returns true (int > 0) if current user is superuser
- * otherwise 0
+ * gets the current user with host
*
- * @return bool Whether use is a superuser
+ * @return string the current user i.e. user@host
+ */
+ public function getCurrentUser()
+ {
+ if (PMA_Util::cacheExists('mysql_cur_user')) {
+ return PMA_Util::cacheGet('mysql_cur_user');
+ }
+ $user = $GLOBALS['dbi']->fetchValue('SELECT USER();');
+ if ($user !== false) {
+ PMA_Util::cacheSet('mysql_cur_user', $user);
+ return PMA_Util::cacheGet('mysql_cur_user');
+ }
+ return '';
+ }
+
+ /**
+ * Checks if current user is superuser
+ *
+ * @return bool Whether user is a superuser
*/
public function isSuperuser()
{
- if (PMA_Util::cacheExists('is_superuser', null)) {
- return PMA_Util::cacheGet('is_superuser', null);
+ return self::isUserType('super');
+ }
+
+ /**
+ * Checks if current user has global create user/grant privilege
+ * or is a superuser (i.e. SELECT on mysql.users)
+ * while caching the result in session.
+ *
+ * @param string $type type of user to check for
+ * i.e. 'create', 'grant', 'super'
+ *
+ * @return bool Whether user is a given type of user
+ */
+ public function isUserType($type)
+ {
+ if (PMA_Util::cacheExists('is_' . $type . 'user')) {
+ return PMA_Util::cacheGet('is_' . $type . 'user');
}
// when connection failed we don't have a $userlink
- if (isset($GLOBALS['userlink'])) {
- if (PMA_DRIZZLE) {
- // Drizzle has no authorization by default, so when no plugin is
- // enabled everyone is a superuser
- // Known authorization libraries: regex_policy, simple_user_policy
- // Plugins limit object visibility (dbs, tables, processes), we can
- // safely assume we always deal with superuser
- $result = true;
- } else {
- // check access to mysql.user table
- $result = (bool) $GLOBALS['dbi']->tryQuery(
- 'SELECT COUNT(*) FROM mysql.user',
- $GLOBALS['userlink'],
- self::QUERY_STORE
- );
+ if (! isset($GLOBALS['userlink'])) {
+ PMA_Util::cacheSet('is_' . $type . 'user', false);
+ return PMA_Util::cacheGet('is_' . $type . 'user');
+ }
+
+ if (PMA_DRIZZLE) {
+ // Drizzle has no authorization by default, so when no plugin is
+ // enabled everyone is a superuser
+ // Known authorization libraries: regex_policy, simple_user_policy
+ // Plugins limit object visibility (dbs, tables, processes), we can
+ // safely assume we always deal with superuser
+ PMA_Util::cacheSet('is_' . $type . 'user', true);
+ return PMA_Util::cacheGet('is_' . $type . 'user');
+ }
+
+ if (! $GLOBALS['cfg']['Server']['DisableIS'] || $type === 'super') {
+ // Prepare query for each user type check
+ $query = '';
+ if ($type === 'super') {
+ $query = 'SELECT 1 FROM mysql.user LIMIT 1';
+ } elseif ($type === 'create') {
+ list($user, $host) = $this->_getCurrentUserAndHost();
+ $query = "SELECT 1 FROM `INFORMATION_SCHEMA`.`USER_PRIVILEGES` "
+ . "WHERE `PRIVILEGE_TYPE` = 'CREATE USER' AND "
+ . "'''" . $user . "''@''" . $host . "''' LIKE `GRANTEE` LIMIT 1";
+ } elseif ($type === 'grant') {
+ list($user, $host) = $this->_getCurrentUserAndHost();
+ $query = "SELECT 1 FROM ("
+ . "SELECT `GRANTEE`, `IS_GRANTABLE` FROM "
+ . "`INFORMATION_SCHEMA`.`COLUMN_PRIVILEGES` UNION "
+ . "SELECT `GRANTEE`, `IS_GRANTABLE` FROM "
+ . "`INFORMATION_SCHEMA`.`TABLE_PRIVILEGES` UNION "
+ . "SELECT `GRANTEE`, `IS_GRANTABLE` FROM "
+ . "`INFORMATION_SCHEMA`.`SCHEMA_PRIVILEGES` UNION "
+ . "SELECT `GRANTEE`, `IS_GRANTABLE` FROM "
+ . "`INFORMATION_SCHEMA`.`USER_PRIVILEGES`) t "
+ . "WHERE `IS_GRANTABLE` = 'YES' AND "
+ . "'''" . $user . "''@''" . $host . "''' LIKE `GRANTEE` LIMIT 1";
}
- PMA_Util::cacheSet('is_superuser', $result, null);
+
+ $is = false;
+ $result = $GLOBALS['dbi']->tryQuery(
+ $query,
+ $GLOBALS['userlink'],
+ self::QUERY_STORE
+ );
+ if ($result) {
+ $is = (bool) $GLOBALS['dbi']->numRows($result);
+ }
+ $GLOBALS['dbi']->freeResult($result);
+
+ PMA_Util::cacheSet('is_' . $type . 'user', $is);
} else {
- PMA_Util::cacheSet('is_superuser', false, null);
+ $is = false;
+ $grants = $GLOBALS['dbi']->fetchResult(
+ "SHOW GRANTS FOR CURRENT_USER();",
+ null,
+ null,
+ $GLOBALS['userlink'],
+ self::QUERY_STORE
+ );
+ if ($grants) {
+ foreach ($grants as $grant) {
+ if ($type === 'create') {
+ if (strpos($grant, "ALL PRIVILEGES ON *.*") !== false
+ || strpos($grant, "CREATE USER") !== false
+ ) {
+ $is = true;
+ break;
+ }
+ } elseif ($type === 'grant') {
+ if (strpos($grant, "WITH GRANT OPTION") !== false) {
+ $is = true;
+ break;
+ }
+ }
+ }
+ }
+
+ PMA_Util::cacheSet('is_' . $type . 'user', $is);
}
- return PMA_Util::cacheGet('is_superuser', null);
+ return PMA_Util::cacheGet('is_' . $type . 'user');
+ }
+
+ /**
+ * Get the current user and host
+ *
+ * @return array array of username and hostname
+ */
+ private function _getCurrentUserAndHost()
+ {
+ $user = $GLOBALS['dbi']->fetchValue("SELECT CURRENT_USER();");
+ return explode("@", $user);
+ }
+
+ /**
+ * Get the list of system schemas
+ *
+ * @return array list of system schemas
+ */
+ public function getSystemSchemas()
+ {
+ $schemas = array(
+ 'information_schema', 'performance_schema', 'data_dictionary', 'mysql'
+ );
+ $systemSchemas = array();
+ foreach ($schemas as $schema) {
+ if ($this->isSystemSchema($schema, true)) {
+ $systemSchemas[] = $schema;
+ }
+ }
+ return $systemSchemas;
}
/**
@@ -2053,8 +2390,10 @@ class PMA_DatabaseInterface
public function isSystemSchema($schema_name, $testForMysqlSchema = false)
{
return strtolower($schema_name) == 'information_schema'
- || (!PMA_DRIZZLE && strtolower($schema_name) == 'performance_schema')
- || (PMA_DRIZZLE && strtolower($schema_name) == 'data_dictionary')
+ || (!PMA_DRIZZLE
+ && strtolower($schema_name) == 'performance_schema')
+ || (PMA_DRIZZLE
+ && strtolower($schema_name) == 'data_dictionary')
|| ($testForMysqlSchema && !PMA_DRIZZLE && $schema_name == 'mysql');
}
@@ -2074,9 +2413,39 @@ class PMA_DatabaseInterface
$user, $password, $is_controluser = false, $server = null,
$auxiliary_connection = false
) {
- return $this->_extension->connect(
+ $result = $this->_extension->connect(
$user, $password, $is_controluser, $server, $auxiliary_connection
);
+
+ if ($result) {
+ if (! $auxiliary_connection && ! $is_controluser) {
+ $GLOBALS['dbi']->postConnect($result);
+ }
+ return $result;
+ }
+
+ if ($is_controluser) {
+ trigger_error(
+ __(
+ 'Connection for controluser as defined in your '
+ . 'configuration failed.'
+ ),
+ E_USER_WARNING
+ );
+ return false;
+ }
+
+ // we could be calling $GLOBALS['dbi']->connect() to connect to another
+ // server, for example in the Synchronize feature, so do not
+ // go back to main login if it fails
+ if ($auxiliary_connection) {
+ return false;
+ }
+
+ PMA_logUser($user, 'mysql-denied');
+ $GLOBALS['auth_plugin']->authFails();
+
+ return $result;
}
/**
@@ -2089,6 +2458,10 @@ class PMA_DatabaseInterface
*/
public function selectDb($dbname, $link = null)
{
+ $link = $this->getLink($link);
+ if ($link === false) {
+ return false;
+ }
return $this->_extension->selectDb($dbname, $link);
}
@@ -2162,7 +2535,11 @@ class PMA_DatabaseInterface
*/
public function moreResults($link = null)
{
- return $this->_extension->moreResults($link = null);
+ $link = $this->getLink($link);
+ if ($link === false) {
+ return false;
+ }
+ return $this->_extension->moreResults($link);
}
/**
@@ -2174,17 +2551,27 @@ class PMA_DatabaseInterface
*/
public function nextResult($link = null)
{
- return $this->_extension->nextResult($link = null);
+ $link = $this->getLink($link);
+ if ($link === false) {
+ return false;
+ }
+ return $this->_extension->nextResult($link);
}
/**
* Store the result returned from multi query
*
+ * @param object $link the connection object
+ *
* @return mixed false when empty results / result set when not empty
*/
- public function storeResult()
+ public function storeResult($link = null)
{
- return $this->_extension->storeResult();
+ $link = $this->getLink($link);
+ if ($link === false) {
+ return false;
+ }
+ return $this->_extension->storeResult($link);
}
/**
@@ -2196,6 +2583,10 @@ class PMA_DatabaseInterface
*/
public function getHostInfo($link = null)
{
+ $link = $this->getLink($link);
+ if ($link === false) {
+ return false;
+ }
return $this->_extension->getHostInfo($link);
}
@@ -2208,6 +2599,10 @@ class PMA_DatabaseInterface
*/
public function getProtoInfo($link = null)
{
+ $link = $this->getLink($link);
+ if ($link === false) {
+ return false;
+ }
return $this->_extension->getProtoInfo($link);
}
@@ -2230,6 +2625,10 @@ class PMA_DatabaseInterface
*/
public function getError($link = null)
{
+ $link = $this->getLink($link);
+ if ($link === false) {
+ return false;
+ }
return $this->_extension->getError($link);
}
@@ -2255,7 +2654,19 @@ class PMA_DatabaseInterface
*/
public function insertId($link = null)
{
- return $this->_extension->insertId($link);
+ $link = $this->getLink($link);
+ if ($link === false) {
+ return false;
+ }
+ // If the primary key is BIGINT we get an incorrect result
+ // (sometimes negative, sometimes positive)
+ // and in the present function we don't know if the PK is BIGINT
+ // so better play safe and use LAST_INSERT_ID()
+ //
+ // When no controluser is defined, using mysqli_insert_id($link)
+ // does not always return the last insert id due to a mixup with
+ // the tracking mechanism, but this works:
+ return $GLOBALS['dbi']->fetchValue('SELECT LAST_INSERT_ID();', 0, 0, $link);
}
/**
@@ -2264,11 +2675,20 @@ class PMA_DatabaseInterface
* @param object $link the connection object
* @param bool $get_from_cache whether to retrieve from cache
*
- * @return string|int
+ * @return int
*/
public function affectedRows($link = null, $get_from_cache = true)
{
- return $this->_extension->affectedRows($link, $get_from_cache);
+ $link = $this->getLink($link);
+ if ($link === false) {
+ return false;
+ }
+
+ if ($get_from_cache) {
+ return $GLOBALS['cached_affected_rows'];
+ } else {
+ return $this->_extension->affectedRows($link);
+ }
}
/**
@@ -2333,5 +2753,99 @@ class PMA_DatabaseInterface
{
return $this->_extension->fieldFlags($result, $i);
}
+
+ /**
+ * Gets server connection port
+ *
+ * @param array|null $server host/port/socket/persistent
+ *
+ * @return null|integer
+ */
+ public function getServerPort($server = null)
+ {
+ if (is_null($server)) {
+ $server = &$GLOBALS['cfg']['Server'];
+ }
+
+ if (empty($server['port'])) {
+ return null;
+ } else {
+ return intval($server['port']);
+ }
+ }
+
+ /**
+ * Gets server connection socket
+ *
+ * @param array|null $server host/port/socket/persistent
+ *
+ * @return null|string
+ */
+ public function getServerSocket($server = null)
+ {
+ if (is_null($server)) {
+ $server = &$GLOBALS['cfg']['Server'];
+ }
+
+ if (empty($server['socket'])) {
+ return null;
+ } else {
+ return $server['socket'];
+ }
+ }
+
+ /**
+ * Gets correct link object.
+ *
+ * @param mixed $link optional database link to use
+ *
+ * @return object
+ */
+ public function getLink($link = null)
+ {
+ if ( ! is_null($link) && $link !== false) {
+ return $link;
+ }
+
+ if (isset($GLOBALS['userlink']) && !is_null($GLOBALS['userlink'])) {
+ return $GLOBALS['userlink'];
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Checks if this database server is running on Amazon RDS.
+ *
+ * @return boolean
+ */
+ public function isAmazonRds()
+ {
+ if (PMA_Util::cacheExists('is_amazon_rds')) {
+ return PMA_Util::cacheGet('is_amazon_rds');
+ }
+ $sql = 'SELECT @@basedir';
+ $result = $this->fetchResult($sql);
+ $rds = ($result[0] == '/rdsdbbin/mysql/');
+ PMA_Util::cacheSet('is_amazon_rds', $rds);
+
+ return $rds;
+ }
+
+ /**
+ * Gets SQL for killing a process.
+ *
+ * @param int $process Process ID
+ *
+ * @return string
+ */
+ public function getKillQuery($process)
+ {
+ if ($this->isAmazonRds()) {
+ return 'CALL mysql.rds_kill(' . $process . ');';
+ } else {
+ return 'KILL ' . $process . ';';
+ }
+ }
}
?>