From d5acfed0e8dd0932bdbf46404ddd9daf7d7f9c74 Mon Sep 17 00:00:00 2001 From: Chanaka Indrajith Date: Fri, 20 Jul 2012 23:13:04 +0530 Subject: [PATCH] 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; + +} + + ?>