diff --git a/doc/config.rst b/doc/config.rst index ace32f44f6..d0aeda9b3b 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -998,6 +998,16 @@ Server connection settings * ``xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xx[yyy-zzz]`` (partial :term:`IPv6` address range) +.. config:option:: $cfg['Servers'][$i]['DisableIS'] + + :type: boolean + :default: false + + Disable using ``INFORMATION_SCHEMA`` to retrieve information (use + ``SHOW`` commands instead), because of speed issues when many + databases are present. Currently used in some parts of the code, more + to come. + .. config:option:: $cfg['Servers'][$i]['SignonScript'] :type: string diff --git a/libraries/DatabaseInterface.class.php b/libraries/DatabaseInterface.class.php index caf0e1d2ff..01c3d6181f 100644 --- a/libraries/DatabaseInterface.class.php +++ b/libraries/DatabaseInterface.class.php @@ -471,79 +471,270 @@ class PMA_DatabaseInterface $databases = $database; } - $sql_where_table = $this->_getTableCondition( - $table, $tbl_is_group, $table_type - ); + $tables = array(); - // 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); + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $sql_where_table = $this->_getTableCondition( + $table, $tbl_is_group, $table_type + ); - $sql = $this->_getSqlForTablesFull($this_databases, $sql_where_table); + // 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); - // Sort the tables - $sql .= " ORDER BY $sort_by $sort_order"; + $sql = $this->_getSqlForTablesFull($this_databases, $sql_where_table); - if ($limit_count) { - $sql .= ' LIMIT ' . $limit_count . ' OFFSET ' . $limit_offset; - } + // Sort the tables + $sql .= " ORDER BY $sort_by $sort_order"; - $tables = $this->fetchResult( - $sql, array('TABLE_SCHEMA', 'TABLE_NAME'), null, $link - ); - - /** @var PMA_String $pmaString */ - $pmaString = $GLOBALS['PMA_String']; - - 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 = $pmaString->strtoupper($db); - if (!isset($tables[$db]) && isset($tables[$db_upper])) { - $tables[$db] = $tables[$db_upper]; - unset($tables[$db_upper]); - } + if ($limit_count) { + $sql .= ' LIMIT ' . $limit_count . ' OFFSET ' . $limit_offset; } - } - 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'); + $tables = $this->fetchResult( + $sql, array('TABLE_SCHEMA', 'TABLE_NAME'), null, $link + ); - 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; + /** @var PMA_String $pmaString */ + $pmaString = $GLOBALS['PMA_String']; + + 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 = $pmaString->strtoupper($db); + if (!isset($tables[$db]) && isset($tables[$db_upper])) { + $tables[$db] = $tables[$db_upper]; + unset($tables[$db_upper]); } - ); - - if ($sort_order == 'DESC') { - $one_database_tables = array_reverse($one_database_tables); } - $tables[$one_database_name] = $one_database_tables; + } + + 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; + } + } + } // 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) || $table_type) { + $sql = 'SHOW TABLE STATUS FROM ' + . PMA_Util::backquote($each_database) + .' WHERE'; + $needAnd = false; + if ($table || (true === $tbl_is_group)) { + $sql .= " `Name` LIKE '" + . PMA_Util::escapeMysqlWildcards( + PMA_Util::sqlAddSlashes($table, true) + ) + . "%'"; + $needAnd = true; + } + if ($table_type) { + if ($needAnd) { + $sql .= " AND"; + } + if ($table_type == 'view') { + $sql .= " `Comment` = 'VIEW'"; + } else if ($table_type == 'table') { + $sql .= " `Comment` != 'VIEW'"; + } + } + } else { + $sql = 'SHOW TABLE STATUS FROM ' + . PMA_Util::backquote($each_database); + } + + $useStatusCache = false; + + if (extension_loaded('apc') + && isset($GLOBALS['cfg']['Server']['StatusCacheDatabases']) + && ! empty($GLOBALS['cfg']['Server']['StatusCacheLifetime']) + ) { + $statusCacheDatabases + = (array) $GLOBALS['cfg']['Server']['StatusCacheDatabases']; + if (in_array($each_database, $statusCacheDatabases)) { + $useStatusCache = true; + } + } + + $each_tables = null; + + if ($useStatusCache) { + $cacheKey = 'phpMyAdmin_tableStatus_' + . sha1($GLOBALS['cfg']['Server']['host'] . '_' . $sql); + + $each_tables = apc_fetch($cacheKey); + } + + if (! $each_tables) { + $each_tables = $this->fetchResult($sql, 'Name', null, $link); + } + + if ($useStatusCache) { + apc_store( + $cacheKey, $each_tables, + $GLOBALS['cfg']['Server']['StatusCacheLifetime'] + ); + } + + // Sort naturally if the config allows it and we're sorting + // the Name column. + if ($sort_by == 'Name' && $GLOBALS['cfg']['NaturalOrder']) { + uksort($each_tables, 'strnatcasecmp'); + + if ($sort_order == 'DESC') { + $each_tables = array_reverse($each_tables); + } + } else { + // Prepare to sort by creating array of the selected sort + // value to pass to array_multisort + + // Size = Data_length + Index_length + 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'] + ); + } + } else { + foreach ($each_tables as $table_name => $table_data) { + ${$sort_by}[$table_name] + = strtolower($table_data[$sort_by]); + } + } + + if ($sort_order == 'DESC') { + array_multisort($$sort_by, SORT_DESC, $each_tables); + } else { + array_multisort($$sort_by, SORT_ASC, $each_tables); + } + + // cleanup the temporary sort array + unset($$sort_by); + } + + if ($limit_count) { + $each_tables = array_slice( + $each_tables, $limit_offset, $limit_count + ); + } + + 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; } } - // end (get information from table schema) + // cache table data + // so PMA_Table does not require to issue SHOW TABLE STATUS again $this->_cacheTableData($tables, $table); if (is_array($database)) { @@ -718,98 +909,152 @@ 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; + 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; + } + + $apply_limit_and_order_manual = false; } - $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'; + // 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 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) { + 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 - ); - foreach ($drops as $drop) { - unset($databases[$drop]); + // 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]); + } + } else { + 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); + } + } } /** @@ -903,78 +1148,167 @@ class PMA_DatabaseInterface public function getColumnsFull($database = null, $table = null, $column = null, $link = null ) { - $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) . '\' '; + } else { + $array_keys[] = 'COLUMN_NAME'; + } - // 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"; + // 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 { - $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`'; + $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) . "'"; + } + + $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; } - if (count($sql_wheres)) { - $sql .= "\n" . ' WHERE ' . implode(' AND ', $sql_wheres); - } - return $this->fetchResult($sql, $array_keys, null, $link); } /** @@ -1760,22 +2094,37 @@ 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 (! $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::sqlAddSlashes($db) . '\''; - if (! empty($table)) { - $query .= " AND EVENT_OBJECT_TABLE = '" - . PMA_Util::sqlAddSlashes($table) . "';"; + 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']; @@ -1911,49 +2260,103 @@ class PMA_DatabaseInterface return PMA_Util::cacheGet('is_' . $type . 'user'); } - // Prepare query for each user type check - $query = ''; - if ($type === 'super') { - $query = 'SELECT 1 FROM mysql.user LIMIT 1'; - } elseif ($type === 'create') { - $query = 'SELECT 1 FROM INFORMATION_SCHEMA.USER_PRIVILEGES ' - . 'WHERE PRIVILEGE_TYPE = \'CREATE USER\' LIMIT 1'; - } elseif ($type === 'grant') { - $query = 'SELECT 1 FROM INFORMATION_SCHEMA.USER_PRIVILEGES ' - . 'WHERE IS_GRANTABLE = \'YES\' LIMIT 1'; + // when connection failed we don't have a $userlink + if (! isset($GLOBALS['userlink'])) { + PMA_Util::cacheSet('is_' . $type . 'user', false); + return PMA_Util::cacheGet('is_' . $type . 'user'); } - // when connection failed we don't have a $userlink - if (isset($GLOBALS['userlink'])) { - $is = false; - 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 - $is = true; - } else { - // Check information_schema.user_privileges table - // for global create user rights - $result = $GLOBALS['dbi']->tryQuery( - $query, - $GLOBALS['userlink'], - self::QUERY_STORE - ); - if ($result) { - $is = (bool) $GLOBALS['dbi']->numRows($result); - } - $GLOBALS['dbi']->freeResult($result); + 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"; } + + $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_' . $type . 'user', false); + $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_' . $type . 'user'); } + /** + * Get the current user and host + * + * @return array arrya of username and hostname + */ + private function _getCurrentUserAndHost() + { + $user = $GLOBALS['dbi']->fetchValue("SELECT CURRENT_USER();"); + return explode("@", $user); + } + /** * Checks whether given schema is a system schema: information_schema * (MySQL and Drizzle) or data_dictionary (Drizzle) diff --git a/libraries/Table.class.php b/libraries/Table.class.php index 055830821a..e8285f14fc 100644 --- a/libraries/Table.class.php +++ b/libraries/Table.class.php @@ -192,9 +192,15 @@ class PMA_Table // use cached data or load information with SHOW command if (isset(PMA_Table::$cache[$db][$table]) + || $GLOBALS['cfg']['Server']['DisableIS'] ) { $type = PMA_Table::sGetStatusInfo($db, $table, 'TABLE_TYPE'); - return $type == 'VIEW'; + return $type == 'VIEW' || $type == 'SYSTEM VIEW'; + } + + // information_schema tables are 'SYSTEM VIEW's + if ($db == 'information_schema') { + return true; } // query information_schema diff --git a/libraries/common.inc.php b/libraries/common.inc.php index 69a52a2234..ca250a6ae1 100644 --- a/libraries/common.inc.php +++ b/libraries/common.inc.php @@ -1015,6 +1015,9 @@ if (! defined('PMA_MINIMUM_COMMON')) { } if (PMA_DRIZZLE) { + // DisableIS must be set to false for Drizzle, it maps SHOW commands + // to INFORMATION_SCHEMA queries anyway so it's fast on large servers + $cfg['Server']['DisableIS'] = false; // SHOW OPEN TABLES is not supported by Drizzle $cfg['SkipLockedTables'] = false; } diff --git a/libraries/config.default.php b/libraries/config.default.php index be0f1080fe..324a4d03a4 100644 --- a/libraries/config.default.php +++ b/libraries/config.default.php @@ -520,6 +520,15 @@ $cfg['Servers'][$i]['AllowDeny']['order'] = ''; */ $cfg['Servers'][$i]['AllowDeny']['rules'] = array(); +/** + * Disable use of INFORMATION_SCHEMA. Is always 'false' for Drizzle. + * + * @see https://sourceforge.net/p/phpmyadmin/bugs/2606/ + * @see http://bugs.mysql.com/19588 + * @global boolean $cfg['Servers'][$i]['DisableIS'] + */ +$cfg['Servers'][$i]['DisableIS'] = false; + /** * Whether the tracking mechanism creates * versions for tables and views automatically. diff --git a/libraries/config/messages.inc.php b/libraries/config/messages.inc.php index 23f75149fe..598a341cd4 100644 --- a/libraries/config/messages.inc.php +++ b/libraries/config/messages.inc.php @@ -583,6 +583,8 @@ $strConfigServers_controlport_desc = __( $strConfigServers_controlport_name = __('Control port'); $strConfigServers_hide_db_desc = __('Hide databases matching regular expression (PCRE).'); +$strConfigServers_DisableIS_desc = __('More information on [a@https://sourceforge.net/p/phpmyadmin/bugs/2606/]PMA bug tracker[/a] and [a@http://bugs.mysql.com/19588]MySQL Bugs[/a]'); +$strConfigServers_DisableIS_name = __('Disable use of INFORMATION_SCHEMA'); $strConfigServers_hide_db_name = __('Hide databases'); $strConfigServers_history_desc = __( 'Leave blank for no SQL query history support, suggested: ' diff --git a/libraries/config/setup.forms.php b/libraries/config/setup.forms.php index 474731ee85..3e7d857c8a 100644 --- a/libraries/config/setup.forms.php +++ b/libraries/config/setup.forms.php @@ -56,6 +56,7 @@ $forms['Servers']['Server_config'] = array('Servers' => array(1 => array( 'hide_db', 'AllowRoot', 'AllowNoPassword', + 'DisableIS', 'AllowDeny/order', 'AllowDeny/rules'))); $forms['Servers']['Server_pmadb'] = array('Servers' => array(1 => array( diff --git a/libraries/dbi/DBIDummy.class.php b/libraries/dbi/DBIDummy.class.php index 926351348f..ba814ee4ed 100644 --- a/libraries/dbi/DBIDummy.class.php +++ b/libraries/dbi/DBIDummy.class.php @@ -30,13 +30,22 @@ $GLOBALS['dummy_queries'] = array( 'result' => array(array('1')), ), array( - 'query' => 'SELECT 1 FROM INFORMATION_SCHEMA.USER_PRIVILEGES ' - . 'WHERE PRIVILEGE_TYPE = \'CREATE USER\' LIMIT 1', + 'query' => "SELECT 1 FROM `INFORMATION_SCHEMA`.`USER_PRIVILEGES`" + . " WHERE `PRIVILEGE_TYPE` = 'CREATE USER'" + . " AND '''pma_test''@''localhost''' LIKE `GRANTEE` LIMIT 1", 'result' => array(array('1')), ), array( - 'query' => 'SELECT 1 FROM INFORMATION_SCHEMA.USER_PRIVILEGES ' - . 'WHERE IS_GRANTABLE = \'YES\' LIMIT 1', + '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 '''pma_test''@''localhost''' LIKE `GRANTEE` LIMIT 1", 'result' => array(array('1')), ), array( @@ -493,18 +502,18 @@ $GLOBALS['dummy_queries'] = array( ), array( 'query' => "SELECT `SCHEMA_NAME` FROM `INFORMATION_SCHEMA`.`SCHEMATA`, " - . "(select DB_first_level from ( SELECT distinct " + . "(SELECT DB_first_level FROM ( SELECT DISTINCT " . "SUBSTRING_INDEX(SCHEMA_NAME, '_', 1) DB_first_level " . "FROM INFORMATION_SCHEMA.SCHEMATA WHERE TRUE ) t ORDER BY " - . "DB_first_level ASC LIMIT 0, 250) t2 where 1 = locate(" - . "concat(DB_first_level, '_'), concat(SCHEMA_NAME, '_')) " - . "order by SCHEMA_NAME ASC", + . "DB_first_level ASC LIMIT 0, 250) t2 WHERE 1 = LOCATE(" + . "CONCAT(DB_first_level, '_'), CONCAT(SCHEMA_NAME, '_')) " + . "ORDER BY SCHEMA_NAME ASC", 'result' => array( "test", ) ), array( - 'query' => "select COUNT(*) from ( SELECT distinct SUBSTRING_INDEX(" + 'query' => "SELECT COUNT(*) FROM ( SELECT DISTINCT SUBSTRING_INDEX(" . "SCHEMA_NAME, '_', 1) DB_first_level " . "FROM INFORMATION_SCHEMA.SCHEMATA WHERE TRUE ) t", 'result' => array( diff --git a/libraries/mysql_charsets.lib.php b/libraries/mysql_charsets.lib.php index b8a9a2ce4c..af48c264ee 100644 --- a/libraries/mysql_charsets.lib.php +++ b/libraries/mysql_charsets.lib.php @@ -114,14 +114,26 @@ function PMA_getDbCollation($db) return 'utf8_general_ci'; } - $sql = PMA_DRIZZLE - ? 'SELECT DEFAULT_COLLATION_NAME FROM data_dictionary.SCHEMAS' - . ' WHERE SCHEMA_NAME = \'' . PMA_Util::sqlAddSlashes($db) - . '\' LIMIT 1' - : 'SELECT DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA' - . ' WHERE SCHEMA_NAME = \'' . PMA_Util::sqlAddSlashes($db) - . '\' LIMIT 1'; - return $GLOBALS['dbi']->fetchValue($sql); + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + // this is slow with thousands of databases + $sql = PMA_DRIZZLE + ? 'SELECT DEFAULT_COLLATION_NAME FROM data_dictionary.SCHEMAS' + . ' WHERE SCHEMA_NAME = \'' . PMA_Util::sqlAddSlashes($db) + . '\' LIMIT 1' + : 'SELECT DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA' + . ' WHERE SCHEMA_NAME = \'' . PMA_Util::sqlAddSlashes($db) + . '\' LIMIT 1'; + return $GLOBALS['dbi']->fetchValue($sql); + } else { + $GLOBALS['dbi']->selectDb($db); + $return = $GLOBALS['dbi']->fetchValue( + 'SHOW VARIABLES LIKE \'collation_database\'', 0, 1 + ); + if ($db !== $GLOBALS['db']) { + $GLOBALS['dbi']->selectDb($GLOBALS['db']); + } + return $return; + } } /** diff --git a/libraries/navigation/Nodes/Node.class.php b/libraries/navigation/Nodes/Node.class.php index 56631f0dd0..e56536855b 100644 --- a/libraries/navigation/Nodes/Node.class.php +++ b/libraries/navigation/Nodes/Node.class.php @@ -359,27 +359,89 @@ class Node */ public function getData($type, $pos, $searchClause = '') { - $query = "SELECT `SCHEMA_NAME` "; - $query .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA`, "; - $query .= "("; - $query .= "select DB_first_level "; - $query .= "from ( "; - $query .= "SELECT distinct SUBSTRING_INDEX(SCHEMA_NAME, "; - $query .= "'{$GLOBALS['cfg']['NavigationTreeDbSeparator']}', 1) "; - $query .= "DB_first_level "; - $query .= "FROM INFORMATION_SCHEMA.SCHEMATA "; - $query .= $this->_getWhereClause($searchClause); - $query .= ") t "; - $query .= "ORDER BY DB_first_level ASC "; - $query .= "LIMIT $pos, {$GLOBALS['cfg']['FirstLevelNavigationItems']}"; - $query .= ") t2 "; - $query .= "where 1 = locate(concat(DB_first_level, "; - $query .= "'{$GLOBALS['cfg']['NavigationTreeDbSeparator']}'), "; - $query .= "concat(SCHEMA_NAME, "; - $query .= "'{$GLOBALS['cfg']['NavigationTreeDbSeparator']}')) "; - $query .= "order by SCHEMA_NAME ASC"; + $maxItems = $GLOBALS['cfg']['FirstLevelNavigationItems']; + if ($GLOBALS['cfg']['NavigationTreeEnableGrouping']) { + $dbSeperator = $GLOBALS['cfg']['NavigationTreeDbSeparator']; + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $query = "SELECT `SCHEMA_NAME` "; + $query .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA`, "; + $query .= "("; + $query .= "SELECT DB_first_level "; + $query .= "FROM ( "; + $query .= "SELECT DISTINCT SUBSTRING_INDEX(SCHEMA_NAME, "; + $query .= "'$dbSeperator', 1) "; + $query .= "DB_first_level "; + $query .= "FROM INFORMATION_SCHEMA.SCHEMATA "; + $query .= $this->_getWhereClause('SCHEMA_NAME', $searchClause); + $query .= ") t "; + $query .= "ORDER BY DB_first_level ASC "; + $query .= "LIMIT $pos, $maxItems"; + $query .= ") t2 "; + $query .= "WHERE 1 = LOCATE(CONCAT(DB_first_level, "; + $query .= "'$dbSeperator'), "; + $query .= "CONCAT(SCHEMA_NAME, "; + $query .= "'$dbSeperator')) "; + $query .= "ORDER BY SCHEMA_NAME ASC"; + $retval = $GLOBALS['dbi']->fetchResult($query); + } else { + $query = "SHOW DATABASES "; + $query .= $this->_getWhereClause('Database', $searchClause); + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle !== false) { + $prefixMap = array(); + $total = $pos + $maxItems; + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + $prefix = strstr($arr[0], $dbSeperator, true); + if ($prefix === false) { + $prefix = $arr[0]; + } + $prefixMap[$prefix] = 1; + if (sizeof($prefixMap) == $total) { + break; + } + } + $prefixes = array_slice(array_keys($prefixMap), $pos); + } - return $GLOBALS['dbi']->fetchResult($query); + $query = "SHOW DATABASES "; + $query .= $this->_getWhereClause('Database', ''); + $query .= " AND ("; + $subClauses = array(); + foreach ($prefixes as $prefix) { + $subClauses[] = " LOCATE('" + . PMA_Util::sqlAddSlashes($prefix) . $dbSeperator . "', " + . "CONCAT(`Database`, '" . $dbSeperator . "')) = 1 "; + } + $query .= implode("OR", $subClauses) . ")"; + $retval = $GLOBALS['dbi']->fetchResult($query); + } + } else { + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $query = "SELECT `SCHEMA_NAME` "; + $query .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA` "; + $query .= $this->_getWhereClause('SCHEMA_NAME', $searchClause); + $query .= "ORDER BY `SCHEMA_NAME` "; + $query .= "LIMIT $pos, $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + } else { + $retval = array(); + $query = "SHOW DATABASES "; + $query .= $this->_getWhereClause('Database', $searchClause); + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle !== false) { + $count = 0; + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr[0]; + $count++; + } + $pos--; + } + } + } + } + + return $retval; } /** @@ -394,15 +456,48 @@ class Node */ public function getPresence($type = '', $searchClause = '') { - $query = "select COUNT(*) "; - $query .= "from ( "; - $query .= "SELECT distinct SUBSTRING_INDEX(SCHEMA_NAME, "; - $query .= "'{$GLOBALS['cfg']['NavigationTreeDbSeparator']}', 1) "; - $query .= "DB_first_level "; - $query .= "FROM INFORMATION_SCHEMA.SCHEMATA "; - $query .= $this->_getWhereClause($searchClause); - $query .= ") t "; - $retval = (int)$GLOBALS['dbi']->fetchValue($query); + if ($GLOBALS['cfg']['NavigationTreeEnableGrouping']) { + $dbSeperator = $GLOBALS['cfg']['NavigationTreeDbSeparator']; + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $query = "SELECT COUNT(*) "; + $query .= "FROM ( "; + $query .= "SELECT DISTINCT SUBSTRING_INDEX(SCHEMA_NAME, "; + $query .= "'$dbSeperator', 1) "; + $query .= "DB_first_level "; + $query .= "FROM INFORMATION_SCHEMA.SCHEMATA "; + $query .= $this->_getWhereClause('SCHEMA_NAME', $searchClause); + $query .= ") t "; + $retval = (int)$GLOBALS['dbi']->fetchValue($query); + } else { + $query = "SHOW DATABASES "; + $query .= $this->_getWhereClause('Database', $searchClause); + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle !== false) { + $prefixMap = array(); + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + $prefix = strstr($arr[0], $dbSeperator, true); + if ($prefix === false) { + $prefix = $arr[0]; + } + $prefixMap[$prefix] = 1; + } + return count($prefixMap); + } + } + } else { + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $query = "SELECT COUNT(*) "; + $query .= "FROM INFORMATION_SCHEMA.SCHEMATA "; + $query .= $this->_getWhereClause('SCHEMA_NAME', $searchClause); + $retval = (int)$GLOBALS['dbi']->fetchValue($query); + } else { + $query = "SHOW DATABASES "; + $query .= $this->_getWhereClause('Database', $searchClause); + $retval = $GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); + } + } return $retval; } @@ -410,15 +505,16 @@ class Node * Returns the WHERE clause depending on the $searchClause parameter * and the hide_db directive * + * @param string $columnName Column name of the column having database names * @param string $searchClause A string used to filter the results of the query * * @return string */ - private function _getWhereClause($searchClause = '') + private function _getWhereClause($columnName, $searchClause = '') { $whereClause = "WHERE TRUE "; if (! empty($searchClause)) { - $whereClause .= "AND `SCHEMA_NAME` LIKE '%"; + $whereClause .= "AND " . PMA_Util::backquote($columnName) . " LIKE '%"; $whereClause .= PMA_Util::sqlAddSlashes( $searchClause, true ); @@ -426,8 +522,8 @@ class Node } if (! empty($GLOBALS['cfg']['Server']['hide_db'])) { - $whereClause .= "AND `SCHEMA_NAME` NOT REGEXP '" - . $GLOBALS['cfg']['Server']['hide_db'] . "' "; + $whereClause .= "AND " . PMA_Util::backquote($columnName) + . " NOT REGEXP '" . $GLOBALS['cfg']['Server']['hide_db'] . "' "; } if (! empty($GLOBALS['cfg']['Server']['only_db'])) { @@ -439,7 +535,7 @@ class Node $whereClause .= "AND ("; $subClauses = array(); foreach ($GLOBALS['cfg']['Server']['only_db'] as $each_only_db) { - $subClauses[] = " `SCHEMA_NAME` LIKE '" + $subClauses[] = " " . PMA_Util::backquote($columnName) . " LIKE '" . $each_only_db . "' "; } $whereClause .= implode("OR", $subClauses) . ")"; diff --git a/libraries/navigation/Nodes/Node_Database.class.php b/libraries/navigation/Nodes/Node_Database.class.php index e1e62cf0d0..6333481bb6 100644 --- a/libraries/navigation/Nodes/Node_Database.class.php +++ b/libraries/navigation/Nodes/Node_Database.class.php @@ -60,126 +60,143 @@ class Node_Database extends Node $db = $this->real_name; switch ($type) { case 'tables': - $db = PMA_Util::sqlAddSlashes($db); - $query = "SELECT COUNT(*) "; - $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; - $query .= "WHERE `TABLE_SCHEMA`='$db' "; - if (PMA_DRIZZLE) { - $query .= "AND `TABLE_TYPE`='BASE' "; - } else { - $query .= "AND `TABLE_TYPE`='BASE TABLE' "; - } - if (! empty($searchClause)) { - if ($singleItem) { - $query .= "AND `TABLE_NAME` = '"; - $query .= PMA_Util::sqlAddSlashes( - $searchClause, true - ); - $query .= "'"; + if (! $GLOBALS['cfg']['Server']['DisableIS'] || PMA_DRIZZLE) { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; + $query .= "WHERE `TABLE_SCHEMA`='$db' "; + if (PMA_DRIZZLE) { + $query .= "AND `TABLE_TYPE`='BASE' "; } else { - $query .= "AND `TABLE_NAME` LIKE '%"; - $query .= PMA_Util::sqlAddSlashes( - $searchClause, true - ); - $query .= "%'"; + $query .= "AND `TABLE_TYPE`='BASE TABLE' "; } + if (! empty($searchClause)) { + $query .= "AND " . $this->_getWhereClauseForSearch( + $searchClause, $singleItem, 'TABLE_NAME' + ); + } + $retval = (int)$GLOBALS['dbi']->fetchValue($query); + } else { + $query = "SHOW FULL TABLES FROM "; + $query .= PMA_Util::backquote($db); + $query .= " WHERE `Table_type`='BASE TABLE' "; + if (! empty($searchClause)) { + $query .= "AND " . $this->_getWhereClauseForSearch( + $searchClause, $singleItem, 'Tables_in_' . $db + ); + } + $retval = $GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); } - $retval = (int)$GLOBALS['dbi']->fetchValue($query); break; case 'views': - $db = PMA_Util::sqlAddSlashes($db); - $query = "SELECT COUNT(*) "; - $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; - $query .= "WHERE `TABLE_SCHEMA`='$db' "; - if (PMA_DRIZZLE) { - $query .= "AND `TABLE_TYPE`!='BASE' "; - } else { - $query .= "AND `TABLE_TYPE`!='BASE TABLE' "; - } - if (! empty($searchClause)) { - if ($singleItem) { - $query .= "AND `TABLE_NAME` = '"; - $query .= PMA_Util::sqlAddSlashes( - $searchClause, true - ); - $query .= "'"; + if (! $GLOBALS['cfg']['Server']['DisableIS'] || PMA_DRIZZLE) { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; + $query .= "WHERE `TABLE_SCHEMA`='$db' "; + if (PMA_DRIZZLE) { + $query .= "AND `TABLE_TYPE`!='BASE' "; } else { - $query .= "AND `TABLE_NAME` LIKE '%"; - $query .= PMA_Util::sqlAddSlashes( - $searchClause, true - ); - $query .= "%'"; + $query .= "AND `TABLE_TYPE`!='BASE TABLE' "; } + if (! empty($searchClause)) { + $query .= "AND " . $this->_getWhereClauseForSearch( + $searchClause, $singleItem, 'TABLE_NAME' + ); + } + $retval = (int)$GLOBALS['dbi']->fetchValue($query); + } else { + $query = "SHOW FULL TABLES FROM "; + $query .= PMA_Util::backquote($db); + $query .= " WHERE `Table_type`!='BASE TABLE' "; + if (! empty($searchClause)) { + $query .= "AND " . $this->_getWhereClauseForSearch( + $searchClause, $singleItem, 'Tables_in_' . $db + ); + } + $retval = $GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); } - $retval = (int)$GLOBALS['dbi']->fetchValue($query); break; case 'procedures': - $db = PMA_Util::sqlAddSlashes($db); - $query = "SELECT COUNT(*) "; - $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; - $query .= "WHERE `ROUTINE_SCHEMA`='$db'"; - $query .= "AND `ROUTINE_TYPE`='PROCEDURE' "; - if (! empty($searchClause)) { - if ($singleItem) { - $query .= "AND `ROUTINE_NAME` = '"; - $query .= PMA_Util::sqlAddSlashes( - $searchClause, true + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; + $query .= "WHERE `ROUTINE_SCHEMA`='$db'"; + $query .= "AND `ROUTINE_TYPE`='PROCEDURE' "; + if (! empty($searchClause)) { + $query .= "AND " . $this->_getWhereClauseForSearch( + $searchClause, $singleItem, 'ROUTINE_NAME' ); - $query .= "'"; - } else { - $query .= "AND `ROUTINE_NAME` LIKE '%"; - $query .= PMA_Util::sqlAddSlashes( - $searchClause, true - ); - $query .= "%'"; } + $retval = (int)$GLOBALS['dbi']->fetchValue($query); + } else { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SHOW PROCEDURE STATUS WHERE `Db`='$db' "; + if (! empty($searchClause)) { + $query .= "AND " . $this->_getWhereClauseForSearch( + $searchClause, $singleItem, 'Name' + ); + } + $retval = $GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); } - $retval = (int)$GLOBALS['dbi']->fetchValue($query); break; case 'functions': - $db = PMA_Util::sqlAddSlashes($db); - $query = "SELECT COUNT(*) "; - $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; - $query .= "WHERE `ROUTINE_SCHEMA`='$db' "; - $query .= "AND `ROUTINE_TYPE`='FUNCTION' "; - if (! empty($searchClause)) { - if ($singleItem) { - $query .= "AND `ROUTINE_NAME` = '"; - $query .= PMA_Util::sqlAddSlashes( - $searchClause, true + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; + $query .= "WHERE `ROUTINE_SCHEMA`='$db' "; + $query .= "AND `ROUTINE_TYPE`='FUNCTION' "; + if (! empty($searchClause)) { + $query .= "AND " . $this->_getWhereClauseForSearch( + $searchClause, $singleItem, 'ROUTINE_NAME' ); - $query .= "'"; - } else { - $query .= "AND `ROUTINE_NAME` LIKE '%"; - $query .= PMA_Util::sqlAddSlashes( - $searchClause, true - ); - $query .= "%'"; } + $retval = (int)$GLOBALS['dbi']->fetchValue($query); + } else { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SHOW FUNCTION STATUS WHERE `Db`='$db' "; + if (! empty($searchClause)) { + $query .= "AND " . $this->_getWhereClauseForSearch( + $searchClause, $singleItem, 'Name' + ); + } + $retval = $GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); } - $retval = (int)$GLOBALS['dbi']->fetchValue($query); break; case 'events': - $db = PMA_Util::sqlAddSlashes($db); - $query = "SELECT COUNT(*) "; - $query .= "FROM `INFORMATION_SCHEMA`.`EVENTS` "; - $query .= "WHERE `EVENT_SCHEMA`='$db' "; - if (! empty($searchClause)) { - if ($singleItem) { - $query .= "AND `EVENT_NAME` = '"; - $query .= PMA_Util::sqlAddSlashes( - $searchClause, true + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`EVENTS` "; + $query .= "WHERE `EVENT_SCHEMA`='$db' "; + if (! empty($searchClause)) { + $query .= "AND " . $this->_getWhereClauseForSearch( + $searchClause, $singleItem, 'EVENT_NAME' ); - $query .= "'"; - } else { - $query .= "AND `EVENT_NAME` LIKE '%"; - $query .= PMA_Util::sqlAddSlashes( - $searchClause, true - ); - $query .= "%'"; } + $retval = (int)$GLOBALS['dbi']->fetchValue($query); + } else { + $db = PMA_Util::backquote($db); + $query = "SHOW EVENTS FROM $db "; + if (! empty($searchClause)) { + $query .= "WHERE " . $this->_getWhereClauseForSearch( + $searchClause, $singleItem, 'Name' + ); + } + $retval = $GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); } - $retval = (int)$GLOBALS['dbi']->fetchValue($query); break; default: break; @@ -187,6 +204,29 @@ class Node_Database extends Node return $retval; } + /** + * Returns the WHERE clause for searching inside a database + * + * @param string $searchClause A string used to filter the results of the query + * @param string $singleItem Whether to get presence of a single known item + * @param string $columnName Name of the column in the result set to match + * + * @return string WHERE clause for searching + */ + private function _getWhereClauseForSearch( + $searchClause, $singleItem, $columnName + ) { + $query = ''; + if ($singleItem) { + $query .= PMA_Util::backquote($columnName) . " = "; + $query .= "'" . PMA_Util::sqlAddSlashes($searchClause) . "'"; + } else { + $query .= PMA_Util::backquote($columnName) . " LIKE "; + $query .= "'%" . PMA_Util::sqlAddSlashes($searchClause, true) . "%'"; + } + return $query; + } + /** * Returns the names of children of type $type present inside this container * This method is overridden by the Node_Database and Node_Table classes @@ -205,96 +245,217 @@ class Node_Database extends Node $db = $this->real_name; switch ($type) { case 'tables': - $escdDb = PMA_Util::sqlAddSlashes($db); - $query = "SELECT `TABLE_NAME` AS `name` "; - $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; - $query .= "WHERE `TABLE_SCHEMA`='$escdDb' "; - if (PMA_DRIZZLE) { - $query .= "AND `TABLE_TYPE`='BASE' "; + if (! $GLOBALS['cfg']['Server']['DisableIS'] || PMA_DRIZZLE) { + $escdDb = PMA_Util::sqlAddSlashes($db); + $query = "SELECT `TABLE_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; + $query .= "WHERE `TABLE_SCHEMA`='$escdDb' "; + if (PMA_DRIZZLE) { + $query .= "AND `TABLE_TYPE`='BASE' "; + } else { + $query .= "AND `TABLE_TYPE`='BASE TABLE' "; + } + if (! empty($searchClause)) { + $query .= "AND `TABLE_NAME` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $query .= "ORDER BY `TABLE_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); } else { - $query .= "AND `TABLE_TYPE`='BASE TABLE' "; + $query = " SHOW FULL TABLES FROM "; + $query .= PMA_Util::backquote($db); + $query .= " WHERE `Table_type`='BASE TABLE' "; + if (! empty($searchClause)) { + $query .= "AND " . PMA_Util::backquote( + "Tables_in_" . $db + ); + $query .= " LIKE '%" . PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle !== false) { + $count = 0; + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr[0]; + $count++; + } + $pos--; + } + } } - if (! empty($searchClause)) { - $query .= "AND `TABLE_NAME` LIKE '%"; - $query .= PMA_Util::sqlAddSlashes( - $searchClause, true - ); - $query .= "%'"; - } - $query .= "ORDER BY `TABLE_NAME` ASC "; - $query .= "LIMIT " . intval($pos) . ", $maxItems"; - $retval = $GLOBALS['dbi']->fetchResult($query); break; case 'views': - $escdDb = PMA_Util::sqlAddSlashes($db); - $query = "SELECT `TABLE_NAME` AS `name` "; - $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; - $query .= "WHERE `TABLE_SCHEMA`='$escdDb' "; - if (PMA_DRIZZLE) { - $query .= "AND `TABLE_TYPE`!='BASE' "; + if (! $GLOBALS['cfg']['Server']['DisableIS'] || PMA_DRIZZLE) { + $escdDb = PMA_Util::sqlAddSlashes($db); + $query = "SELECT `TABLE_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; + $query .= "WHERE `TABLE_SCHEMA`='$escdDb' "; + if (PMA_DRIZZLE) { + $query .= "AND `TABLE_TYPE`!='BASE' "; + } else { + $query .= "AND `TABLE_TYPE`!='BASE TABLE' "; + } + if (! empty($searchClause)) { + $query .= "AND `TABLE_NAME` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $query .= "ORDER BY `TABLE_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); } else { - $query .= "AND `TABLE_TYPE`!='BASE TABLE' "; + $query = "SHOW FULL TABLES FROM "; + $query .= PMA_Util::backquote($db); + $query .= " WHERE `Table_type`!='BASE TABLE' "; + if (! empty($searchClause)) { + $query .= "AND " . PMA_Util::backquote( + "Tables_in_" . $db + ); + $query .= " LIKE '%" . PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle !== false) { + $count = 0; + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr[0]; + $count++; + } + $pos--; + } + } } - if (! empty($searchClause)) { - $query .= "AND `TABLE_NAME` LIKE '%"; - $query .= PMA_Util::sqlAddSlashes( - $searchClause, true - ); - $query .= "%'"; - } - $query .= "ORDER BY `TABLE_NAME` ASC "; - $query .= "LIMIT " . intval($pos) . ", $maxItems"; - $retval = $GLOBALS['dbi']->fetchResult($query); break; case 'procedures': - $escdDb = PMA_Util::sqlAddSlashes($db); - $query = "SELECT `ROUTINE_NAME` AS `name` "; - $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; - $query .= "WHERE `ROUTINE_SCHEMA`='$escdDb'"; - $query .= "AND `ROUTINE_TYPE`='PROCEDURE' "; - if (! empty($searchClause)) { - $query .= "AND `ROUTINE_NAME` LIKE '%"; - $query .= PMA_Util::sqlAddSlashes( - $searchClause, true - ); - $query .= "%'"; + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $escdDb = PMA_Util::sqlAddSlashes($db); + $query = "SELECT `ROUTINE_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; + $query .= "WHERE `ROUTINE_SCHEMA`='$escdDb'"; + $query .= "AND `ROUTINE_TYPE`='PROCEDURE' "; + if (! empty($searchClause)) { + $query .= "AND `ROUTINE_NAME` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $query .= "ORDER BY `ROUTINE_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + } else { + $escdDb = PMA_Util::sqlAddSlashes($db); + $query = "SHOW PROCEDURE STATUS WHERE `Db`='$escdDb' "; + if (! empty($searchClause)) { + $query .= "AND `Name` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle !== false) { + $count = 0; + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr['Name']; + $count++; + } + $pos--; + } + } } - $query .= "ORDER BY `ROUTINE_NAME` ASC "; - $query .= "LIMIT " . intval($pos) . ", $maxItems"; - $retval = $GLOBALS['dbi']->fetchResult($query); break; case 'functions': - $escdDb = PMA_Util::sqlAddSlashes($db); - $query = "SELECT `ROUTINE_NAME` AS `name` "; - $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; - $query .= "WHERE `ROUTINE_SCHEMA`='$escdDb' "; - $query .= "AND `ROUTINE_TYPE`='FUNCTION' "; - if (! empty($searchClause)) { - $query .= "AND `ROUTINE_NAME` LIKE '%"; - $query .= PMA_Util::sqlAddSlashes( - $searchClause, true - ); - $query .= "%'"; + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $escdDb = PMA_Util::sqlAddSlashes($db); + $query = "SELECT `ROUTINE_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; + $query .= "WHERE `ROUTINE_SCHEMA`='$escdDb' "; + $query .= "AND `ROUTINE_TYPE`='FUNCTION' "; + if (! empty($searchClause)) { + $query .= "AND `ROUTINE_NAME` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $query .= "ORDER BY `ROUTINE_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + } else { + $escdDb = PMA_Util::sqlAddSlashes($db); + $query = "SHOW FUNCTION STATUS WHERE `Db`='$escdDb' "; + if (! empty($searchClause)) { + $query .= "AND `Name` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle !== false) { + $count = 0; + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr['Name']; + $count++; + } + $pos--; + } + } } - $query .= "ORDER BY `ROUTINE_NAME` ASC "; - $query .= "LIMIT " . intval($pos) . ", $maxItems"; - $retval = $GLOBALS['dbi']->fetchResult($query); break; case 'events': - $escdDb = PMA_Util::sqlAddSlashes($db); - $query = "SELECT `EVENT_NAME` AS `name` "; - $query .= "FROM `INFORMATION_SCHEMA`.`EVENTS` "; - $query .= "WHERE `EVENT_SCHEMA`='$escdDb' "; - if (! empty($searchClause)) { - $query .= "AND `EVENT_NAME` LIKE '%"; - $query .= PMA_Util::sqlAddSlashes( - $searchClause, true - ); - $query .= "%'"; + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $escdDb = PMA_Util::sqlAddSlashes($db); + $query = "SELECT `EVENT_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`EVENTS` "; + $query .= "WHERE `EVENT_SCHEMA`='$escdDb' "; + if (! empty($searchClause)) { + $query .= "AND `EVENT_NAME` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $query .= "ORDER BY `EVENT_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + } else { + $escdDb = PMA_Util::backquote($db); + $query = "SHOW EVENTS FROM $escdDb "; + if (! empty($searchClause)) { + $query .= "WHERE `Name` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle !== false) { + $count = 0; + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr['Name']; + $count++; + } + $pos--; + } + } } - $query .= "ORDER BY `EVENT_NAME` ASC "; - $query .= "LIMIT " . intval($pos) . ", $maxItems"; - $retval = $GLOBALS['dbi']->fetchResult($query); break; default: break; diff --git a/libraries/navigation/Nodes/Node_Table.class.php b/libraries/navigation/Nodes/Node_Table.class.php index a41e3a9a28..5297a8f4f3 100644 --- a/libraries/navigation/Nodes/Node_Table.class.php +++ b/libraries/navigation/Nodes/Node_Table.class.php @@ -77,13 +77,22 @@ class Node_Table extends Node_DatabaseChild $table = $this->real_name; switch ($type) { case 'columns': - $db = PMA_Util::sqlAddSlashes($db); - $table = PMA_Util::sqlAddSlashes($table); - $query = "SELECT COUNT(*) "; - $query .= "FROM `INFORMATION_SCHEMA`.`COLUMNS` "; - $query .= "WHERE `TABLE_NAME`='$table' "; - $query .= "AND `TABLE_SCHEMA`='$db'"; - $retval = (int)$GLOBALS['dbi']->fetchValue($query); + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $db = PMA_Util::sqlAddSlashes($db); + $table = PMA_Util::sqlAddSlashes($table); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`COLUMNS` "; + $query .= "WHERE `TABLE_NAME`='$table' "; + $query .= "AND `TABLE_SCHEMA`='$db'"; + $retval = (int)$GLOBALS['dbi']->fetchValue($query); + } else { + $db = PMA_Util::backquote($db); + $table = PMA_Util::backquote($table); + $query = "SHOW COLUMNS FROM $table FROM $db"; + $retval = (int)$GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); + } break; case 'indexes': $db = PMA_Util::backquote($db); @@ -94,13 +103,22 @@ class Node_Table extends Node_DatabaseChild ); break; case 'triggers': - $db = PMA_Util::sqlAddSlashes($db); - $table = PMA_Util::sqlAddSlashes($table); - $query = "SELECT COUNT(*) "; - $query .= "FROM `INFORMATION_SCHEMA`.`TRIGGERS` "; - $query .= "WHERE `EVENT_OBJECT_SCHEMA`='$db' "; - $query .= "AND `EVENT_OBJECT_TABLE`='$table'"; - $retval = (int)$GLOBALS['dbi']->fetchValue($query); + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $db = PMA_Util::sqlAddSlashes($db); + $table = PMA_Util::sqlAddSlashes($table); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`TRIGGERS` "; + $query .= "WHERE `EVENT_OBJECT_SCHEMA`='$db' "; + $query .= "AND `EVENT_OBJECT_TABLE`='$table'"; + $retval = (int)$GLOBALS['dbi']->fetchValue($query); + } else { + $db = PMA_Util::backquote($db); + $table = PMA_Util::sqlAddSlashes($table); + $query = "SHOW TRIGGERS FROM $db WHERE `Table` = '$table'"; + $retval = (int)$GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); + } break; default: break; @@ -127,15 +145,32 @@ class Node_Table extends Node_DatabaseChild $table = $this->real_name; switch ($type) { case 'columns': - $db = PMA_Util::sqlAddSlashes($db); - $table = PMA_Util::sqlAddSlashes($table); - $query = "SELECT `COLUMN_NAME` AS `name` "; - $query .= "FROM `INFORMATION_SCHEMA`.`COLUMNS` "; - $query .= "WHERE `TABLE_NAME`='$table' "; - $query .= "AND `TABLE_SCHEMA`='$db' "; - $query .= "ORDER BY `COLUMN_NAME` ASC "; - $query .= "LIMIT " . intval($pos) . ", $maxItems"; - $retval = $GLOBALS['dbi']->fetchResult($query); + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $db = PMA_Util::sqlAddSlashes($db); + $table = PMA_Util::sqlAddSlashes($table); + $query = "SELECT `COLUMN_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`COLUMNS` "; + $query .= "WHERE `TABLE_NAME`='$table' "; + $query .= "AND `TABLE_SCHEMA`='$db' "; + $query .= "ORDER BY `COLUMN_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + } else { + $db = PMA_Util::backquote($db); + $table = PMA_Util::backquote($table); + $query = "SHOW COLUMNS FROM $table FROM $db"; + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle !== false) { + $count = 0; + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr['Field']; + $count++; + } + $pos--; + } + } + } break; case 'indexes': $db = PMA_Util::backquote($db); @@ -157,15 +192,32 @@ class Node_Table extends Node_DatabaseChild } break; case 'triggers': - $db = PMA_Util::sqlAddSlashes($db); - $table = PMA_Util::sqlAddSlashes($table); - $query = "SELECT `TRIGGER_NAME` AS `name` "; - $query .= "FROM `INFORMATION_SCHEMA`.`TRIGGERS` "; - $query .= "WHERE `EVENT_OBJECT_SCHEMA`='$db' "; - $query .= "AND `EVENT_OBJECT_TABLE`='$table' "; - $query .= "ORDER BY `TRIGGER_NAME` ASC "; - $query .= "LIMIT " . intval($pos) . ", $maxItems"; - $retval = $GLOBALS['dbi']->fetchResult($query); + if (! $GLOBALS['cfg']['Server']['DisableIS']) { + $db = PMA_Util::sqlAddSlashes($db); + $table = PMA_Util::sqlAddSlashes($table); + $query = "SELECT `TRIGGER_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`TRIGGERS` "; + $query .= "WHERE `EVENT_OBJECT_SCHEMA`='$db' "; + $query .= "AND `EVENT_OBJECT_TABLE`='$table' "; + $query .= "ORDER BY `TRIGGER_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + } else { + $db = PMA_Util::backquote($db); + $table = PMA_Util::sqlAddSlashes($table); + $query = "SHOW TRIGGERS FROM $db WHERE `Table` = '$table'"; + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle !== false) { + $count = 0; + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr['Trigger']; + $count++; + } + $pos--; + } + } + } break; default: break; diff --git a/libraries/structure.lib.php b/libraries/structure.lib.php index 0f6553d26f..08f3a87eee 100644 --- a/libraries/structure.lib.php +++ b/libraries/structure.lib.php @@ -728,7 +728,10 @@ function PMA_getHtmlForNotNullEngineViewTable($table_is_view, $current_table, if (!($GLOBALS['cfg']['PropertiesNumColumns'] > 1)) { $html_output .= '' - . ($table_is_view ? __('View') : $current_table['ENGINE']) + . ( ! empty($current_table['ENGINE']) + ? $current_table['ENGINE'] + : ($table_is_view ? __('View') : '') + ) . ''; if ($GLOBALS['PMA_String']->strlen($collation)) { $html_output .= '' . $collation . ''; @@ -1131,15 +1134,7 @@ function PMA_getStuffForEngineTypeTable($current_table, $db_is_system_schema, case null : case 'SYSTEM VIEW' : case 'FunctionEngine' : - // if table is broken, Engine is reported as null, so one more test - if ($current_table['TABLE_TYPE'] == 'VIEW') { - // countRecords() takes care of $cfg['MaxExactCountViews'] - $current_table['TABLE_ROWS'] = PMA_Table::countRecords( - $GLOBALS['db'], $current_table['TABLE_NAME'], - true, true - ); - $table_is_view = true; - } + // possibly a view, do nothing break; default : // Unknown table type. @@ -1149,6 +1144,17 @@ function PMA_getStuffForEngineTypeTable($current_table, $db_is_system_schema, } } // end switch + if ($current_table['TABLE_TYPE'] == 'VIEW' + || $current_table['TABLE_TYPE'] == 'SYSTEM VIEW' + ) { + // countRecords() takes care of $cfg['MaxExactCountViews'] + $current_table['TABLE_ROWS'] = PMA_Table::countRecords( + $GLOBALS['db'], $current_table['TABLE_NAME'], + true, true + ); + $table_is_view = true; + } + return array($current_table, $formatted_size, $unit, $formatted_overhead, $overhead_unit, $overhead_size, $table_is_view, $sum_size ); @@ -3198,13 +3204,13 @@ function PMA_handleRealRowCountRequest() } /** - * Possibly show the table creation dialog + * Possibly show the table creation dialog * * @param string $db Current database name * @param bool $db_is_system_schema Whether this db is a system schema * @param PMA_Response $response PMA_Response instance * - * @return void + * @return void */ function PMA_possiblyShowCreateTableDialog($db, $db_is_system_schema, $response) { diff --git a/test/classes/PMA_Header_test.php b/test/classes/PMA_Header_test.php index cb7c8b63f9..7377b495ea 100644 --- a/test/classes/PMA_Header_test.php +++ b/test/classes/PMA_Header_test.php @@ -54,6 +54,7 @@ class PMA_Header_Test extends PHPUnit_Framework_TestCase $GLOBALS['table'] = 'table1'; $GLOBALS['PMA_Config'] = new PMA_Config(); $GLOBALS['PMA_Config']->enableBc(); + $GLOBALS['cfg']['Server']['DisableIS'] = false; $GLOBALS['cfg']['Server']['verbose'] = 'verbose host'; $GLOBALS['cfg']['Server']['pmadb'] = ''; $GLOBALS['cfg']['Server']['user'] = ''; diff --git a/test/classes/PMA_Menu_test.php b/test/classes/PMA_Menu_test.php index ab48f9f1b9..c2f1c4a129 100644 --- a/test/classes/PMA_Menu_test.php +++ b/test/classes/PMA_Menu_test.php @@ -39,6 +39,7 @@ class PMA_Menu_Test extends PHPUnit_Framework_TestCase if (!defined('PMA_IS_WINDOWS')) { define('PMA_IS_WINDOWS', false); } + $GLOBALS['cfg']['Server']['DisableIS'] = false; $GLOBALS['server'] = 0; $GLOBALS['cfg']['ServerDefault'] = 1; $GLOBALS['cfg']['Server']['verbose'] = 'verbose host'; diff --git a/test/classes/PMA_TableSearch_test.php b/test/classes/PMA_TableSearch_test.php index 2847dd1406..7be77b5746 100644 --- a/test/classes/PMA_TableSearch_test.php +++ b/test/classes/PMA_TableSearch_test.php @@ -54,6 +54,7 @@ class PMA_TableSearch_Test extends PHPUnit_Framework_TestCase $GLOBALS['cfg']['ServerDefault'] = 1; $GLOBALS['cfg']['maxRowPlotLimit'] = 500; + $GLOBALS['cfg']['Server']['DisableIS'] = false; $GLOBALS['cfg']['ServerDefault'] = 1; $GLOBALS['cfg']['ActionLinksMode'] = 'both'; $GLOBALS['cfg']['ForeignKeyMaxLimit'] = 100; diff --git a/test/classes/PMA_Table_test.php b/test/classes/PMA_Table_test.php index cfbb191974..2c2e29731f 100644 --- a/test/classes/PMA_Table_test.php +++ b/test/classes/PMA_Table_test.php @@ -38,6 +38,7 @@ class PMA_Table_Test extends PHPUnit_Framework_TestCase * SET these to avoid undefined index error */ $GLOBALS['server'] = 0; + $GLOBALS['cfg']['Server']['DisableIS'] = false; $GLOBALS['cfg']['ServerDefault'] = 1; $GLOBALS['cfg']['ActionLinksMode'] = 'both'; $GLOBALS['cfg']['MaxExactCount'] = 100; diff --git a/test/classes/navigation/PMA_NavigationTree_test.php b/test/classes/navigation/PMA_NavigationTree_test.php index 456513a6e7..71e727133d 100644 --- a/test/classes/navigation/PMA_NavigationTree_test.php +++ b/test/classes/navigation/PMA_NavigationTree_test.php @@ -11,6 +11,7 @@ * since 'check_user_privileges.lib.php' will use it globally */ $GLOBALS['server'] = 0; +$GLOBALS['cfg']['Server']['DisableIS'] = false; require_once 'libraries/Util.class.php'; require_once 'libraries/Theme.class.php'; @@ -51,6 +52,7 @@ class PMA_NavigationTreeTest extends PHPUnit_Framework_TestCase $GLOBALS['cfg']['Server']['host'] = 'localhost'; $GLOBALS['cfg']['Server']['user'] = 'root'; $GLOBALS['cfg']['Server']['pmadb'] = ''; + $GLOBALS['cfg']['Server']['DisableIS'] = false; $GLOBALS['pmaThemeImage'] = 'image'; $_SESSION['PMA_Theme'] = PMA_Theme::load('./themes/pmahomme'); diff --git a/test/classes/navigation/PMA_Node_test.php b/test/classes/navigation/PMA_Node_test.php index 7511b41529..225d1bef2a 100644 --- a/test/classes/navigation/PMA_Node_test.php +++ b/test/classes/navigation/PMA_Node_test.php @@ -26,6 +26,7 @@ class Node_Test extends PHPUnit_Framework_TestCase public function setup() { $GLOBALS['server'] = 0; + $GLOBALS['cfg']['Server']['DisableIS'] = false; $_SESSION['PMA_Theme'] = PMA_Theme::load('./themes/pmahomme'); } @@ -286,13 +287,13 @@ class Node_Test extends PHPUnit_Framework_TestCase // Vanilla case $node = PMA_NodeFactory::getInstance(); $this->assertEquals( - "WHERE TRUE ", $method->invoke($node) + "WHERE TRUE ", $method->invoke($node, 'SCHEMA_NAME') ); // When a schema names is passed as search clause $this->assertEquals( "WHERE TRUE AND `SCHEMA_NAME` LIKE '%schemaName%' ", - $method->invoke($node, 'schemaName') + $method->invoke($node, 'SCHEMA_NAME', 'schemaName') ); if (! isset($GLOBALS['cfg'])) { @@ -306,7 +307,7 @@ class Node_Test extends PHPUnit_Framework_TestCase $GLOBALS['cfg']['Server']['hide_db'] = 'regexpHideDb'; $this->assertEquals( "WHERE TRUE AND `SCHEMA_NAME` NOT REGEXP 'regexpHideDb' ", - $method->invoke($node) + $method->invoke($node, 'SCHEMA_NAME') ); unset($GLOBALS['cfg']['Server']['hide_db']); @@ -314,7 +315,7 @@ class Node_Test extends PHPUnit_Framework_TestCase $GLOBALS['cfg']['Server']['only_db'] = 'stringOnlyDb'; $this->assertEquals( "WHERE TRUE AND ( `SCHEMA_NAME` LIKE 'stringOnlyDb' )", - $method->invoke($node) + $method->invoke($node, 'SCHEMA_NAME') ); unset($GLOBALS['cfg']['Server']['only_db']); @@ -323,33 +324,36 @@ class Node_Test extends PHPUnit_Framework_TestCase $this->assertEquals( "WHERE TRUE AND ( `SCHEMA_NAME` LIKE 'onlyDbOne' " . "OR `SCHEMA_NAME` LIKE 'onlyDbTwo' )", - $method->invoke($node) + $method->invoke($node, 'SCHEMA_NAME') ); unset($GLOBALS['cfg']['Server']['only_db']); } /** - * Tests getData() method + * Tests getData() method when DisableIS is false and navigation tree + * grouping enabled. * * @return void * @test */ - public function testGetData() + public function testGetDataWithEnabledISAndGroupingEnabled() { $pos = 10; $limit = 20; if (! isset($GLOBALS['cfg'])) { $GLOBALS['cfg'] = array(); } + $GLOBALS['cfg']['Server']['DisableIS'] = false; + $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = true; $GLOBALS['cfg']['FirstLevelNavigationItems'] = $limit; $GLOBALS['cfg']['NavigationTreeDbSeparator'] = '_'; $expectedSql = "SELECT `SCHEMA_NAME` "; $expectedSql .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA`, "; $expectedSql .= "("; - $expectedSql .= "select DB_first_level "; - $expectedSql .= "from ( "; - $expectedSql .= "SELECT distinct SUBSTRING_INDEX(SCHEMA_NAME, "; + $expectedSql .= "SELECT DB_first_level "; + $expectedSql .= "FROM ( "; + $expectedSql .= "SELECT DISTINCT SUBSTRING_INDEX(SCHEMA_NAME, "; $expectedSql .= "'_', 1) "; $expectedSql .= "DB_first_level "; $expectedSql .= "FROM INFORMATION_SCHEMA.SCHEMATA "; @@ -358,9 +362,9 @@ class Node_Test extends PHPUnit_Framework_TestCase $expectedSql .= "ORDER BY DB_first_level ASC "; $expectedSql .= "LIMIT $pos, $limit"; $expectedSql .= ") t2 "; - $expectedSql .= "where 1 = locate(concat(DB_first_level, '_'), "; - $expectedSql .= "concat(SCHEMA_NAME, '_')) "; - $expectedSql .= "order by SCHEMA_NAME ASC"; + $expectedSql .= "WHERE 1 = LOCATE(CONCAT(DB_first_level, '_'), "; + $expectedSql .= "CONCAT(SCHEMA_NAME, '_')) "; + $expectedSql .= "ORDER BY SCHEMA_NAME ASC"; // It would have been better to mock _getWhereClause method // but stangely, mocking private methods is not supported in PHPUnit @@ -377,27 +381,118 @@ class Node_Test extends PHPUnit_Framework_TestCase } /** - * Tests the getPresence method + * Tests getData() method when DisableIS is false and navigation tree + * grouping disabled. * * @return void * @test */ - public function testGetPresence() + public function testGetDataWithEnabledISAndGroupingDisabled() { + $pos = 10; + $limit = 20; if (! isset($GLOBALS['cfg'])) { $GLOBALS['cfg'] = array(); } - if (! isset($GLOBALS['cfg']['Servers'])) { - $GLOBALS['cfg']['Servers'] = array(); - } - if (! isset($GLOBALS['cfg']['Servers'][0])) { - $GLOBALS['cfg']['Servers'][0] = array(); + $GLOBALS['cfg']['Server']['DisableIS'] = false; + $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = false; + $GLOBALS['cfg']['FirstLevelNavigationItems'] = $limit; + + $expectedSql = "SELECT `SCHEMA_NAME` "; + $expectedSql .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA` "; + $expectedSql .= "WHERE TRUE "; + $expectedSql .= "ORDER BY `SCHEMA_NAME` "; + $expectedSql .= "LIMIT $pos, $limit"; + + // It would have been better to mock _getWhereClause method + // but stangely, mocking private methods is not supported in PHPUnit + $node = PMA_NodeFactory::getInstance(); + + $dbi = $this->getMockBuilder('PMA_DatabaseInterface') + ->disableOriginalConstructor() + ->getMock(); + $dbi->expects($this->once()) + ->method('fetchResult') + ->with($expectedSql); + $GLOBALS['dbi'] = $dbi; + $node->getData('', $pos); + } + + /** + * Tests getData() method when DisableIS is true and navigation tree + * grouping enabled. + * + * @return void + * @test + */ + public function testGetDataWithDisabledISAndGroupingEnabled() + { + $pos = 0; + $limit = 10; + if (! isset($GLOBALS['cfg'])) { + $GLOBALS['cfg'] = array(); } + $GLOBALS['cfg']['Server']['DisableIS'] = true; + $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = true; + $GLOBALS['cfg']['FirstLevelNavigationItems'] = $limit; $GLOBALS['cfg']['NavigationTreeDbSeparator'] = '_'; - $query = "select COUNT(*) "; - $query .= "from ( "; - $query .= "SELECT distinct SUBSTRING_INDEX(SCHEMA_NAME, '_', 1) "; + $node = PMA_NodeFactory::getInstance(); + + $dbi = $this->getMockBuilder('PMA_DatabaseInterface') + ->disableOriginalConstructor() + ->getMock(); + $dbi->expects($this->once()) + ->method('tryQuery') + ->with("SHOW DATABASES WHERE TRUE AND `Database` LIKE '%db%' ") + ->will($this->returnValue(true)); + $dbi->expects($this->at(1)) + ->method('fetchArray') + ->will( + $this->returnValue( + array( + '0' => 'db' + ) + ) + ); + $dbi->expects($this->at(2)) + ->method('fetchArray') + ->will( + $this->returnValue( + array( + '0' => 'aa_db' + ) + ) + ); + $dbi->expects($this->at(3)) + ->method('fetchArray') + ->will($this->returnValue(false)); + $dbi->expects($this->once()) + ->method('fetchResult') + ->with("SHOW DATABASES WHERE TRUE AND (" + . " LOCATE('db_', CONCAT(`Database`, '_')) = 1" + . " OR LOCATE('aa_', CONCAT(`Database`, '_')) = 1 )" + ); + $GLOBALS['dbi'] = $dbi; + $node->getData('', $pos, 'db'); + } + + /** + * Tests the getPresence method when DisableIS is false and navigation tree + * grouping enabled. + * + * @return void + * @test + */ + public function testGetPresenceWithEnabledISAndGroupingEnabled() + { + $GLOBALS['cfg']['Server']['DisableIS'] = false; + $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = true; + $GLOBALS['cfg']['NavigationTreeDbSeparator'] = '_'; + + $query = "SELECT COUNT(*) "; + $query .= "FROM ( "; + $query .= "SELECT DISTINCT SUBSTRING_INDEX(SCHEMA_NAME, '_', 1) "; $query .= "DB_first_level "; $query .= "FROM INFORMATION_SCHEMA.SCHEMATA "; $query .= "WHERE TRUE "; @@ -416,5 +511,66 @@ class Node_Test extends PHPUnit_Framework_TestCase $GLOBALS['dbi'] = $dbi; $node->getPresence(); } + + /** + * Tests the getPresence method when DisableIS is false and navigation tree + * grouping disabled. + * + * @return void + * @test + */ + public function testGetPresenceWithEnabledISAndGroupingDisabled() + { + $GLOBALS['cfg']['Server']['DisableIS'] = false; + $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = false; + + $query = "SELECT COUNT(*) "; + $query .= "FROM INFORMATION_SCHEMA.SCHEMATA "; + $query .= "WHERE TRUE "; + + $node = PMA_NodeFactory::getInstance(); + $dbi = $this->getMockBuilder('PMA_DatabaseInterface') + ->disableOriginalConstructor() + ->getMock(); + $dbi->expects($this->once()) + ->method('fetchValue') + ->with($query); + $GLOBALS['dbi'] = $dbi; + $node->getPresence(); + } + + /** + * Tests the getPresence method when DisableIS is true + * + * @return void + * @test + */ + public function testGetPresenceWithDisabledIS() + { + $GLOBALS['cfg']['Server']['DisableIS'] = true; + $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = true; + + $node = PMA_NodeFactory::getInstance(); + + // test with no search clause + $dbi = $this->getMockBuilder('PMA_DatabaseInterface') + ->disableOriginalConstructor() + ->getMock(); + $dbi->expects($this->once()) + ->method('tryQuery') + ->with("SHOW DATABASES WHERE TRUE "); + $GLOBALS['dbi'] = $dbi; + $node->getPresence(); + + // test with a search clause + $dbi = $this->getMockBuilder('PMA_DatabaseInterface') + ->disableOriginalConstructor() + ->getMock(); + $dbi->expects($this->once()) + ->method('tryQuery') + ->with("SHOW DATABASES WHERE TRUE AND `Database` LIKE '%dbname%' "); + $GLOBALS['dbi'] = $dbi; + $node->getPresence('', 'dbname'); + } } ?> diff --git a/test/classes/plugin/export/PMA_ExportSql_test.php b/test/classes/plugin/export/PMA_ExportSql_test.php index 2eef7592bb..c843963d94 100644 --- a/test/classes/plugin/export/PMA_ExportSql_test.php +++ b/test/classes/plugin/export/PMA_ExportSql_test.php @@ -817,12 +817,18 @@ class PMA_ExportSql_Test extends PHPUnit_Framework_TestCase // case2: no backquotes unset($GLOBALS['sql_compatibility']); + $GLOBALS['cfg']['Server']['DisableIS'] = true; unset($GLOBALS['sql_backquotes']); $dbi = $this->getMockBuilder('PMA_DatabaseInterface') ->disableOriginalConstructor() ->getMock(); + $dbi->expects($this->once()) + ->method('fetchValue') + ->with('SHOW VARIABLES LIKE \'collation_database\'', 0, 1) + ->will($this->returnValue('testcollation')); + $GLOBALS['dbi'] = $dbi; ob_start(); @@ -837,7 +843,7 @@ class PMA_ExportSql_Test extends PHPUnit_Framework_TestCase ); $this->assertContains( - 'CREATE DATABASE IF NOT EXISTS db', + 'CREATE DATABASE IF NOT EXISTS db DEFAULT CHARACTER SET testcollation;', $result ); @@ -1230,6 +1236,7 @@ class PMA_ExportSql_Test extends PHPUnit_Framework_TestCase ->will($this->returnValue($row)); $GLOBALS['dbi'] = $dbi; + $GLOBALS['cfg']['Server']['DisableIS'] = false; $result = $this->object->getTableDef( 'db', 'table', "\n", "example.com/err", true, true, true @@ -1406,6 +1413,7 @@ class PMA_ExportSql_Test extends PHPUnit_Framework_TestCase ->will($this->returnValue($row)); $GLOBALS['dbi'] = $dbi; + $GLOBALS['cfg']['Server']['DisableIS'] = false; $result = $this->object->getTableDef( 'db', 'table', "\n", "example.com/err", true, true, true @@ -1523,6 +1531,7 @@ class PMA_ExportSql_Test extends PHPUnit_Framework_TestCase ->will($this->returnValue('error occurred')); $GLOBALS['dbi'] = $dbi; + $GLOBALS['cfg']['Server']['DisableIS'] = false; $result = $this->object->getTableDef( 'db', 'table', "\n", "example.com/err", true, true, true @@ -1873,6 +1882,7 @@ class PMA_ExportSql_Test extends PHPUnit_Framework_TestCase $GLOBALS['sql_truncate'] = true; $GLOBALS['sql_insert_syntax'] = 'both'; $GLOBALS['sql_hex_for_binary'] = true; + $GLOBALS['cfg']['Server']['DisableIS'] = false; ob_start(); $this->object->exportData( @@ -1988,6 +1998,7 @@ class PMA_ExportSql_Test extends PHPUnit_Framework_TestCase $GLOBALS['sql_truncate'] = true; $GLOBALS['sql_insert_syntax'] = 'both'; $GLOBALS['sql_hex_for_binary'] = true; + $GLOBALS['cfg']['Server']['DisableIS'] = false; ob_start(); $this->object->exportData( @@ -2020,6 +2031,7 @@ class PMA_ExportSql_Test extends PHPUnit_Framework_TestCase ->will($this->returnValue(true)); $GLOBALS['dbi'] = $dbi; + $GLOBALS['cfg']['Server']['DisableIS'] = false; $GLOBALS['sql_views_as_tables'] = false; $GLOBALS['sql_include_comments'] = true; $GLOBALS['crlf'] = "\n"; @@ -2057,6 +2069,7 @@ class PMA_ExportSql_Test extends PHPUnit_Framework_TestCase ->will($this->returnValue('err')); $GLOBALS['dbi'] = $dbi; + $GLOBALS['cfg']['Server']['DisableIS'] = false; $GLOBALS['sql_views_as_tables'] = true; $GLOBALS['sql_include_comments'] = true; $GLOBALS['crlf'] = "\n"; diff --git a/test/classes/plugin/export/PMA_ExportXml_test.php b/test/classes/plugin/export/PMA_ExportXml_test.php index 0aa3ddfee9..be041d946d 100644 --- a/test/classes/plugin/export/PMA_ExportXml_test.php +++ b/test/classes/plugin/export/PMA_ExportXml_test.php @@ -249,6 +249,7 @@ class PMA_ExportXml_Test extends PHPUnit_Framework_TestCase $GLOBALS['charset_of_file'] = 'iso-8859-1'; $GLOBALS['cfg']['Server']['port'] = 80; $GLOBALS['cfg']['Server']['host'] = 'localhost'; + $GLOBALS['cfg']['Server']['DisableIS'] = false; $GLOBALS['xml_export_tables'] = 1; $GLOBALS['xml_export_triggers'] = 1; $GLOBALS['xml_export_procedures'] = 1; @@ -494,6 +495,7 @@ class PMA_ExportXml_Test extends PHPUnit_Framework_TestCase $GLOBALS['xml_export_triggers'] = true; $GLOBALS['cfg']['Server']['port'] = 80; $GLOBALS['cfg']['Server']['host'] = 'localhost'; + $GLOBALS['cfg']['Server']['DisableIS'] = false; $GLOBALS['crlf'] = "\n"; $GLOBALS['db'] = 'dassertEquals( @@ -122,6 +123,12 @@ class PMA_MySQL_Charsets_Test extends PHPUnit_Framework_TestCase PMA_getDbCollation('pma_test') ); + $GLOBALS['cfg']['Server']['DisableIS'] = true; + $GLOBALS['db'] = 'pma_test2'; + $this->assertEquals( + 'bar', + PMA_getDbCollation('pma_test') + ); $this->assertNotEquals( 'pma_test', $GLOBALS['dummy_db'] diff --git a/test/libraries/PMA_server_collations_test.php b/test/libraries/PMA_server_collations_test.php index 5f27827e3e..9391e162a8 100644 --- a/test/libraries/PMA_server_collations_test.php +++ b/test/libraries/PMA_server_collations_test.php @@ -22,6 +22,9 @@ $GLOBALS['available_languages']= array( ); $GLOBALS['text_dir'] = "text_dir"; $GLOBALS['cfg']['DBG']['sql'] = false; +$GLOBALS['cfg']['Server'] = array( + 'DisableIS' => false +); //$_SESSION require_once 'libraries/Theme.class.php'; $_SESSION['PMA_Theme'] = PMA_Theme::load('./themes/pmahomme'); diff --git a/test/libraries/PMA_structure_test.php b/test/libraries/PMA_structure_test.php index 2206d5a73f..a44613577d 100644 --- a/test/libraries/PMA_structure_test.php +++ b/test/libraries/PMA_structure_test.php @@ -52,6 +52,7 @@ class PMA_Structure_Test extends PHPUnit_Framework_TestCase $GLOBALS['cfg']['ShowSQL'] = true; $GLOBALS['cfg']['TableNavigationLinksMode'] = 'icons'; $GLOBALS['cfg']['LimitChars'] = 100; + $GLOBALS['cfg']['Server']['DisableIS'] = false; $GLOBALS['table'] = "table"; $GLOBALS['pmaThemeImage'] = 'image'; diff --git a/test/libraries/common/PMA_showMessage_test_disabled.php b/test/libraries/common/PMA_showMessage_test_disabled.php index 769b3d7f50..d20b848c25 100644 --- a/test/libraries/common/PMA_showMessage_test_disabled.php +++ b/test/libraries/common/PMA_showMessage_test_disabled.php @@ -49,6 +49,7 @@ class PMA_ShowMessage_Test extends PHPUnit_Framework_TestCase global $cfg; $GLOBALS['is_ajax_request'] = true; + $cfg['Server']['DisableIS'] = false; $GLOBALS['table'] = 'tbl'; $GLOBALS['db'] = 'db';