From ec4549f9945a9b224cfa7f74a38c2c916afc702e Mon Sep 17 00:00:00 2001 From: Marc Delisle Date: Mon, 15 Dec 2008 17:27:43 +0000 Subject: [PATCH] patch #2356575 [display] Sortable database columns --- ChangeLog | 2 + db_structure.php | 76 +++++++++++++++++++++++++--- libraries/database_interface.lib.php | 65 +++++++++++++++++++++--- libraries/db_info.inc.php | 31 ++++++++++-- 4 files changed, 155 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index b528a6978..85d7ecf44 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,8 @@ $HeadURL: https://phpmyadmin.svn.sourceforge.net/svnroot/phpmyadmin/trunk/phpMyA + rfe #1821619 LeftFrameDBSeparator can be an array + patch #1821619 [privileges] Extra back reference when editing table-specific privileges, thanks to Herman van Rink - helmo ++ patch #2356575 [display] Sortable database columns, + thanks to Bryce Thornton - brycethornton 3.1.2.0 (not yet released) - bug #1253252 [display] Can't NULL a column with relation defined diff --git a/db_structure.php b/db_structure.php index 23fe15d15..1c3a40f15 100644 --- a/db_structure.php +++ b/db_structure.php @@ -77,6 +77,7 @@ $db_collation = PMA_getDbCollation($db); * @uses $GLOBALS['strSize'] * @uses $GLOBALS['strOverhead'] * @uses $GLOBALS['structure_tbl_col_cnt'] + * @uses PMA_SortableTableHeader() * @param boolean $db_is_information_schema */ function PMA_TableHeader($db_is_information_schema = false) @@ -92,22 +93,22 @@ function PMA_TableHeader($db_is_information_schema = false) echo '' . "\n" .'' . "\n" .'' . "\n" - .' ' . "\n" + .' ' . "\n" .' ' - .' ' . "\n"; if (!($GLOBALS['cfg']['PropertiesNumColumns'] > 1)) { - echo ' ' . "\n"; + echo ' ' . "\n"; $cnt++; - echo ' ' . "\n"; + echo ' ' . "\n"; $cnt++; } if ($GLOBALS['is_show_stats']) { - echo ' ' . "\n" - . ' ' . "\n"; + echo ' ' . "\n" + . ' ' . "\n"; $cnt += 2; } echo '' . "\n"; @@ -116,6 +117,59 @@ function PMA_TableHeader($db_is_information_schema = false) $GLOBALS['structure_tbl_col_cnt'] = $cnt + $action_colspan + 3; } // end function PMA_TableHeader() + +/** + * Creates a clickable column header for table information + * + * @param string title to use for the link + * @param string corresponds to sortable data name mapped in libraries/db_info.inc.php + * @returns string link to be displayed in the table header + */ +function PMA_SortableTableHeader($title, $sort) +{ + // Set some defaults + $requested_sort = 'table'; + $requested_sort_order = 'ASC'; + $sort_order = 'ASC'; + + // If the user requested a sort + if (isset($_REQUEST['sort'])) { + $requested_sort = $_REQUEST['sort']; + + if (isset($_REQUEST['sort_order'])) { + $requested_sort_order = $_REQUEST['sort_order']; + } + } + + $order_img = ''; + $order_link_params = array(); + $order_link_params['title'] = $GLOBALS['strSort']; + + // If this column was requested to be sorted. + if ($requested_sort == $sort) { + if ($requested_sort_order == 'ASC') { + $sort_order = 'DESC'; + $order_img = ' '. $GLOBALS['strDescending'] . ''; + $order_link_params['onmouseover'] = 'if(document.getElementById(\'soimg' . $i . '\')){ document.getElementById(\'soimg' . $i . '\').src=\'' . $GLOBALS['pmaThemeImage'] . 's_asc.png\'; }'; + $order_link_params['onmouseout'] = 'if(document.getElementById(\'soimg' . $i . '\')){ document.getElementById(\'soimg' . $i . '\').src=\'' . $GLOBALS['pmaThemeImage'] . 's_desc.png\'; }'; + } else { + $order_img = ' '. $GLOBALS['strAscending'] . ''; + $order_link_params['onmouseover'] = 'if(document.getElementById(\'soimg' . $i . '\')){ document.getElementById(\'soimg' . $i . '\').src=\'' . $GLOBALS['pmaThemeImage'] . 's_desc.png\'; }'; + $order_link_params['onmouseout'] = 'if(document.getElementById(\'soimg' . $i . '\')){ document.getElementById(\'soimg' . $i . '\').src=\'' . $GLOBALS['pmaThemeImage'] . 's_asc.png\'; }'; + } + } + + $_url_params = array( + 'db' => $_REQUEST['db'], + ); + + $url = 'db_structure.php'.PMA_generate_common_url($_url_params); + // We set the position back to 0 every time they sort. + $url .= "&pos=0&sort=$sort&sort_order=$sort_order"; + + return PMA_linkOrButton($url, $title . $order_img, $order_link_params); +} + $titles = array(); if (true == $cfg['PropertiesIconic']) { $titles['Browse'] = '' . $strBrowse . ''; @@ -160,11 +214,19 @@ if (true == $cfg['PropertiesIconic']) { /** * Displays the tables list */ - $_url_params = array( 'pos' => $pos, 'db' => $db); +// Add the sort options if they exists +if ($_REQUEST['sort']) { + $_url_params['sort'] = $_REQUEST['sort']; +} + +if ($_REQUEST['sort_order']) { + $_url_params['sort_order'] = $_REQUEST['sort_order']; +} + PMA_listNavigator($total_num_tables, $pos, $_url_params, 'db_structure.php', 'frame_content', $GLOBALS['cfg']['MaxTableList']); ?> diff --git a/libraries/database_interface.lib.php b/libraries/database_interface.lib.php index 38497516a..fabc19ac3 100644 --- a/libraries/database_interface.lib.php +++ b/libraries/database_interface.lib.php @@ -241,10 +241,12 @@ function PMA_usort_comparison_callback($a, $b) * @param resource $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) * @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) +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') { require_once './libraries/Table.class.php'; @@ -311,9 +313,37 @@ function PMA_DBI_get_tables_full($database, $table = false, WHERE ' . (PMA_IS_WINDOWS ? '' : 'BINARY') . ' `TABLE_SCHEMA` IN (\'' . implode("', '", $this_databases) . '\') ' . $sql_where_table; + // Sort the tables + if ($sort_by == 'Name' && $GLOBALS['cfg']['NaturalOrder']) { + // This crazy bit of SQL was inspired by a post here: + // http://forums.mysql.com/read.php?10,34908,35959#msg-35959 + + // Find the longest table name + $max_name_sql = "SELECT MAX(LENGTH(TABLE_NAME)) FROM `information_schema`.`TABLES` + WHERE `TABLE_SCHEMA` IN ('" . implode("', '", $this_databases) . "')"; + $max_name_array = PMA_DBI_fetch_result($max_name_sql); + $max_name_length = $max_name_array[0]; + + // Put the CASE statement SQL together. + $sql_case = ''; + for ($i = 1; $i < $max_name_length; $i++) { + $sql_case .= " when substr(Name, $i) between '0' and '9' then $i"; + } + $sql_case .= " ELSE $max_name_length end) "; + + // Add the CASE statement to the main SQL + $sql .= " ORDER BY left(Name, (CASE "; + $sql .= $sql_case . "-1) $sort_order, 0+substr(Name, CASE"; + $sql .= $sql_case . $sort_order; + } else { + // Just let MySQL sort as it normally does + $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); @@ -335,6 +365,31 @@ function PMA_DBI_get_tables_full($database, $table = false, $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 + 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); } @@ -396,12 +451,6 @@ function PMA_DBI_get_tables_full($database, $table = false, } } - if ($GLOBALS['cfg']['NaturalOrder']) { - foreach ($tables as $key => $val) { - uksort($tables[$key], 'strnatcasecmp'); - } - } - // cache table data // so PMA_Table does not require to issue SHOW TABLE STATUS again PMA_Table::$cache = array_merge_recursive(PMA_Table::$cache, $tables); diff --git a/libraries/db_info.inc.php b/libraries/db_info.inc.php index 467f1d162..161386abd 100644 --- a/libraries/db_info.inc.php +++ b/libraries/db_info.inc.php @@ -197,13 +197,36 @@ if (true === $cfg['SkipLockedTables']) { } if (! isset($sot_ready)) { + + // Set some sorting defaults + $sort = 'name'; + $sort_order = 'ASC'; + + if ($_REQUEST['sort']) { + $sortable_name_mappings = array( + 'table' => 'Name', + 'records' => 'Rows', + 'type' => 'Engine', + 'collation' => 'Collation', + 'size' => 'Data_length', + 'overhead' => 'Data_free' + ); + + // Make sure the sort type is implemented + if ($sort = $sortable_name_mappings[$_REQUEST['sort']]) { + if ($_REQUEST['sort_order'] == 'DESC') { + $sort_order = 'DESC'; + } + } + } + if (! empty($tbl_group) && ! $cfg['ShowTooltipAliasTB']) { // only tables for selected group - $tables = PMA_DBI_get_tables_full($db, $tbl_group, true); + $tables = PMA_DBI_get_tables_full($db, $tbl_group, true, null, 0, false, $sort, $sort_order); } elseif (! empty($tbl_group) && $cfg['ShowTooltipAliasTB']) { // only tables for selected group, // but grouping is done on comment ... - $tables = PMA_DBI_get_tables_full($db, $tbl_group, 'comment'); + $tables = PMA_DBI_get_tables_full($db, $tbl_group, 'comment', null, 0, false, $sort, $sort_order); } else { // all tables in db // - get the total number of tables @@ -218,10 +241,10 @@ if (! isset($sot_ready)) { * * @todo Page selector for table names? */ - $tables = PMA_DBI_get_tables_full($db, false, false, null, 0, false); + $tables = PMA_DBI_get_tables_full($db, false, false, null, 0, false, $sort, $sort_order); } else { // fetch the details for a possible limited subset - $tables = PMA_DBI_get_tables_full($db, false, false, null, $pos, true); + $tables = PMA_DBI_get_tables_full($db, false, false, null, $pos, true, $sort, $sort_order); } }
' . $GLOBALS['strTable'] . '' . PMA_SortableTableHeader($GLOBALS['strTable'], 'table') . '' . "\n" .' ' . $GLOBALS['strAction'] . "\n" .' ' . $GLOBALS['strRecords'] + .' ' . PMA_SortableTableHeader($GLOBALS['strRecords'], 'records') .PMA_showHint(PMA_sanitize($GLOBALS['strApproximateCount'])) . "\n" .' ' . $GLOBALS['strType'] . '' . PMA_SortableTableHeader($GLOBALS['strType'], 'type') . '' . $GLOBALS['strCollation'] . '' . PMA_SortableTableHeader($GLOBALS['strCollation'], 'collation') . '' . $GLOBALS['strSize'] . '' . $GLOBALS['strOverhead'] . '' . PMA_SortableTableHeader($GLOBALS['strSize'], 'size') . '' . PMA_SortableTableHeader($GLOBALS['strOverhead'], 'overhead') . '