From d5acfed0e8dd0932bdbf46404ddd9daf7d7f9c74 Mon Sep 17 00:00:00 2001 From: Chanaka Indrajith Date: Fri, 20 Jul 2012 23:13:04 +0530 Subject: [PATCH 1/6] Multiple results support for SQL executions --- import.php | 6 +- libraries/database_interface.lib.php | 23 ++ libraries/dbi/mysqli.dbi.lib.php | 13 + libraries/import.lib.php | 28 ++- libraries/plugins/import/ImportSql.class.php | 12 +- sql.php | 248 ++++++++++++++++--- 6 files changed, 276 insertions(+), 54 deletions(-) diff --git a/import.php b/import.php index a558144242..193a4260f1 100644 --- a/import.php +++ b/import.php @@ -430,6 +430,10 @@ if (! $error && isset($skip)) { unset($skip); } +// This array contain the data like numberof valid sql queries in the statement +// and complete valid sql statement (which affected for rows) +$sql_data = array('valid_sql' => array(), 'valid_queries' => 0); + if (! $error) { // Check for file existance require_once("libraries/plugin_interface.lib.php"); @@ -445,7 +449,7 @@ if (! $error) { ); } else { // Do the real import - $import_plugin->doImport(); + $import_plugin->doImport($sql_data); } } diff --git a/libraries/database_interface.lib.php b/libraries/database_interface.lib.php index 3c26c03e99..c3b17d1e3c 100644 --- a/libraries/database_interface.lib.php +++ b/libraries/database_interface.lib.php @@ -177,6 +177,29 @@ function PMA_DBI_try_query($query, $link = null, $options = 0, return $r; } +/** + * Run multi query statement and return results + * + * @param string $multi_query multi query statement to execute + * @param mysqli $link mysqli object + * + * @return mysqli_result collection | boolean(false) + */ +function PMA_DBI_try_multi_query($multi_query = '', $link = null) +{ + + if (empty($link)) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + + return mysqli_multi_query($link, $multi_query); + +} + /** * converts charset of a mysql message, usually coming from mysql_error(), * into PMA charset, usally UTF-8 diff --git a/libraries/dbi/mysqli.dbi.lib.php b/libraries/dbi/mysqli.dbi.lib.php index 316796c36c..dc246957d3 100644 --- a/libraries/dbi/mysqli.dbi.lib.php +++ b/libraries/dbi/mysqli.dbi.lib.php @@ -253,6 +253,19 @@ function PMA_DBI_real_query($query, $link, $options) return mysqli_query($link, $query, $method); } +/** + * Run the multi query and output the results + * + * @param mysqli $link mysqli object + * @param string $query multi query statement to execute + * + * @return mysqli_result collection | boolean(false) + */ +function PMA_DBI_real_muli_query($link, $query) +{ + return mysqli_multi_query($link, $query); +} + /** * returns array of rows with associative and numeric keys from $result * diff --git a/libraries/import.lib.php b/libraries/import.lib.php index 0160f0bee9..1db15025b0 100644 --- a/libraries/import.lib.php +++ b/libraries/import.lib.php @@ -81,7 +81,7 @@ function PMA_detectCompression($filepath) * @return void * @access public */ -function PMA_importRunQuery($sql = '', $full = '', $controluser = false) +function PMA_importRunQuery($sql = '', $full = '', $controluser = false, &$sql_data = array()) { global $import_run_buffer, $go_sql, $complete_query, $display_query, $sql_query, $my_die, $error, $reload, @@ -108,7 +108,17 @@ function PMA_importRunQuery($sql = '', $full = '', $controluser = false) $GLOBALS['message'] = PMA_Message::error(__('"DROP DATABASE" statements are disabled.')); $error = true; } else { + $executed_queries++; + + if ($controluser) { + $result = PMA_queryAsControlUser( + $import_run_buffer['sql'] + ); + } else { + $result = PMA_DBI_try_query($import_run_buffer['sql']); + } + if ($run_query && $GLOBALS['finished'] && empty($sql) @@ -126,6 +136,12 @@ function PMA_importRunQuery($sql = '', $full = '', $controluser = false) $display_query = ''; } $sql_query = $import_run_buffer['sql']; + + if ($result !== false) { + $sql_data['valid_sql'][] = $import_run_buffer['full']; + $sql_data['valid_queries']++; + } + // If a 'USE ' SQL-clause was found, // set our current $db to the new one list($db, $reload) = PMA_lookForUse( @@ -134,13 +150,7 @@ function PMA_importRunQuery($sql = '', $full = '', $controluser = false) $reload ); } elseif ($run_query) { - if ($controluser) { - $result = PMA_queryAsControlUser( - $import_run_buffer['sql'] - ); - } else { - $result = PMA_DBI_try_query($import_run_buffer['sql']); - } + $msg = '# '; if ($result === false) { // execution failed if (! isset($my_die)) { @@ -163,6 +173,8 @@ function PMA_importRunQuery($sql = '', $full = '', $controluser = false) if ($a_num_rows > 0) { $msg .= __('Rows'). ': ' . $a_num_rows; $last_query_with_results = $import_run_buffer['sql']; + $sql_data['valid_sql'][] = $import_run_buffer['sql']; + $sql_data['valid_queries']++; } elseif ($a_aff_rows > 0) { $message = PMA_Message::affected_rows($a_aff_rows); $msg .= $message->getMessage(); diff --git a/libraries/plugins/import/ImportSql.class.php b/libraries/plugins/import/ImportSql.class.php index d25ea2396e..d25c71139a 100644 --- a/libraries/plugins/import/ImportSql.class.php +++ b/libraries/plugins/import/ImportSql.class.php @@ -93,10 +93,12 @@ class ImportSql extends ImportPlugin /** * Handles the whole import logic + * + * @param &$sql_data array 2-element array with sql data * * @return void */ - public function doImport() + public function doImport(&$sql_data = array()) { global $error, $timeout_passed; @@ -384,7 +386,9 @@ class ImportSql extends ImportPlugin $sql = $tmp_sql; PMA_importRunQuery( $sql, - substr($buffer, 0, $i + strlen($sql_delimiter)) + substr($buffer, 0, $i + strlen($sql_delimiter)), + false, + $sql_data ); $buffer = substr($buffer, $i + strlen($sql_delimiter)); // Reset parser: @@ -408,7 +412,7 @@ class ImportSql extends ImportPlugin } // End of parser loop } // End of import loop // Commit any possible data in buffers - PMA_importRunQuery('', substr($buffer, 0, $len)); - PMA_importRunQuery(); + PMA_importRunQuery('', substr($buffer, 0, $len), false, $sql_data); + PMA_importRunQuery('', '', false, $sql_data); } } \ No newline at end of file diff --git a/sql.php b/sql.php index 65a50cf440..27df11e36b 100644 --- a/sql.php +++ b/sql.php @@ -464,32 +464,11 @@ if (empty($reload) * @todo detect all this with the parser, to avoid problems finding * those strings in comments or backquoted identifiers */ - -$is_explain = $is_count = $is_export = $is_delete = $is_insert = $is_affected = $is_show = $is_maint = $is_analyse = $is_group = $is_func = $is_replace = false; -if ($is_select) { // see line 141 - $is_group = preg_match('@(GROUP[[:space:]]+BY|HAVING|SELECT[[:space:]]+DISTINCT)[[:space:]]+@i', $sql_query); - $is_func = ! $is_group && (preg_match('@[[:space:]]+(SUM|AVG|STD|STDDEV|MIN|MAX|BIT_OR|BIT_AND)\s*\(@i', $sql_query)); - $is_count = ! $is_group && (preg_match('@^SELECT[[:space:]]+COUNT\((.*\.+)?.*\)@i', $sql_query)); - $is_export = (preg_match('@[[:space:]]+INTO[[:space:]]+OUTFILE[[:space:]]+@i', $sql_query)); - $is_analyse = (preg_match('@[[:space:]]+PROCEDURE[[:space:]]+ANALYSE@i', $sql_query)); -} elseif (preg_match('@^EXPLAIN[[:space:]]+@i', $sql_query)) { - $is_explain = true; -} elseif (preg_match('@^DELETE[[:space:]]+@i', $sql_query)) { - $is_delete = true; - $is_affected = true; -} elseif (preg_match('@^(INSERT|LOAD[[:space:]]+DATA|REPLACE)[[:space:]]+@i', $sql_query)) { - $is_insert = true; - $is_affected = true; - if (preg_match('@^(REPLACE)[[:space:]]+@i', $sql_query)) { - $is_replace = true; - } -} elseif (preg_match('@^UPDATE[[:space:]]+@i', $sql_query)) { - $is_affected = true; -} elseif (preg_match('@^[[:space:]]*SHOW[[:space:]]+@i', $sql_query)) { - $is_show = true; -} elseif (preg_match('@^(CHECK|ANALYZE|REPAIR|OPTIMIZE)[[:space:]]+TABLE[[:space:]]+@i', $sql_query)) { - $is_maint = true; -} +list($is_group, $is_func, $is_count, $is_export, $is_analyse, $is_explain, + $is_delete, $is_affected, $is_insert, $is_replace, $is_show, $is_maint) + = PMA_getDisplayPropertyParams( + $sql_query, $is_select + ); // assign default full_sql_query $full_sql_query = $sql_query; @@ -937,13 +916,24 @@ if ((0 == $num_rows && 0 == $unlim_num_rows) || $is_affected) { $printview = isset($printview) ? $printview : null; $url_query = isset($url_query) ? $url_query : null; - $displayResultsObject->setProperties( - $unlim_num_rows, $fields_meta, $is_count, $is_export, $is_func, - $is_analyse, $num_rows, $fields_cnt, $querytime, $pmaThemeImage, $text_dir, - $is_maint, $is_explain, $is_show, $showtable, $printview, $url_query - ); - echo $displayResultsObject->getTable($result, $disp_mode, $analyzed_sql); - exit(); + if (!empty($sql_data) && ($sql_data['valid_queries'] > 1)) { + + echo getTableHtmlForMultipleQueries( + $displayResultsObject, $db, $sql_data, $goto, + $pmaThemeImage, $text_dir, $printview, $url_query, $disp_mode + ); + + } else { + + $displayResultsObject->setProperties( + $unlim_num_rows, $fields_meta, $is_count, $is_export, $is_func, + $is_analyse, $num_rows, $fields_cnt, $querytime, $pmaThemeImage, $text_dir, + $is_maint, $is_explain, $is_show, $showtable, $printview, $url_query + ); + + echo $displayResultsObject->getTable($result, $disp_mode, $analyzed_sql); + exit(); + } } @@ -1032,7 +1022,7 @@ if ((0 == $num_rows && 0 == $unlim_num_rows) || $is_affected) { } // Display previous update query (from tbl_replace) - if (isset($disp_query) && $cfg['ShowSQL'] == true) { + if (isset($disp_query) && ($cfg['ShowSQL'] == true) && empty($sql_data)) { echo $common_functions->getMessage($disp_message, $disp_query, 'success'); } @@ -1097,13 +1087,24 @@ $(makeProfilingChart); $printview = isset($printview) ? $printview : null; $url_query = isset($url_query) ? $url_query : null; - $displayResultsObject->setProperties( - $unlim_num_rows, $fields_meta, $is_count, $is_export, $is_func, - $is_analyse, $num_rows, $fields_cnt, $querytime, $pmaThemeImage, $text_dir, - $is_maint, $is_explain, $is_show, $showtable, $printview, $url_query - ); - echo $displayResultsObject->getTable($result, $disp_mode, $analyzed_sql); - PMA_DBI_free_result($result); + if (!empty($sql_data) && ($sql_data['valid_queries'] > 1)) { + + echo getTableHtmlForMultipleQueries( + $displayResultsObject, $db, $sql_data, $goto, + $pmaThemeImage, $text_dir, $printview, $url_query, $disp_mode + ); + + } else { + + $displayResultsObject->setProperties( + $unlim_num_rows, $fields_meta, $is_count, $is_export, $is_func, + $is_analyse, $num_rows, $fields_cnt, $querytime, $pmaThemeImage, $text_dir, + $is_maint, $is_explain, $is_show, $showtable, $printview, $url_query + ); + + echo $displayResultsObject->getTable($result, $disp_mode, $analyzed_sql); + PMA_DBI_free_result($result); + } // BEGIN INDEX CHECK See if indexes should be checked. if (isset($query_type) && $query_type == 'check_tbl' && isset($selected) && is_array($selected)) { @@ -1176,4 +1177,169 @@ $(makeProfilingChart); if (! isset($_REQUEST['table_maintenance'])) { exit; } + + +// These functions will need for use set the required parameters for display results + +/** + * Initialize some parameters needed to display results + * + * @param string $sql_query SQL statement + * @param boolean $is_select select query or not + * + * @return array set of parameters + * + * @access public + */ +function PMA_getDisplayPropertyParams($sql_query, $is_select) +{ + + $is_explain = $is_count = $is_export = $is_delete = $is_insert = $is_affected = $is_show = $is_maint = $is_analyse = $is_group = $is_func = $is_replace = false; + + if ($is_select) { + $is_group = preg_match('@(GROUP[[:space:]]+BY|HAVING|SELECT[[:space:]]+DISTINCT)[[:space:]]+@i', $sql_query); + $is_func = ! $is_group && (preg_match('@[[:space:]]+(SUM|AVG|STD|STDDEV|MIN|MAX|BIT_OR|BIT_AND)\s*\(@i', $sql_query)); + $is_count = ! $is_group && (preg_match('@^SELECT[[:space:]]+COUNT\((.*\.+)?.*\)@i', $sql_query)); + $is_export = (preg_match('@[[:space:]]+INTO[[:space:]]+OUTFILE[[:space:]]+@i', $sql_query)); + $is_analyse = (preg_match('@[[:space:]]+PROCEDURE[[:space:]]+ANALYSE@i', $sql_query)); + } elseif (preg_match('@^EXPLAIN[[:space:]]+@i', $sql_query)) { + $is_explain = true; + } elseif (preg_match('@^DELETE[[:space:]]+@i', $sql_query)) { + $is_delete = true; + $is_affected = true; + } elseif (preg_match('@^(INSERT|LOAD[[:space:]]+DATA|REPLACE)[[:space:]]+@i', $sql_query)) { + $is_insert = true; + $is_affected = true; + if (preg_match('@^(REPLACE)[[:space:]]+@i', $sql_query)) { + $is_replace = true; + } + } elseif (preg_match('@^UPDATE[[:space:]]+@i', $sql_query)) { + $is_affected = true; + } elseif (preg_match('@^[[:space:]]*SHOW[[:space:]]+@i', $sql_query)) { + $is_show = true; + } elseif (preg_match('@^(CHECK|ANALYZE|REPAIR|OPTIMIZE)[[:space:]]+TABLE[[:space:]]+@i', $sql_query)) { + $is_maint = true; + } + + return array( + $is_group, $is_func, $is_count, $is_export, $is_analyse, $is_explain, + $is_delete, $is_affected, $is_insert, $is_replace,$is_show, $is_maint + ); + +} + +/** + * Get the table name in a sql query + * If there are several tables in the SQL query, + * first table wil lreturn + * + * @param string $sql SQL query + * @param array $tables array of names in current database + * + * @return string $table table name + */ +function PMA_getTableNameBySQL($sql, $tables) +{ + + $table = ''; + + // loop through all the tables in the database + foreach($tables as $tbl){ + if(strpos($sql,$tbl)){ + $table .= ' ' . $tbl; + } + } + + if (count(explode(' ', trim($table))) > 1) { + $tmp_array = explode(' ', trim($table)); + return $tmp_array[0]; + } + + return trim($table); + +} + + +/** + * Generate table html when SQL statement have multiple queries + * which return displayable results + * + * @param PMA_DisplayResults $displayResultsObject object + * @param string $db database name + * @param array $sql_data information about SQL statement + * @param string $goto the URL to go back in case of errors + * @param string $pmaThemeImage path for theme images directory + * @param string $text_dir + * @param string $printview + * @param string $url_query URL query + * @param array $disp_mode the display mode + * + * @return string $table_html html content + */ +function getTableHtmlForMultipleQueries( + $displayResultsObject, $db, $sql_data, $goto, $pmaThemeImage, + $text_dir, $printview, $url_query, $disp_mode +) { + + $table_html = ''; + + $tables_array = PMA_DBI_get_tables($db); + $multi_sql = implode(";", $sql_data['valid_sql']); + + $querytime_before = array_sum(explode(' ', microtime())); + + $multiple_results = @PMA_DBI_try_multi_query($multi_sql); + + $querytime_after = array_sum(explode(' ', microtime())); + $querytime = $querytime_after - $querytime_before; + $sql_no = 0; + + do { + + $table = PMA_getTableNameBySQL($sql_data['valid_sql'][$sql_no], $tables_array); + $result = mysqli_store_result($GLOBALS['userlink']); + $fields_meta = PMA_DBI_get_fields_meta($result); + $fields_cnt = count($fields_meta); + $parsed_sql = PMA_SQP_parse($sql_query); + $analyzed_sql = PMA_SQP_analyze($parsed_sql); + $is_select = isset($analyzed_sql[0]['queryflags']['select_from']); + $unlim_num_rows = PMA_Table::countRecords($db, $table, $force_exact = true); + $showtable = PMA_Table::sGetStatusInfo($db, $table, null, true); + $url_query = PMA_generate_common_url($db, $table); + + list($is_group, $is_func, $is_count, $is_export, $is_analyse, + $is_explain, $is_delete, $is_affected, $is_insert, $is_replace, + $is_show, $is_maint) + = PMA_getDisplayPropertyParams( + $sql_data['valid_sql'][$sql_no], $is_select + ); + + if (! $is_affected) { + $num_rows = ($result) ? @PMA_DBI_num_rows($result) : 0; + } elseif (! isset($num_rows)) { + $num_rows = @PMA_DBI_affected_rows(); + } + + $displayResultsObject->__set('_db', $db); + $displayResultsObject->__set('_table', $table); + $displayResultsObject->__set('_goto', $goto); + $displayResultsObject->__set('_sql_query', $sql_data['valid_sql'][$sql_no]); + + $displayResultsObject->setProperties( + $unlim_num_rows, $fields_meta, $is_count, $is_export, $is_func, + $is_analyse, $num_rows, $fields_cnt, $querytime, $pmaThemeImage, $text_dir, + $is_maint, $is_explain, $is_show, $showtable, $printview, $url_query + ); + + $table_html .= $displayResultsObject->getTable($result, $disp_mode, $analyzed_sql); + unset($result); + $sql_no++; + + } while (mysqli_next_result($GLOBALS['userlink'])); + + return $table_html; + +} + + ?> From 9f1f8d6c75c4f4332f5e78ffd9fc66747c2ea226 Mon Sep 17 00:00:00 2001 From: Chanaka Indrajith Date: Sun, 22 Jul 2012 16:22:49 +0530 Subject: [PATCH 2/6] Support for stored procedures with multiple queries --- libraries/dbi/mysqli.dbi.lib.php | 17 ++++ libraries/import.lib.php | 23 ++--- sql.php | 153 +++++++++++++++++++++++-------- 3 files changed, 142 insertions(+), 51 deletions(-) diff --git a/libraries/dbi/mysqli.dbi.lib.php b/libraries/dbi/mysqli.dbi.lib.php index dc246957d3..bc49cc29d7 100644 --- a/libraries/dbi/mysqli.dbi.lib.php +++ b/libraries/dbi/mysqli.dbi.lib.php @@ -367,6 +367,23 @@ function PMA_DBI_next_result($link = null) return mysqli_next_result($link); } +/** + * Store the result returned from multi query + * + * @return mixed false when empty results / result set when not empty + */ +function PMA_DBI_store_result() +{ + if (empty($link)) { + if (isset($GLOBALS['userlink'])) { + $link = $GLOBALS['userlink']; + } else { + return false; + } + } + return mysqli_store_result($link); +} + /** * Returns a string representing the type of connection used * diff --git a/libraries/import.lib.php b/libraries/import.lib.php index 1db15025b0..220dcf5beb 100644 --- a/libraries/import.lib.php +++ b/libraries/import.lib.php @@ -111,14 +111,6 @@ function PMA_importRunQuery($sql = '', $full = '', $controluser = false, &$sql_d $executed_queries++; - if ($controluser) { - $result = PMA_queryAsControlUser( - $import_run_buffer['sql'] - ); - } else { - $result = PMA_DBI_try_query($import_run_buffer['sql']); - } - if ($run_query && $GLOBALS['finished'] && empty($sql) @@ -136,11 +128,8 @@ function PMA_importRunQuery($sql = '', $full = '', $controluser = false, &$sql_d $display_query = ''; } $sql_query = $import_run_buffer['sql']; - - if ($result !== false) { - $sql_data['valid_sql'][] = $import_run_buffer['full']; - $sql_data['valid_queries']++; - } + $sql_data['valid_sql'][] = $import_run_buffer['sql']; + $sql_data['valid_queries']++; // If a 'USE ' SQL-clause was found, // set our current $db to the new one @@ -151,6 +140,14 @@ function PMA_importRunQuery($sql = '', $full = '', $controluser = false, &$sql_d ); } elseif ($run_query) { + if ($controluser) { + $result = PMA_queryAsControlUser( + $import_run_buffer['sql'] + ); + } else { + $result = PMA_DBI_try_query($import_run_buffer['sql']); + } + $msg = '# '; if ($result === false) { // execution failed if (! isset($my_die)) { diff --git a/sql.php b/sql.php index 27df11e36b..654f8ab96e 100644 --- a/sql.php +++ b/sql.php @@ -476,41 +476,29 @@ $full_sql_query = $sql_query; // Handle remembered sorting order, only for single table query if ($GLOBALS['cfg']['RememberSorting'] && ! ($is_count || $is_export || $is_func || $is_analyse) - && count($analyzed_sql[0]['select_expr']) == 0 + && isset($analyzed_sql[0]['select_expr']) + && (count($analyzed_sql[0]['select_expr']) == 0) && isset($analyzed_sql[0]['queryflags']['select_from']) && count($analyzed_sql[0]['table_ref']) == 1 -) { - $pmatable = new PMA_Table($table, $db); - if (empty($analyzed_sql[0]['order_by_clause'])) { - $sorted_col = $pmatable->getUiProp(PMA_Table::PROP_SORTED_COLUMN); - if ($sorted_col) { - // retrieve the remembered sorting order for current table - $sql_order_to_append = ' ORDER BY ' . $sorted_col . ' '; - $full_sql_query = $analyzed_sql[0]['section_before_limit'] . $sql_order_to_append - . $analyzed_sql[0]['limit_clause'] . ' ' . $analyzed_sql[0]['section_after_limit']; - - // update the $analyzed_sql - $analyzed_sql[0]['section_before_limit'] .= $sql_order_to_append; - $analyzed_sql[0]['order_by_clause'] = $sorted_col; - } - } else { - // store the remembered table into session - $pmatable->setUiProp(PMA_Table::PROP_SORTED_COLUMN, $analyzed_sql[0]['order_by_clause']); - } +) { + + PMA_handleSortOrder($db, $table, $analyzed_sql, $full_sql_query); + } +$sql_limit_to_append = ' LIMIT ' . $_SESSION['tmp_user_values']['pos'] + . ', ' . $_SESSION['tmp_user_values']['max_rows'] . " "; + // Do append a "LIMIT" clause? if (($_SESSION['tmp_user_values']['max_rows'] != 'all') && ! ($is_count || $is_export || $is_func || $is_analyse) && isset($analyzed_sql[0]['queryflags']['select_from']) && ! isset($analyzed_sql[0]['queryflags']['offset']) && empty($analyzed_sql[0]['limit_clause']) -) { - $sql_limit_to_append = ' LIMIT ' . $_SESSION['tmp_user_values']['pos'] - . ', ' . $_SESSION['tmp_user_values']['max_rows'] . " "; +) { - $full_sql_query = $analyzed_sql[0]['section_before_limit'] . "\n" - . $sql_limit_to_append . $analyzed_sql[0]['section_after_limit']; + $full_sql_query = PMA_getSqlWithLimitClause($full_sql_query, $analyzed_sql, $sql_limit_to_append); + /** * @todo pretty printing of this modified query */ @@ -553,11 +541,16 @@ if (isset($GLOBALS['show_as_php']) || ! empty($GLOBALS['validatequery'])) { // If a stored procedure was called, there may be more results that are // queued up and waiting to be flushed from the buffer. So let's do that. - while (true) { + do { + PMA_DBI_store_result(); if (! PMA_DBI_more_results()) { break; } - PMA_DBI_next_result(); + } while (PMA_DBI_next_result()); + + $is_procedure = false; + if (stripos($full_sql_query, 'call') !== false) { + $is_procedure = true; } $querytime_after = array_sum(explode(' ', microtime())); @@ -920,7 +913,7 @@ if ((0 == $num_rows && 0 == $unlim_num_rows) || $is_affected) { echo getTableHtmlForMultipleQueries( $displayResultsObject, $db, $sql_data, $goto, - $pmaThemeImage, $text_dir, $printview, $url_query, $disp_mode + $pmaThemeImage, $text_dir, $printview, $url_query, $disp_mode, $sql_limit_to_append ); } else { @@ -1087,11 +1080,11 @@ $(makeProfilingChart); $printview = isset($printview) ? $printview : null; $url_query = isset($url_query) ? $url_query : null; - if (!empty($sql_data) && ($sql_data['valid_queries'] > 1)) { + if (!empty($sql_data) && ($sql_data['valid_queries'] > 1) || $is_procedure) { echo getTableHtmlForMultipleQueries( $displayResultsObject, $db, $sql_data, $goto, - $pmaThemeImage, $text_dir, $printview, $url_query, $disp_mode + $pmaThemeImage, $text_dir, $printview, $url_query, $disp_mode, $sql_limit_to_append ); } else { @@ -1278,7 +1271,7 @@ function PMA_getTableNameBySQL($sql, $tables) */ function getTableHtmlForMultipleQueries( $displayResultsObject, $db, $sql_data, $goto, $pmaThemeImage, - $text_dir, $printview, $url_query, $disp_mode + $text_dir, $printview, $url_query, $disp_mode, $sql_limit_to_append ) { $table_html = ''; @@ -1288,7 +1281,9 @@ function getTableHtmlForMultipleQueries( $querytime_before = array_sum(explode(' ', microtime())); - $multiple_results = @PMA_DBI_try_multi_query($multi_sql); + // Assignment for variable is not needed since the results are + // looiping using the connection + @PMA_DBI_try_multi_query($multi_sql); $querytime_after = array_sum(explode(' ', microtime())); $querytime = $querytime_after - $querytime_before; @@ -1296,13 +1291,15 @@ function getTableHtmlForMultipleQueries( do { + // Initialize needed params related to each query $table = PMA_getTableNameBySQL($sql_data['valid_sql'][$sql_no], $tables_array); - $result = mysqli_store_result($GLOBALS['userlink']); + $result = PMA_DBI_store_result(); $fields_meta = PMA_DBI_get_fields_meta($result); $fields_cnt = count($fields_meta); - $parsed_sql = PMA_SQP_parse($sql_query); - $analyzed_sql = PMA_SQP_analyze($parsed_sql); - $is_select = isset($analyzed_sql[0]['queryflags']['select_from']); + $parsed_sql = PMA_SQP_parse($sql_data['valid_sql'][$sql_no]); + + $analyzed_sql = PMA_SQP_analyze($parsed_sql); + $is_select = isset($analyzed_sql[0]['queryflags']['select_from']); $unlim_num_rows = PMA_Table::countRecords($db, $table, $force_exact = true); $showtable = PMA_Table::sGetStatusInfo($db, $table, null, true); $url_query = PMA_generate_common_url($db, $table); @@ -1314,12 +1311,40 @@ function getTableHtmlForMultipleQueries( $sql_data['valid_sql'][$sql_no], $is_select ); + // Handle remembered sorting order, only for single table query + if ($GLOBALS['cfg']['RememberSorting'] + && ! ($is_count || $is_export || $is_func || $is_analyse) + && isset($analyzed_sql[0]['select_expr']) + && (count($analyzed_sql[0]['select_expr']) == 0) + && isset($analyzed_sql[0]['queryflags']['select_from']) + && count($analyzed_sql[0]['table_ref']) == 1 + ) { + PMA_handleSortOrder($db, $table, $analyzed_sql, $sql_data['valid_sql'][$sql_no]); + } + + // Do append a "LIMIT" clause? + if (($_SESSION['tmp_user_values']['max_rows'] != 'all') + && ! ($is_count || $is_export || $is_func || $is_analyse) + && isset($analyzed_sql[0]['queryflags']['select_from']) + && ! isset($analyzed_sql[0]['queryflags']['offset']) + && empty($analyzed_sql[0]['limit_clause']) + ) { + $sql_data['valid_sql'][$sql_no] = PMA_getSqlWithLimitClause( + $sql_data['valid_sql'][$sql_no], $analyzed_sql, $sql_limit_to_append + ); + } + if (! $is_affected) { $num_rows = ($result) ? @PMA_DBI_num_rows($result) : 0; } elseif (! isset($num_rows)) { $num_rows = @PMA_DBI_affected_rows(); } + if ($num_rows == 0) { + continue; + } + + // Set the needed properties related to executing sql query $displayResultsObject->__set('_db', $db); $displayResultsObject->__set('_table', $table); $displayResultsObject->__set('_goto', $goto); @@ -1331,15 +1356,67 @@ function getTableHtmlForMultipleQueries( $is_maint, $is_explain, $is_show, $showtable, $printview, $url_query ); - $table_html .= $displayResultsObject->getTable($result, $disp_mode, $analyzed_sql); - unset($result); + // Collect the tables + $table_html .= $displayResultsObject->getTable($result, $disp_mode, $analyzed_sql); $sql_no++; + + // Free the result to save the memory + PMA_DBI_free_result($result); + + if (! PMA_DBI_more_results()) { + break; + } - } while (mysqli_next_result($GLOBALS['userlink'])); + } while (PMA_DBI_next_result()); return $table_html; } +/** + * Handle remembered sorting order, only for single table query + * + * @param string $db database name + * @param string $table table name + * @param array $analyzed_sql the analyzed query + * @param string $full_sql_query SQL query + */ +function PMA_handleSortOrder($db, $table, &$analyzed_sql, &$full_sql_query) +{ + + $pmatable = new PMA_Table($table, $db); + if (empty($analyzed_sql[0]['order_by_clause'])) { + $sorted_col = $pmatable->getUiProp(PMA_Table::PROP_SORTED_COLUMN); + if ($sorted_col) { + // retrieve the remembered sorting order for current table + $sql_order_to_append = ' ORDER BY ' . $sorted_col . ' '; + $full_sql_query = $analyzed_sql[0]['section_before_limit'] . $sql_order_to_append + . $analyzed_sql[0]['limit_clause'] . ' ' . $analyzed_sql[0]['section_after_limit']; + // update the $analyzed_sql + $analyzed_sql[0]['section_before_limit'] .= $sql_order_to_append; + $analyzed_sql[0]['order_by_clause'] = $sorted_col; + } + } else { + // store the remembered table into session + $pmatable->setUiProp(PMA_Table::PROP_SORTED_COLUMN, $analyzed_sql[0]['order_by_clause']); + } + +} + +/** + * Append limit clause to SQL query + * + * @param string $full_sql_query SQL query + * @param array $analyzed_sql the analyzed query + * @param string $sql_limit_to_append clause to append + * + * @return string limit clause appended SQL query + */ +function PMA_getSqlWithLimitClause($full_sql_query, $analyzed_sql, $sql_limit_to_append) +{ + return $analyzed_sql[0]['section_before_limit'] . "\n" + . $sql_limit_to_append . $analyzed_sql[0]['section_after_limit']; +} + ?> From 42bff42aca96f32e6bbe68653944f92199cc1a2c Mon Sep 17 00:00:00 2001 From: Chanaka Indrajith Date: Sun, 22 Jul 2012 18:33:02 +0530 Subject: [PATCH 3/6] Support for swap among databases in multiple queries --- libraries/import.lib.php | 16 ++++++++++++++-- sql.php | 35 +++++++++++++++++++++++++++++++---- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/libraries/import.lib.php b/libraries/import.lib.php index 220dcf5beb..ff8acee258 100644 --- a/libraries/import.lib.php +++ b/libraries/import.lib.php @@ -97,6 +97,14 @@ function PMA_importRunQuery($sql = '', $full = '', $controluser = false, &$sql_d if (! empty($import_run_buffer['sql']) && trim($import_run_buffer['sql']) != '' ) { + + // USE query changes the database, son need to track + // while running multiple queries + $is_use_query + = (stripos($import_run_buffer['sql'], "use ") !== false) + ? true + : false; + $max_sql_len = max($max_sql_len, strlen($import_run_buffer['sql'])); if (! $sql_query_disabled) { $sql_query .= $import_run_buffer['full']; @@ -170,14 +178,18 @@ function PMA_importRunQuery($sql = '', $full = '', $controluser = false, &$sql_d if ($a_num_rows > 0) { $msg .= __('Rows'). ': ' . $a_num_rows; $last_query_with_results = $import_run_buffer['sql']; - $sql_data['valid_sql'][] = $import_run_buffer['sql']; - $sql_data['valid_queries']++; } elseif ($a_aff_rows > 0) { $message = PMA_Message::affected_rows($a_aff_rows); $msg .= $message->getMessage(); } else { $msg .= __('MySQL returned an empty result set (i.e. zero rows).'); } + + if (($a_num_rows > 0) || $is_use_query) { + $sql_data['valid_sql'][] = $import_run_buffer['sql']; + $sql_data['valid_queries']++; + } + } if (! $sql_query_disabled) { $sql_query .= $msg . "\n"; diff --git a/sql.php b/sql.php index 654f8ab96e..5fff2bd43d 100644 --- a/sql.php +++ b/sql.php @@ -1221,6 +1221,27 @@ function PMA_getDisplayPropertyParams($sql_query, $is_select) } +/** + * Get the database name inside a USE query + * + * @param string $sql SQL query + * @param array $databases array with all databases + * + * @return strin $db new database name + */ +function PMA_getNewDatabase($sql, $databases) +{ + $db = ''; + // loop through all the databases + foreach ($databases as $database){ + if (strpos($sql,$database['SCHEMA_NAME']) !== false) { + $db = $database; + break; + } + } + return $db; +} + /** * Get the table name in a sql query * If there are several tables in the SQL query, @@ -1237,8 +1258,8 @@ function PMA_getTableNameBySQL($sql, $tables) $table = ''; // loop through all the tables in the database - foreach($tables as $tbl){ - if(strpos($sql,$tbl)){ + foreach ($tables as $tbl) { + if (strpos($sql,$tbl)) { $table .= ' ' . $tbl; } } @@ -1277,8 +1298,8 @@ function getTableHtmlForMultipleQueries( $table_html = ''; $tables_array = PMA_DBI_get_tables($db); - $multi_sql = implode(";", $sql_data['valid_sql']); - + $databases_array = PMA_DBI_get_databases_full(); + $multi_sql = implode(";", $sql_data['valid_sql']); $querytime_before = array_sum(explode(' ', microtime())); // Assignment for variable is not needed since the results are @@ -1292,6 +1313,12 @@ function getTableHtmlForMultipleQueries( do { // Initialize needed params related to each query + + // Use query can change the database + if (stripos($sql_data['valid_sql'][$sql_no], "use ")) { + $db = PMA_getNewDatabase($sql_data['valid_sql'][$sql_no], $databases_array); + } + $table = PMA_getTableNameBySQL($sql_data['valid_sql'][$sql_no], $tables_array); $result = PMA_DBI_store_result(); $fields_meta = PMA_DBI_get_fields_meta($result); From 0659000a4e773ef8ae2f46f800bfdbce285deb6a Mon Sep 17 00:00:00 2001 From: Chanaka Indrajith Date: Sun, 22 Jul 2012 22:19:16 +0530 Subject: [PATCH 4/6] Support for routines execute under Routines tab --- libraries/rte/rte_routines.lib.php | 117 ++++++++++++++++++----------- 1 file changed, 72 insertions(+), 45 deletions(-) diff --git a/libraries/rte/rte_routines.lib.php b/libraries/rte/rte_routines.lib.php index b07b598cfd..89d0bddb84 100644 --- a/libraries/rte/rte_routines.lib.php +++ b/libraries/rte/rte_routines.lib.php @@ -1253,34 +1253,26 @@ function PMA_RTN_handleExecute() . "(" . implode(', ', $args) . ") " . "AS " . $common_functions->backquote($routine['item_name']) . ";\n"; } - // Execute the queries - $affected = 0; - $result = null; + + // Get all the queries as one SQL statement + $multiple_query = implode("", $queries); + $outcome = true; - foreach ($queries as $query) { - $resource = PMA_DBI_try_query($query); - if ($resource === false) { - $outcome = false; - break; - } - while (true) { - if (! PMA_DBI_more_results()) { - break; - } - PMA_DBI_next_result(); - } - if (substr($query, 0, 6) == 'SELECT') { - $result = $resource; - } else if (substr($query, 0, 4) == 'CALL') { - $result = $resource ? $resource : $result; - $affected = PMA_DBI_affected_rows() - PMA_DBI_num_rows($resource); - } + $affected = 0; + + // Execute query + if (! PMA_DBI_try_multi_query($multiple_query)) { + $outcome = false; } + // Generate output if ($outcome) { $message = __('Your SQL query has been executed successfully'); if ($routine['item_type'] == 'PROCEDURE') { $message .= '
'; + + // TODO : message need to be modified according to the + // output from the routine $message .= sprintf( _ngettext( '%d row affected by the last statement inside the procedure', @@ -1295,36 +1287,70 @@ function PMA_RTN_handleExecute() $output = ''; $output .= PMA_SQP_formatHtml(PMA_SQP_parse(implode($queries))); $output .= ''; + // Display results - if ($result) { - $output .= "
"; - $output .= sprintf( - __('Execution results of routine %s'), - $common_functions->backquote(htmlspecialchars($routine['item_name'])) - ); - $output .= ""; - $output .= ""; - foreach (PMA_DBI_get_fields_meta($result) as $key => $field) { - $output .= ""; - } - $output .= ""; - // Stored routines can only ever return ONE ROW. - $data = PMA_DBI_fetch_single_row($result); - foreach ($data as $key => $value) { - if ($value === null) { - $value = 'NULL'; - } else { - $value = htmlspecialchars($value); + $output .= "
"; + $output .= sprintf( + __('Execution results of routine %s'), + $common_functions->backquote(htmlspecialchars($routine['item_name'])) + ); + $output .= ""; + + $num_of_rusults_set_to_display = 0; + + do { + + $result = PMA_DBI_store_result(); + $num_rows = PMA_DBI_num_rows($result); + + if (($result !== false) && ($num_rows > 0)) { + + $output .= "
"; - $output .= htmlspecialchars($field->name); - $output .= "
"; + foreach (PMA_DBI_get_fields_meta($result) as $key => $field) { + $output .= ""; + } + $output .= ""; + + $color_class = 'odd'; + + while ($row = PMA_DBI_fetch_assoc($result)) { + $output .= ""; + foreach ($row as $key => $value) { + if ($value === null) { + $value = 'NULL'; + } else { + $value = htmlspecialchars($value); + } + $output .= ""; + } + $output .= ""; + $color_class = ($color_class == 'odd') ? 'even' : 'odd'; } - $output .= ""; + + $output .= "
"; + $output .= htmlspecialchars($field->name); + $output .= "
" . $value . "
" . $value . "
"; + $num_of_rusults_set_to_display++; + } - $output .= "
"; - } else { + + if (! PMA_DBI_more_results()) { + break; + } + + $output .= "
"; + + PMA_DBI_free_result($result); + + } while (PMA_DBI_next_result()); + + $output .= ""; + + if ($num_of_rusults_set_to_display == 0) { $notice = __('MySQL returned an empty result set (i.e. zero rows).'); $output .= PMA_message::notice($notice)->getDisplay(); } + } else { $output = ''; $message = PMA_message::error( @@ -1336,6 +1362,7 @@ function PMA_RTN_handleExecute() . __('MySQL said: ') . PMA_DBI_getError(null) ); } + // Print/send output if ($GLOBALS['is_ajax_request']) { $response = PMA_Response::getInstance(); From adcae901e18c626b4a649d8f93b3e0966d19d6ee Mon Sep 17 00:00:00 2001 From: Chanaka Indrajith Date: Mon, 23 Jul 2012 00:13:35 +0530 Subject: [PATCH 5/6] Put some limitations for multiple results display mode --- libraries/DisplayResults.class.php | 25 ++++++++++++++----------- sql.php | 10 ++++++++-- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/libraries/DisplayResults.class.php b/libraries/DisplayResults.class.php index 9fbde32e25..e045f8057e 100644 --- a/libraries/DisplayResults.class.php +++ b/libraries/DisplayResults.class.php @@ -940,7 +940,7 @@ class PMA_DisplayResults private function _getTableHeaders( &$is_display, $analyzed_sql = '', $sort_expression = '', $sort_expression_nodirection = '', - $sort_direction = '' + $sort_direction = '', $is_limited_display = false ) { $table_headers_html = ''; @@ -1002,7 +1002,7 @@ class PMA_DisplayResults $this->__set('_vertical_display', $vertical_display); // Display options (if we are not in print view) - if (! (isset($printview) && ($printview == '1'))) { + if (! (isset($printview) && ($printview == '1')) && ! $is_limited_display) { $table_headers_html .= $this->_getOptionsBlock(); @@ -2422,8 +2422,9 @@ class PMA_DisplayResults * * @see getTable() */ - private function _getTableBody(&$dt_result, &$is_display, $map, $analyzed_sql) - { + private function _getTableBody( + &$dt_result, &$is_display, $map, $analyzed_sql, $is_limited_display = false + ) { global $row; // mostly because of browser transformations, // to make the row-data accessible in a plugin @@ -2447,8 +2448,9 @@ class PMA_DisplayResults $vertical_display['data'] = array(); $vertical_display['row_delete'] = array(); $this->__set('_vertical_display', $vertical_display); + // name of the class added to all grid editable elements - $grid_edit_class = 'grid_edit'; + $grid_edit_class = $is_limited_display ? '' : 'grid_edit'; // prepare to get the column order, if available list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql); @@ -4246,9 +4248,10 @@ class PMA_DisplayResults * * @see sql.php file */ - public function getTable(&$dt_result, &$the_disp_mode, $analyzed_sql) - { - + public function getTable( + &$dt_result, &$the_disp_mode, $analyzed_sql, $is_limited_display = false + ) { + $table_html = ''; // Following variable are needed for use in isset/empty or // use with array indexes/safe use in foreach @@ -4394,13 +4397,13 @@ class PMA_DisplayResults // 3. ----- Prepare the results table ----- $table_html .= $this->_getTableHeaders( $is_display, $analyzed_sql, $sort_expression, - $sort_expression_nodirection, $sort_direction + $sort_expression_nodirection, $sort_direction, $is_limited_display ) . '' . "\n"; $url_query = ''; $table_html .= $this->_getTableBody( - $dt_result, $is_display, $map, $analyzed_sql + $dt_result, $is_display, $map, $analyzed_sql, $is_limited_display ); // vertical output case @@ -4439,7 +4442,7 @@ class PMA_DisplayResults // 6. ----- Prepare "Query results operations" - if (! isset($printview) || ($printview != '1')) { + if ((! isset($printview) || ($printview != '1')) && ! $is_limited_display) { $table_html .= $this->_getResultsOperations( $the_disp_mode, $analyzed_sql ); diff --git a/sql.php b/sql.php index 5fff2bd43d..5adb0f936a 100644 --- a/sql.php +++ b/sql.php @@ -1382,9 +1382,15 @@ function getTableHtmlForMultipleQueries( $is_analyse, $num_rows, $fields_cnt, $querytime, $pmaThemeImage, $text_dir, $is_maint, $is_explain, $is_show, $showtable, $printview, $url_query ); - + + // With multiple results, operations are limied + $disp_mode = 'nnnn000000'; + $is_limited_display = true; + // Collect the tables - $table_html .= $displayResultsObject->getTable($result, $disp_mode, $analyzed_sql); + $table_html .= $displayResultsObject->getTable( + $result, $disp_mode, $analyzed_sql, $is_limited_display + ); $sql_no++; // Free the result to save the memory From b81935e05c23cd7c86d86ca76141589b19f16ef4 Mon Sep 17 00:00:00 2001 From: Chanaka Indrajith Date: Mon, 23 Jul 2012 21:34:54 +0530 Subject: [PATCH 6/6] Use PMA_DBI_real_multi_query function, inside PMA_DBI_try_multi_query function --- libraries/database_interface.lib.php | 2 +- libraries/dbi/mysql.dbi.lib.php | 18 ++++++++++++++++++ libraries/dbi/mysqli.dbi.lib.php | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/libraries/database_interface.lib.php b/libraries/database_interface.lib.php index c3b17d1e3c..30b934a697 100644 --- a/libraries/database_interface.lib.php +++ b/libraries/database_interface.lib.php @@ -196,7 +196,7 @@ function PMA_DBI_try_multi_query($multi_query = '', $link = null) } } - return mysqli_multi_query($link, $multi_query); + return PMA_DBI_real_multi_query($link, $multi_query); } diff --git a/libraries/dbi/mysql.dbi.lib.php b/libraries/dbi/mysql.dbi.lib.php index 0e4a5587a1..41d4472556 100644 --- a/libraries/dbi/mysql.dbi.lib.php +++ b/libraries/dbi/mysql.dbi.lib.php @@ -53,6 +53,24 @@ function PMA_DBI_real_connect($server, $user, $password, $client_flags, $persist return $link; } +/** + * Run the multi query and output the results + * + * @param mysqli $link mysqli object + * @param string $query multi query statement to execute + * + * @return boolean false always false since mysql extention not support + * for multi query executions + */ +function PMA_DBI_real_multi_query($link, $query) +{ + // N.B.: PHP's 'mysql' extension does not support + // multi_queries so this function will always + // return false. Use the 'mysqli' extension, if + // you need support for multi_queries. + return false; +} + /** * connects to the database server * diff --git a/libraries/dbi/mysqli.dbi.lib.php b/libraries/dbi/mysqli.dbi.lib.php index bc49cc29d7..1bb6a84552 100644 --- a/libraries/dbi/mysqli.dbi.lib.php +++ b/libraries/dbi/mysqli.dbi.lib.php @@ -261,7 +261,7 @@ function PMA_DBI_real_query($query, $link, $options) * * @return mysqli_result collection | boolean(false) */ -function PMA_DBI_real_muli_query($link, $query) +function PMA_DBI_real_multi_query($link, $query) { return mysqli_multi_query($link, $query); }