/** * returns array of all tables in given db or dbs * this function expects unquoted names: * RIGHT: my_database * WRONG: `my_database` * WRONG: my\_database * if $tbl_is_group is true, $table is used as filter for table names * if $tbl_is_group is 'comment, $table is used as filter for table comments * * <code> * PMA_DBI_get_tables_full('my_database'); * PMA_DBI_get_tables_full('my_database', 'my_table')); * PMA_DBI_get_tables_full('my_database', 'my_tables_', true)); * PMA_DBI_get_tables_full('my_database', 'my_tables_', 'comment')); * </code> * * @param string $database database * @param string|bool $table table or false * @param boolean|string $tbl_is_group $table is a table group * @param mixed $link mysql link * @param integer $limit_offset zero-based offset for the count * @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) * * @todo move into PMA_Table * * @return array list of tables in given db(s) */ function PMA_DBI_get_tables_full($database, $table = false, $tbl_is_group = false, $link = null, $limit_offset = 0, $limit_count = false, $sort_by = 'Name', $sort_order = 'ASC') { if (true === $limit_count) { $limit_count = $GLOBALS['cfg']['MaxTableList']; } // prepare and check parameters if (!is_array($database)) { $databases = array($database); } else { $databases = $database; } $tables = array(); if (!$GLOBALS['cfg']['Server']['DisableIS']) { // get table information from information_schema if ($table) { if (true === $tbl_is_group) { $sql_where_table = 'AND t.`TABLE_NAME` LIKE \'' . PMA_escapeMysqlWildcards(PMA_sqlAddSlashes($table)) . '%\''; } elseif ('comment' === $tbl_is_group) { $sql_where_table = 'AND t.`TABLE_COMMENT` LIKE \'' . PMA_escapeMysqlWildcards(PMA_sqlAddSlashes($table)) . '%\''; } else { $sql_where_table = 'AND t.`TABLE_NAME` = \'' . PMA_sqlAddSlashes($table) . '\''; } } else { $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_sqlAddSlashes', $databases); if (PMA_DRIZZLE) { $engine_info = PMA_cacheGet('drizzle_engines', true); $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)"; } // data_dictionary.table_cache may not contain any data for some tables, it's just a table cache // auto_increment == 0 is cast to NULL because currently (2011.03.13 GA) Drizzle doesn't provide correct value $sql = "\n SELECT t.*,\n t.TABLE_SCHEMA AS `Db`,\n t.TABLE_NAME AS `Name`,\n t.TABLE_TYPE AS `TABLE_TYPE`,\n t.ENGINE AS `Engine`,\n t.ENGINE AS `Type`,\n t.TABLE_VERSION AS `Version`,-- VERSION\n t.ROW_FORMAT AS `Row_format`,\n coalesce(tc.ROWS, stat.NUM_ROWS)\n AS `Rows`,-- TABLE_ROWS,\n coalesce(tc.ROWS, stat.NUM_ROWS)\n AS `TABLE_ROWS`,\n tc.AVG_ROW_LENGTH AS `Avg_row_length`, -- AVG_ROW_LENGTH\n tc.TABLE_SIZE AS `Data_length`, -- DATA_LENGTH\n NULL AS `Max_data_length`, -- MAX_DATA_LENGTH\n NULL AS `Index_length`, -- INDEX_LENGTH\n NULL AS `Data_free`, -- DATA_FREE\n nullif(t.AUTO_INCREMENT, 0)\n AS `Auto_increment`,\n t.TABLE_CREATION_TIME AS `Create_time`, -- CREATE_TIME\n t.TABLE_UPDATE_TIME AS `Update_time`, -- UPDATE_TIME\n NULL AS `Check_time`, -- CHECK_TIME\n t.TABLE_COLLATION AS `Collation`,\n NULL AS `Checksum`, -- CHECKSUM\n NULL AS `Create_options`, -- CREATE_OPTIONS\n t.TABLE_COMMENT AS `Comment`\n FROM data_dictionary.TABLES t\n LEFT JOIN data_dictionary.TABLE_CACHE tc ON tc.TABLE_SCHEMA = t.TABLE_SCHEMA AND tc.TABLE_NAME = t.TABLE_NAME\n {$stats_join}\n WHERE t.TABLE_SCHEMA IN ('" . implode("', '", $this_databases) . "')\n " . $sql_where_table; } else { $sql = ' SELECT *, `TABLE_SCHEMA` AS `Db`, `TABLE_NAME` AS `Name`, `TABLE_TYPE` AS `TABLE_TYPE`, `ENGINE` AS `Engine`, `ENGINE` AS `Type`, `VERSION` AS `Version`, `ROW_FORMAT` AS `Row_format`, `TABLE_ROWS` AS `Rows`, `AVG_ROW_LENGTH` AS `Avg_row_length`, `DATA_LENGTH` AS `Data_length`, `MAX_DATA_LENGTH` AS `Max_data_length`, `INDEX_LENGTH` AS `Index_length`, `DATA_FREE` AS `Data_free`, `AUTO_INCREMENT` AS `Auto_increment`, `CREATE_TIME` AS `Create_time`, `UPDATE_TIME` AS `Update_time`, `CHECK_TIME` AS `Check_time`, `TABLE_COLLATION` AS `Collation`, `CHECKSUM` AS `Checksum`, `CREATE_OPTIONS` AS `Create_options`, `TABLE_COMMENT` AS `Comment` FROM `information_schema`.`TABLES` t WHERE ' . (PMA_IS_WINDOWS ? '' : 'BINARY') . ' `TABLE_SCHEMA` IN (\'' . implode("', '", $this_databases) . '\') ' . $sql_where_table; } // Sort the tables $sql .= " ORDER BY {$sort_by} {$sort_order}"; if ($limit_count) { $sql .= ' LIMIT ' . $limit_count . ' OFFSET ' . $limit_offset; } $tables = PMA_DBI_fetch_result($sql, array('TABLE_SCHEMA', 'TABLE_NAME'), null, $link); unset($sql_where_table, $sql); 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 ($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; } } } // 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) { $sql = 'SHOW TABLE STATUS FROM ' . PMA_backquote($each_database) . ' LIKE \'' . PMA_escapeMysqlWildcards(PMA_sqlAddSlashes($table, true)) . '%\''; } else { $sql = 'SHOW TABLE STATUS FROM ' . PMA_backquote($each_database); } $each_tables = PMA_DBI_fetch_result($sql, 'Name', null, $link); // 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 ('comment' === $tbl_is_group && 0 === strpos($each_table['Comment'], $table)) { // remove table from list unset($each_tables[$table_name]); continue; } 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 $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'; } 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 // Note: I don't see why we would need array_merge_recursive() here, // as it creates double entries for the same table (for example a double // 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 foreach ($tables as $one_database => $its_tables) { if (isset(PMA_Table::$cache[$one_database])) { PMA_Table::$cache[$one_database] = PMA_Table::$cache[$one_database] + $tables[$one_database]; } else { PMA_Table::$cache[$one_database] = $tables[$one_database]; } } unset($one_database, $its_tables); 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 #1436171 // http://sf.net/support/tracker.php?aid=1436171 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 { return $tables; } }
/** * PMA_escapeMysqlWildcards tests * @dataProvider escapeDataProvider */ public function testEscape($a, $b) { $this->assertEquals($a, PMA_escapeMysqlWildcards($b)); }
} $user_form .= ' <tr class="noclick ' . ($odd_row ? 'odd' : 'even') . '">' . "\n" . ' <td'; if (count($current_privileges) > 1) { $user_form .= ' rowspan="' . count($current_privileges) . '"'; } $user_form .= '>' . (empty($current_user) ? '<span style="color: #FF0000">' . __('Any') . '</span>' : htmlspecialchars($current_user)) . "\n" . ' </td>' . "\n" . ' <td'; if (count($current_privileges) > 1) { $user_form .= ' rowspan="' . count($current_privileges) . '"'; } $user_form .= '>' . htmlspecialchars($current_host) . '</td>' . "\n"; for ($i = 0; $i < count($current_privileges); $i++) { $current = $current_privileges[$i]; $user_form .= ' <td>' . "\n" . ' '; if (!isset($current['Db']) || $current['Db'] == '*') { $user_form .= __('global'); } elseif ($current['Db'] == PMA_escapeMysqlWildcards($checkprivs)) { $user_form .= __('database-specific'); } else { $user_form .= __('wildcard') . ': <code>' . htmlspecialchars($current['Db']) . '</code>'; } $user_form .= "\n" . ' </td>' . "\n" . ' <td>' . "\n" . ' <code>' . "\n" . ' ' . join(',' . "\n" . ' ', PMA_extractPrivInfo($current, true)) . "\n" . ' </code>' . "\n" . ' </td>' . "\n" . ' <td>' . "\n" . ' ' . ($current['Grant_priv'] == 'Y' ? __('Yes') : __('No')) . "\n" . ' </td>' . "\n" . ' <td>' . "\n"; $user_form .= sprintf($link_edit, urlencode($current_user), urlencode($current_host), urlencode(!isset($current['Db']) || $current['Db'] == '*' ? '' : $current['Db']), ''); $user_form .= '</td>' . "\n" . ' </tr>' . "\n"; if ($i + 1 < count($current_privileges)) { $user_form .= '<tr class="noclick ' . ($odd_row ? 'odd' : 'even') . '">' . "\n"; } } if (empty($row) && empty($row1) && empty($row2)) { break; } $odd_row = !$odd_row;
/** * @global bool whether selected db is information_schema */ $db_is_information_schema = false; if (PMA_is_system_schema($db)) { $is_show_stats = false; $db_is_information_schema = true; } /** * @global array information about tables in db */ $tables = array(); // When used in Nested table group mode, // only show tables matching the given groupname if (PMA_isValid($tbl_group) && !$cfg['ShowTooltipAliasTB']) { $tbl_group_sql = ' LIKE "' . PMA_escapeMysqlWildcards($tbl_group) . '%"'; } else { $tbl_group_sql = ''; } if ($cfg['ShowTooltip']) { $tooltip_truename = array(); $tooltip_aliasname = array(); } // Special speedup for newer MySQL Versions (in 4.0 format changed) if (true === $cfg['SkipLockedTables']) { $db_info_result = PMA_DBI_query('SHOW OPEN TABLES FROM ' . PMA_backquote($db) . ';'); // Blending out tables in use if ($db_info_result && PMA_DBI_num_rows($db_info_result) > 0) { while ($tmp = PMA_DBI_fetch_row($db_info_result)) { // if in use memorize tablename if (preg_match('@in_use=[1-9]+@i', $tmp[1])) {