Merge branch 'QA_4_4' into QA_4_5
[phpmyadmin.git] / libraries / sql.lib.php
blob12c7998b3d4512469a5546940d2335f924da30b4
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * set of functions for the sql executor
6 * @package PhpMyAdmin
7 */
8 if (!defined('PHPMYADMIN')) {
9 exit;
12 /**
13 * Parses and analyzes the given SQL query.
15 * @param string $sql_query SQL query
16 * @param string $db DB name
18 * @return mixed
20 function PMA_parseAndAnalyze($sql_query, $db = null)
22 if (($db === null) && (!empty($GLOBALS['db']))) {
23 $db = $GLOBALS['db'];
26 // `$sql_query` is being used inside `parse_analyze.inc.php`.
27 return include 'libraries/parse_analyze.inc.php';
30 /**
31 * Handle remembered sorting order, only for single table query
33 * @param string $db database name
34 * @param string $table table name
35 * @param array &$analyzed_sql_results the analyzed query results
36 * @param string &$full_sql_query SQL query
38 * @return void
40 function PMA_handleSortOrder(
41 $db, $table, &$analyzed_sql_results, &$full_sql_query
42 ) {
43 $pmatable = new PMA_Table($table, $db);
45 if (empty($analyzed_sql_results['order'])) {
47 // Retrieving the name of the column we should sort after.
48 $sortCol = $pmatable->getUiProp(PMA_Table::PROP_SORTED_COLUMN);
49 if (empty($sortCol)) {
50 return;
53 // Remove the name of the table from the retrieved field name.
54 $sortCol = str_replace(PMA_Util::backquote($table) . '.', '', $sortCol);
56 // Create the new query.
57 $full_sql_query = SqlParser\Utils\Query::replaceClause(
58 $analyzed_sql_results['statement'],
59 $analyzed_sql_results['parser']->list,
60 'ORDER BY ' . $sortCol
63 // TODO: Avoid reparsing the query.
64 $analyzed_sql_results = SqlParser\Utils\Query::getAll($full_sql_query);
65 } else {
66 // Store the remembered table into session.
67 $pmatable->setUiProp(
68 PMA_Table::PROP_SORTED_COLUMN,
69 SqlParser\Utils\Query::getClause(
70 $analyzed_sql_results['statement'],
71 $analyzed_sql_results['parser']->list,
72 'ORDER BY'
78 /**
79 * Append limit clause to SQL query
81 * @param array &$analyzed_sql_results the analyzed query results
83 * @return string limit clause appended SQL query
85 function PMA_getSqlWithLimitClause(&$analyzed_sql_results)
87 return SqlParser\Utils\Query::replaceClause(
88 $analyzed_sql_results['statement'],
89 $analyzed_sql_results['parser']->list,
90 'LIMIT ' . $_SESSION['tmpval']['pos'] . ', '
91 . $_SESSION['tmpval']['max_rows']
95 /**
96 * Verify whether the result set has columns from just one table
98 * @param array $fields_meta meta fields
100 * @return boolean whether the result set has columns from just one table
102 function PMA_resultSetHasJustOneTable($fields_meta)
104 $just_one_table = true;
105 $prev_table = '';
106 foreach ($fields_meta as $one_field_meta) {
107 if ($one_field_meta->table != ''
108 && $prev_table != ''
109 && $one_field_meta->table != $prev_table
111 $just_one_table = false;
113 if ($one_field_meta->table != '') {
114 $prev_table = $one_field_meta->table;
117 return $just_one_table && $prev_table != '';
121 * Verify whether the result set contains all the columns
122 * of at least one unique key
124 * @param string $db database name
125 * @param string $table table name
126 * @param array $fields_meta meta fields
128 * @return boolean whether the result set contains a unique key
130 function PMA_resultSetContainsUniqueKey($db, $table, $fields_meta)
132 $resultSetColumnNames = array();
133 foreach ($fields_meta as $oneMeta) {
134 $resultSetColumnNames[] = $oneMeta->name;
136 foreach (PMA_Index::getFromTable($table, $db) as $index) {
137 if ($index->isUnique()) {
138 $indexColumns = $index->getColumns();
139 $numberFound = 0;
140 foreach ($indexColumns as $indexColumnName => $dummy) {
141 if (in_array($indexColumnName, $resultSetColumnNames)) {
142 $numberFound++;
145 if ($numberFound == count($indexColumns)) {
146 return true;
150 return false;
154 * Get the HTML for relational column dropdown
155 * During grid edit, if we have a relational field, returns the html for the
156 * dropdown
158 * @param string $db current database
159 * @param string $table current table
160 * @param string $column current column
161 * @param string $curr_value current selected value
163 * @return string $dropdown html for the dropdown
165 function PMA_getHtmlForRelationalColumnDropdown($db, $table, $column, $curr_value)
167 $foreigners = PMA_getForeigners($db, $table, $column);
169 $foreignData = PMA_getForeignData($foreigners, $column, false, '', '');
171 if ($foreignData['disp_row'] == null) {
172 //Handle the case when number of values
173 //is more than $cfg['ForeignKeyMaxLimit']
174 $_url_params = array(
175 'db' => $db,
176 'table' => $table,
177 'field' => $column
180 $dropdown = '<span class="curr_value">'
181 . htmlspecialchars($_REQUEST['curr_value'])
182 . '</span>'
183 . '<a href="browse_foreigners.php'
184 . PMA_URL_getCommon($_url_params) . '"'
185 . 'class="ajax browse_foreign" ' . '>'
186 . __('Browse foreign values')
187 . '</a>';
188 } else {
189 $dropdown = PMA_foreignDropdown(
190 $foreignData['disp_row'],
191 $foreignData['foreign_field'],
192 $foreignData['foreign_display'],
193 $curr_value,
194 $GLOBALS['cfg']['ForeignKeyMaxLimit']
196 $dropdown = '<select>' . $dropdown . '</select>';
199 return $dropdown;
203 * Get the HTML for the profiling table and accompanying chart if profiling is set.
204 * Otherwise returns null
206 * @param string $url_query url query
207 * @param string $db current database
208 * @param array $profiling_results array containing the profiling info
210 * @return string $profiling_table html for the profiling table and chart
212 function PMA_getHtmlForProfilingChart($url_query, $db, $profiling_results)
214 if (! empty($profiling_results)) {
215 $pma_token = $_SESSION[' PMA_token '];
216 $url_query = isset($url_query)
217 ? $url_query
218 : PMA_URL_getCommon(array('db' => $db));
220 $profiling_table = '';
221 $profiling_table .= '<fieldset><legend>' . __('Profiling')
222 . '</legend>' . "\n";
223 $profiling_table .= '<div class="floatleft">';
224 $profiling_table .= '<h3>' . __('Detailed profile') . '</h3>';
225 $profiling_table .= '<table id="profiletable"><thead>' . "\n";
226 $profiling_table .= ' <tr>' . "\n";
227 $profiling_table .= ' <th>' . __('Order')
228 . '<div class="sorticon"></div></th>' . "\n";
229 $profiling_table .= ' <th>' . __('State')
230 . PMA_Util::showMySQLDocu('general-thread-states')
231 . '<div class="sorticon"></div></th>' . "\n";
232 $profiling_table .= ' <th>' . __('Time')
233 . '<div class="sorticon"></div></th>' . "\n";
234 $profiling_table .= ' </tr></thead><tbody>' . "\n";
235 list($detailed_table, $chart_json, $profiling_stats)
236 = PMA_analyzeAndGetTableHtmlForProfilingResults($profiling_results);
237 $profiling_table .= $detailed_table;
238 $profiling_table .= '</tbody></table>' . "\n";
239 $profiling_table .= '</div>';
241 $profiling_table .= '<div class="floatleft">';
242 $profiling_table .= '<h3>' . __('Summary by state') . '</h3>';
243 $profiling_table .= '<table id="profilesummarytable"><thead>' . "\n";
244 $profiling_table .= ' <tr>' . "\n";
245 $profiling_table .= ' <th>' . __('State')
246 . PMA_Util::showMySQLDocu('general-thread-states')
247 . '<div class="sorticon"></div></th>' . "\n";
248 $profiling_table .= ' <th>' . __('Total Time')
249 . '<div class="sorticon"></div></th>' . "\n";
250 $profiling_table .= ' <th>' . __('% Time')
251 . '<div class="sorticon"></div></th>' . "\n";
252 $profiling_table .= ' <th>' . __('Calls')
253 . '<div class="sorticon"></div></th>' . "\n";
254 $profiling_table .= ' <th>' . __('ø Time')
255 . '<div class="sorticon"></div></th>' . "\n";
256 $profiling_table .= ' </tr></thead><tbody>' . "\n";
257 $profiling_table .= PMA_getTableHtmlForProfilingSummaryByState(
258 $profiling_stats
260 $profiling_table .= '</tbody></table>' . "\n";
262 $profiling_table .= <<<EOT
263 <script type="text/javascript">
264 pma_token = '$pma_token';
265 url_query = '$url_query';
266 </script>
267 EOT;
268 $profiling_table .= "</div>";
269 $profiling_table .= "<div class='clearfloat'></div>";
271 //require_once 'libraries/chart.lib.php';
272 $profiling_table .= '<div id="profilingChartData" style="display:none;">';
273 $profiling_table .= json_encode($chart_json);
274 $profiling_table .= '</div>';
275 $profiling_table .= '<div id="profilingchart" style="display:none;">';
276 $profiling_table .= '</div>';
277 $profiling_table .= '<script type="text/javascript">';
278 $profiling_table .= "AJAX.registerOnload('sql.js', function () {";
279 $profiling_table .= 'makeProfilingChart();';
280 $profiling_table .= 'initProfilingTables();';
281 $profiling_table .= '});';
282 $profiling_table .= '</script>';
283 $profiling_table .= '</fieldset>' . "\n";
284 } else {
285 $profiling_table = null;
287 return $profiling_table;
291 * Function to get HTML for detailed profiling results table, profiling stats, and
292 * $chart_json for displaying the chart.
294 * @param array $profiling_results profiling results
296 * @return mixed
298 function PMA_analyzeAndGetTableHtmlForProfilingResults(
299 $profiling_results
301 $profiling_stats = array(
302 'total_time' => 0,
303 'states' => array(),
305 $chart_json = Array();
306 $i = 1;
307 $table = '';
308 foreach ($profiling_results as $one_result) {
309 if (isset($profiling_stats['states'][ucwords($one_result['Status'])])) {
310 $states = $profiling_stats['states'];
311 $states[ucwords($one_result['Status'])]['total_time']
312 += $one_result['Duration'];
313 $states[ucwords($one_result['Status'])]['calls']++;
314 } else {
315 $profiling_stats['states'][ucwords($one_result['Status'])] = array(
316 'total_time' => $one_result['Duration'],
317 'calls' => 1,
320 $profiling_stats['total_time'] += $one_result['Duration'];
322 $table .= ' <tr>' . "\n";
323 $table .= '<td>' . $i++ . '</td>' . "\n";
324 $table .= '<td>' . ucwords($one_result['Status'])
325 . '</td>' . "\n";
326 $table .= '<td class="right">'
327 . (PMA_Util::formatNumber($one_result['Duration'], 3, 1))
328 . 's<span style="display:none;" class="rawvalue">'
329 . $one_result['Duration'] . '</span></td>' . "\n";
330 if (isset($chart_json[ucwords($one_result['Status'])])) {
331 $chart_json[ucwords($one_result['Status'])]
332 += $one_result['Duration'];
333 } else {
334 $chart_json[ucwords($one_result['Status'])]
335 = $one_result['Duration'];
338 return array($table, $chart_json, $profiling_stats);
342 * Function to get HTML for summary by state table
344 * @param array $profiling_stats profiling stats
346 * @return string $table html for the table
348 function PMA_getTableHtmlForProfilingSummaryByState($profiling_stats)
350 $table = '';
351 foreach ($profiling_stats['states'] as $name => $stats) {
352 $table .= ' <tr>' . "\n";
353 $table .= '<td>' . $name . '</td>' . "\n";
354 $table .= '<td align="right">'
355 . PMA_Util::formatNumber($stats['total_time'], 3, 1)
356 . 's<span style="display:none;" class="rawvalue">'
357 . $stats['total_time'] . '</span></td>' . "\n";
358 $table .= '<td align="right">'
359 . PMA_Util::formatNumber(
360 100 * ($stats['total_time'] / $profiling_stats['total_time']),
361 0, 2
363 . '%</td>' . "\n";
364 $table .= '<td align="right">' . $stats['calls'] . '</td>'
365 . "\n";
366 $table .= '<td align="right">'
367 . PMA_Util::formatNumber(
368 $stats['total_time'] / $stats['calls'], 3, 1
370 . 's<span style="display:none;" class="rawvalue">'
371 . number_format($stats['total_time'] / $stats['calls'], 8, '.', '')
372 . '</span></td>' . "\n";
373 $table .= ' </tr>' . "\n";
375 return $table;
379 * Get the HTML for the enum column dropdown
380 * During grid edit, if we have a enum field, returns the html for the
381 * dropdown
383 * @param string $db current database
384 * @param string $table current table
385 * @param string $column current column
386 * @param string $curr_value currently selected value
388 * @return string $dropdown html for the dropdown
390 function PMA_getHtmlForEnumColumnDropdown($db, $table, $column, $curr_value)
392 $values = PMA_getValuesForColumn($db, $table, $column);
393 $dropdown = '<option value="">&nbsp;</option>';
394 $dropdown .= PMA_getHtmlForOptionsList($values, array($curr_value));
395 $dropdown = '<select>' . $dropdown . '</select>';
396 return $dropdown;
400 * Get the HTML for the set column dropdown
401 * During grid edit, if we have a set field, returns the html for the
402 * dropdown
404 * @param string $db current database
405 * @param string $table current table
406 * @param string $column current column
407 * @param string $curr_value currently selected value
409 * @return string $dropdown html for the set column
411 function PMA_getHtmlForSetColumn($db, $table, $column, $curr_value)
413 $values = PMA_getValuesForColumn($db, $table, $column);
414 $dropdown = '';
416 //converts characters of $curr_value to HTML entities
417 $converted_curr_value = htmlentities(
418 $curr_value, ENT_COMPAT, "UTF-8"
421 $selected_values = explode(',', $converted_curr_value);
422 $dropdown .= PMA_getHtmlForOptionsList($values, $selected_values);
424 $select_size = (sizeof($values) > 10) ? 10 : sizeof($values);
425 $dropdown = '<select multiple="multiple" size="' . $select_size . '">'
426 . $dropdown . '</select>';
428 return $dropdown;
432 * Get all the values for a enum column or set column in a table
434 * @param string $db current database
435 * @param string $table current table
436 * @param string $column current column
438 * @return array $values array containing the value list for the column
440 function PMA_getValuesForColumn($db, $table, $column)
442 $field_info_query = $GLOBALS['dbi']->getColumnsSql($db, $table, $column);
444 $field_info_result = $GLOBALS['dbi']->fetchResult(
445 $field_info_query, null, null, null, PMA_DatabaseInterface::QUERY_STORE
448 $values = PMA_Util::parseEnumSetValues($field_info_result[0]['Type']);
450 return $values;
454 * Get HTML for options list
456 * @param array $values set of values
457 * @param array $selected_values currently selected values
459 * @return string $options HTML for options list
461 function PMA_getHtmlForOptionsList($values, $selected_values)
463 $options = '';
464 foreach ($values as $value) {
465 $options .= '<option value="' . $value . '"';
466 if (in_array($value, $selected_values, true)) {
467 $options .= ' selected="selected" ';
469 $options .= '>' . $value . '</option>';
471 return $options;
475 * Function to get html for bookmark support if bookmarks are enabled. Else will
476 * return null
478 * @param array $displayParts the parts to display
479 * @param bool $cfgBookmark configuration setting for bookmarking
480 * @param string $sql_query sql query
481 * @param string $db current database
482 * @param string $table current table
483 * @param string $complete_query complete query
484 * @param string $bkm_user bookmarking user
486 * @return string $html
488 function PMA_getHtmlForBookmark($displayParts, $cfgBookmark, $sql_query, $db,
489 $table, $complete_query, $bkm_user
491 if ($displayParts['bkm_form'] == '1'
492 && (! empty($cfgBookmark) && empty($_GET['id_bookmark']))
493 && ! empty($sql_query)
495 $goto = 'sql.php'
496 . PMA_URL_getCommon(
497 array(
498 'db' => $db,
499 'table' => $table,
500 'sql_query' => $sql_query,
501 'id_bookmark'=> 1,
504 $bkm_sql_query = urlencode(
505 isset($complete_query) ? $complete_query : $sql_query
507 $html = '<form action="sql.php" method="post"'
508 . ' onsubmit="return ! emptyCheckTheField(this,'
509 . '\'bkm_fields[bkm_label]\');"'
510 . ' class="bookmarkQueryForm print_ignore">';
511 $html .= PMA_URL_getHiddenInputs();
512 $html .= '<input type="hidden" name="db"'
513 . ' value="' . htmlspecialchars($db) . '" />';
514 $html .= '<input type="hidden" name="goto" value="' . $goto . '" />';
515 $html .= '<input type="hidden" name="bkm_fields[bkm_database]"'
516 . ' value="' . htmlspecialchars($db) . '" />';
517 $html .= '<input type="hidden" name="bkm_fields[bkm_user]"'
518 . ' value="' . $bkm_user . '" />';
519 $html .= '<input type="hidden" name="bkm_fields[bkm_sql_query]"'
520 . ' value="'
521 . $bkm_sql_query
522 . '" />';
523 $html .= '<fieldset>';
524 $html .= '<legend>';
525 $html .= PMA_Util::getIcon(
526 'b_bookmark.png', __('Bookmark this SQL query'), true
528 $html .= '</legend>';
529 $html .= '<div class="formelement">';
530 $html .= '<label>' . __('Label:') . '</label>';
531 $html .= '<input type="text" name="bkm_fields[bkm_label]" value="" />';
532 $html .= '</div>';
533 $html .= '<div class="formelement">';
534 $html .= '<input type="checkbox" name="bkm_all_users" value="true" />';
535 $html .= '<label>' . __('Let every user access this bookmark') . '</label>';
536 $html .= '</div>';
537 $html .= '<div class="clearfloat"></div>';
538 $html .= '</fieldset>';
539 $html .= '<fieldset class="tblFooters">';
540 $html .= '<input type="hidden" name="store_bkm" value="1" />';
541 $html .= '<input type="submit"'
542 . ' value="' . __('Bookmark this SQL query') . '" />';
543 $html .= '</fieldset>';
544 $html .= '</form>';
546 } else {
547 $html = null;
550 return $html;
554 * Function to check whether to remember the sorting order or not
556 * @param array $analyzed_sql_results the analyzed query and other variables set
557 * after analyzing the query
559 * @return boolean
561 function PMA_isRememberSortingOrder($analyzed_sql_results)
563 return $GLOBALS['cfg']['RememberSorting']
564 && ! ($analyzed_sql_results['is_count']
565 || $analyzed_sql_results['is_export']
566 || $analyzed_sql_results['is_func']
567 || $analyzed_sql_results['is_analyse'])
568 && $analyzed_sql_results['select_from']
569 && ((empty($analyzed_sql_results['select_expr']))
570 || (count($analyzed_sql_results['select_expr'] == 1)
571 && ($analyzed_sql_results['select_expr'][0] == '*')))
572 && count($analyzed_sql_results['select_tables']) == 1;
576 * Function to check whether the LIMIT clause should be appended or not
578 * @param array $analyzed_sql_results the analyzed query and other variables set
579 * after analyzing the query
581 * @return boolean
583 function PMA_isAppendLimitClause($analyzed_sql_results)
585 return ($_SESSION['tmpval']['max_rows'] != 'all')
586 && ! ($analyzed_sql_results['is_export']
587 || $analyzed_sql_results['is_analyse'])
588 && ($analyzed_sql_results['select_from']
589 || $analyzed_sql_results['is_subquery'])
590 && empty($analyzed_sql_results['limit']);
594 * Function to check whether this query is for just browsing
596 * @param array $analyzed_sql_results the analyzed query and other variables set
597 * after analyzing the query
598 * @param boolean $find_real_end whether the real end should be found
600 * @return boolean
602 function PMA_isJustBrowsing($analyzed_sql_results, $find_real_end)
604 return ! $analyzed_sql_results['is_group']
605 && ! $analyzed_sql_results['is_func']
606 && empty($analyzed_sql_results['union'])
607 && empty($analyzed_sql_results['distinct'])
608 && $analyzed_sql_results['select_from']
609 && (count($analyzed_sql_results['select_tables']) <= 1)
610 && (empty($analyzed_sql_results['statement']->where)
611 || (count($analyzed_sql_results['statement']->where) == 1
612 && $analyzed_sql_results['statement']->where[0]->expr ==='1'))
613 && empty($analyzed_sql_results['group'])
614 && ! isset($find_real_end)
615 && ! $analyzed_sql_results['is_subquery']
616 && empty($analyzed_sql_results['having']);
620 * Function to check whether the related transformation information should be deleted
622 * @param array $analyzed_sql_results the analyzed query and other variables set
623 * after analyzing the query
625 * @return boolean
627 function PMA_isDeleteTransformationInfo($analyzed_sql_results)
629 return !empty($analyzed_sql_results['querytype'])
630 && (($analyzed_sql_results['querytype'] == 'ALTER')
631 || ($analyzed_sql_results['querytype'] == 'DROP'));
635 * Function to check whether the user has rights to drop the database
637 * @param array $analyzed_sql_results the analyzed query and other variables set
638 * after analyzing the query
639 * @param boolean $allowUserDropDatabase whether the user is allowed to drop db
640 * @param boolean $is_superuser whether this user is a superuser
642 * @return boolean
644 function PMA_hasNoRightsToDropDatabase($analyzed_sql_results,
645 $allowUserDropDatabase, $is_superuser
647 return ! defined('PMA_CHK_DROP')
648 && ! $allowUserDropDatabase
649 && $analyzed_sql_results['drop_database']
650 && ! $is_superuser;
654 * Function to set a column property
656 * @param PMA_Table $pmatable PMA_Table instance
657 * @param string $request_index col_order|col_visib
659 * @return boolean $retval
661 function PMA_setColumnProperty($pmatable, $request_index)
663 $property_value = explode(',', $_REQUEST[$request_index]);
664 switch($request_index) {
665 case 'col_order':
666 $property_to_set = PMA_Table::PROP_COLUMN_ORDER;
667 break;
668 case 'col_visib':
669 $property_to_set = PMA_Table::PROP_COLUMN_VISIB;
670 break;
671 default:
672 $property_to_set = '';
674 $retval = $pmatable->setUiProp(
675 $property_to_set,
676 $property_value,
677 $_REQUEST['table_create_time']
679 if (gettype($retval) != 'boolean') {
680 $response = PMA_Response::getInstance();
681 $response->isSuccess(false);
682 $response->addJSON('message', $retval->getString());
683 exit;
686 return $retval;
690 * Function to check the request for setting the column order or visibility
692 * @param String $table the current table
693 * @param String $db the current database
695 * @return void
697 function PMA_setColumnOrderOrVisibility($table, $db)
699 $pmatable = new PMA_Table($table, $db);
700 $retval = false;
702 // set column order
703 if (isset($_REQUEST['col_order'])) {
704 $retval = PMA_setColumnProperty($pmatable, 'col_order');
707 // set column visibility
708 if ($retval === true && isset($_REQUEST['col_visib'])) {
709 $retval = PMA_setColumnProperty($pmatable, 'col_visib');
712 $response = PMA_Response::getInstance();
713 $response->isSuccess($retval == true);
714 exit;
718 * Function to add a bookmark
720 * @param String $pmaAbsoluteUri absolute URI
721 * @param String $goto goto page URL
723 * @return void
725 function PMA_addBookmark($pmaAbsoluteUri, $goto)
727 $result = PMA_Bookmark_save(
728 $_POST['bkm_fields'],
729 (isset($_POST['bkm_all_users'])
730 && $_POST['bkm_all_users'] == 'true' ? true : false
733 $response = PMA_Response::getInstance();
734 if ($response->isAjax()) {
735 if ($result) {
736 $msg = PMA_message::success(__('Bookmark %s has been created.'));
737 $msg->addParam($_POST['bkm_fields']['bkm_label']);
738 $response->addJSON('message', $msg);
739 } else {
740 $msg = PMA_message::error(__('Bookmark not created!'));
741 $response->isSuccess(false);
742 $response->addJSON('message', $msg);
744 exit;
745 } else {
746 // go back to sql.php to redisplay query; do not use &amp; in this case:
748 * @todo In which scenario does this happen?
750 PMA_sendHeaderLocation(
751 $pmaAbsoluteUri . $goto
752 . '&label=' . $_POST['bkm_fields']['bkm_label']
758 * Function to find the real end of rows
760 * @param String $db the current database
761 * @param String $table the current table
763 * @return mixed the number of rows if "retain" param is true, otherwise true
765 function PMA_findRealEndOfRows($db, $table)
767 $unlim_num_rows = $GLOBALS['dbi']->getTable($db, $table)->countRecords(true);
768 $_SESSION['tmpval']['pos'] = PMA_getStartPosToDisplayRow($unlim_num_rows);
770 return $unlim_num_rows;
774 * Function to get values for the relational columns
776 * @param String $db the current database
777 * @param String $table the current table
779 * @return void
781 function PMA_getRelationalValues($db, $table)
783 $column = $_REQUEST['column'];
784 if ($_SESSION['tmpval']['relational_display'] == 'D'
785 && isset($_REQUEST['relation_key_or_display_column'])
786 && $_REQUEST['relation_key_or_display_column']
788 $curr_value = $_REQUEST['relation_key_or_display_column'];
789 } else {
790 $curr_value = $_REQUEST['curr_value'];
792 $dropdown = PMA_getHtmlForRelationalColumnDropdown(
793 $db, $table, $column, $curr_value
795 $response = PMA_Response::getInstance();
796 $response->addJSON('dropdown', $dropdown);
797 exit;
801 * Function to get values for Enum or Set Columns
803 * @param String $db the current database
804 * @param String $table the current table
805 * @param String $columnType whether enum or set
807 * @return void
809 function PMA_getEnumOrSetValues($db, $table, $columnType)
811 $column = $_REQUEST['column'];
812 $curr_value = $_REQUEST['curr_value'];
813 $response = PMA_Response::getInstance();
814 if ($columnType == "enum") {
815 $dropdown = PMA_getHtmlForEnumColumnDropdown(
816 $db, $table, $column, $curr_value
818 $response->addJSON('dropdown', $dropdown);
819 } else {
820 $select = PMA_getHtmlForSetColumn($db, $table, $column, $curr_value);
821 $response->addJSON('select', $select);
823 exit;
827 * Function to get the default sql query for browsing page
829 * @param String $db the current database
830 * @param String $table the current table
832 * @return String $sql_query the default $sql_query for browse page
834 function PMA_getDefaultSqlQueryForBrowse($db, $table)
836 include_once 'libraries/bookmark.lib.php';
837 $book_sql_query = PMA_Bookmark_get(
838 $db,
839 '\'' . PMA_Util::sqlAddSlashes($table) . '\'',
840 'label',
841 false,
842 true
845 if (! empty($book_sql_query)) {
846 $GLOBALS['using_bookmark_message'] = PMA_message::notice(
847 __('Using bookmark "%s" as default browse query.')
849 $GLOBALS['using_bookmark_message']->addParam($table);
850 $GLOBALS['using_bookmark_message']->addMessage(
851 PMA_Util::showDocu('faq', 'faq6-22')
853 $sql_query = $book_sql_query;
854 } else {
856 $defaultOrderByClause = '';
858 if (isset($GLOBALS['cfg']['TablePrimaryKeyOrder'])
859 && ($GLOBALS['cfg']['TablePrimaryKeyOrder'] !== 'NONE')
862 $primaryKey = null;
863 $primary = PMA_Index::getPrimary($table, $db);
865 if ($primary !== false) {
867 $primarycols = $primary->getColumns();
869 foreach ($primarycols as $col) {
870 $primaryKey = $col->getName();
871 break;
874 if ($primaryKey != null) {
875 $defaultOrderByClause = ' ORDER BY '
876 . PMA_Util::backquote($table) . '.'
877 . PMA_Util::backquote($primaryKey) . ' '
878 . $GLOBALS['cfg']['TablePrimaryKeyOrder'];
885 $sql_query = 'SELECT * FROM ' . PMA_Util::backquote($table)
886 . $defaultOrderByClause;
889 unset($book_sql_query);
891 return $sql_query;
895 * Responds an error when an error happens when executing the query
897 * @param boolean $is_gotofile whether goto file or not
898 * @param String $error error after executing the query
899 * @param String $full_sql_query full sql query
901 * @return void
903 function PMA_handleQueryExecuteError($is_gotofile, $error, $full_sql_query)
905 if ($is_gotofile) {
906 $message = PMA_Message::rawError($error);
907 $response = PMA_Response::getInstance();
908 $response->isSuccess(false);
909 $response->addJSON('message', $message);
910 } else {
911 PMA_Util::mysqlDie($error, $full_sql_query, '', '');
913 exit;
917 * Function to store the query as a bookmark
919 * @param String $db the current database
920 * @param String $bkm_user the bookmarking user
921 * @param String $sql_query_for_bookmark the query to be stored in bookmark
922 * @param String $bkm_label bookmark label
923 * @param boolean $bkm_replace whether to replace existing bookmarks
925 * @return void
927 function PMA_storeTheQueryAsBookmark($db, $bkm_user, $sql_query_for_bookmark,
928 $bkm_label, $bkm_replace
930 include_once 'libraries/bookmark.lib.php';
931 $bfields = array(
932 'bkm_database' => $db,
933 'bkm_user' => $bkm_user,
934 'bkm_sql_query' => urlencode($sql_query_for_bookmark),
935 'bkm_label' => $bkm_label
938 // Should we replace bookmark?
939 if (isset($bkm_replace)) {
940 $bookmarks = PMA_Bookmark_getList($db);
941 foreach ($bookmarks as $key => $val) {
942 if ($val['label'] == $bkm_label) {
943 PMA_Bookmark_delete($key);
948 PMA_Bookmark_save($bfields, isset($_POST['bkm_all_users']));
953 * Function to execute the SQL query and set the execution time
955 * @param String $full_sql_query the full sql query
957 * @return mixed $result the results after running the query
959 function PMA_executeQueryAndStoreResults($full_sql_query)
961 // close session in case the query takes too long
962 session_write_close();
964 // Measure query time.
965 $querytime_before = array_sum(explode(' ', microtime()));
967 $result = @$GLOBALS['dbi']->tryQuery(
968 $full_sql_query, null, PMA_DatabaseInterface::QUERY_STORE
970 $querytime_after = array_sum(explode(' ', microtime()));
972 // reopen session
973 session_start();
975 $GLOBALS['querytime'] = $querytime_after - $querytime_before;
977 return $result;
981 * Function to get the affected or changed number of rows after executing a query
983 * @param boolean $is_affected whether the query affected a table
984 * @param mixed $result results of executing the query
986 * @return int $num_rows number of rows affected or changed
988 function PMA_getNumberOfRowsAffectedOrChanged($is_affected, $result)
990 if (! $is_affected) {
991 $num_rows = ($result) ? @$GLOBALS['dbi']->numRows($result) : 0;
992 } else {
993 $num_rows = @$GLOBALS['dbi']->affectedRows();
996 return $num_rows;
1000 * Checks if the current database has changed
1001 * This could happen if the user sends a query like "USE `database`;"
1003 * @param String $db the database in the query
1005 * @return int $reload whether to reload the navigation(1) or not(0)
1007 function PMA_hasCurrentDbChanged($db)
1009 if (/*overload*/mb_strlen($db)) {
1010 $current_db = $GLOBALS['dbi']->fetchValue('SELECT DATABASE()');
1011 // $current_db is false, except when a USE statement was sent
1012 return ($current_db != false) && ($db !== $current_db);
1015 return false;
1019 * If a table, database or column gets dropped, clean comments.
1021 * @param String $db current database
1022 * @param String $table current table
1023 * @param String $column current column
1024 * @param bool $purge whether purge set or not
1026 * @return array $extra_data
1028 function PMA_cleanupRelations($db, $table, $column, $purge)
1030 include_once 'libraries/relation_cleanup.lib.php';
1032 if (! empty($purge) && /*overload*/mb_strlen($db)) {
1033 if (/*overload*/mb_strlen($table)) {
1034 if (isset($column) && /*overload*/mb_strlen($column)) {
1035 PMA_relationsCleanupColumn($db, $table, $column);
1036 } else {
1037 PMA_relationsCleanupTable($db, $table);
1039 } else {
1040 PMA_relationsCleanupDatabase($db);
1046 * Function to count the total number of rows for the same 'SELECT' query without
1047 * the 'LIMIT' clause that may have been programatically added
1049 * @param int $num_rows number of rows affected/changed by the query
1050 * @param bool $justBrowsing whether just browsing or not
1051 * @param string $db the current database
1052 * @param string $table the current table
1053 * @param array $analyzed_sql_results the analyzed query and other variables set
1054 * after analyzing the query
1056 * @return int $unlim_num_rows unlimited number of rows
1058 function PMA_countQueryResults(
1059 $num_rows, $justBrowsing, $db, $table, $analyzed_sql_results
1062 if (!PMA_isAppendLimitClause($analyzed_sql_results)) {
1063 // if we did not append a limit, set this to get a correct
1064 // "Showing rows..." message
1065 // $_SESSION['tmpval']['max_rows'] = 'all';
1066 $unlim_num_rows = $num_rows;
1067 } elseif ($analyzed_sql_results['querytype'] == 'SELECT'
1068 || $analyzed_sql_results['is_subquery']
1070 // c o u n t q u e r y
1072 // If we are "just browsing", there is only one table,
1073 // and no WHERE clause (or just 'WHERE 1 '),
1074 // we do a quick count (which uses MaxExactCount) because
1075 // SQL_CALC_FOUND_ROWS is not quick on large InnoDB tables
1077 // However, do not count again if we did it previously
1078 // due to $find_real_end == true
1079 if ($justBrowsing) {
1080 // Get row count (is approximate for InnoDB)
1081 $unlim_num_rows = $GLOBALS['dbi']->getTable($db, $table)->countRecords();
1083 * @todo Can we know at this point that this is InnoDB,
1084 * (in this case there would be no need for getting
1085 * an exact count)?
1087 if ($unlim_num_rows < $GLOBALS['cfg']['MaxExactCount']) {
1088 // Get the exact count if approximate count
1089 // is less than MaxExactCount
1091 * @todo In countRecords(), MaxExactCount is also verified,
1092 * so can we avoid checking it twice?
1094 $unlim_num_rows = $GLOBALS['dbi']->getTable($db, $table)
1095 ->countRecords(true);
1098 } else {
1100 // The SQL_CALC_FOUND_ROWS option of the SELECT statement is used.
1102 // For UNION statements, only a SQL_CALC_FOUND_ROWS is required
1103 // after the first SELECT.
1105 $count_query = SqlParser\Utils\Query::replaceClause(
1106 $analyzed_sql_results['statement'],
1107 $analyzed_sql_results['parser']->list,
1108 'SELECT SQL_CALC_FOUND_ROWS',
1109 null,
1110 true
1113 // Another LIMIT clause is added to avoid long delays.
1114 // A complete result will be returned anyway, but the LIMIT would
1115 // stop the query as soon as the result that is required has been
1116 // computed.
1118 if (empty($analyzed_sql_results['union'])) {
1119 $count_query .= ' LIMIT 1';
1122 // Running the count query.
1123 $GLOBALS['dbi']->tryQuery($count_query);
1125 $unlim_num_rows = $GLOBALS['dbi']->fetchValue('SELECT FOUND_ROWS()');
1126 } // end else "just browsing"
1127 } else {// not $is_select
1128 $unlim_num_rows = 0;
1131 return $unlim_num_rows;
1135 * Function to handle all aspects relating to executing the query
1137 * @param array $analyzed_sql_results analyzed sql results
1138 * @param String $full_sql_query full sql query
1139 * @param boolean $is_gotofile whether to go to a file
1140 * @param String $db current database
1141 * @param String $table current table
1142 * @param boolean $find_real_end whether to find the real end
1143 * @param String $sql_query_for_bookmark sql query to be stored as bookmark
1144 * @param array $extra_data extra data
1146 * @return mixed
1148 function PMA_executeTheQuery($analyzed_sql_results, $full_sql_query, $is_gotofile,
1149 $db, $table, $find_real_end, $sql_query_for_bookmark, $extra_data
1151 $response = PMA_Response::getInstance();
1152 $response->getHeader()->getMenu()->setTable($table);
1154 // Only if we ask to see the php code
1155 if (isset($GLOBALS['show_as_php'])) {
1156 $result = null;
1157 $num_rows = 0;
1158 $unlim_num_rows = 0;
1159 } else { // If we don't ask to see the php code
1160 if (isset($_SESSION['profiling']) && PMA_Util::profilingSupported()) {
1161 $GLOBALS['dbi']->query('SET PROFILING=1;');
1164 $result = PMA_executeQueryAndStoreResults($full_sql_query);
1166 // Displays an error message if required and stop parsing the script
1167 $error = $GLOBALS['dbi']->getError();
1168 if ($error) {
1169 PMA_handleQueryExecuteError($is_gotofile, $error, $full_sql_query);
1172 // If there are no errors and bookmarklabel was given,
1173 // store the query as a bookmark
1174 if (! empty($_POST['bkm_label']) && ! empty($sql_query_for_bookmark)) {
1175 $cfgBookmark = PMA_Bookmark_getParams();
1176 PMA_storeTheQueryAsBookmark(
1177 $db, $cfgBookmark['user'],
1178 $sql_query_for_bookmark, $_POST['bkm_label'],
1179 isset($_POST['bkm_replace']) ? $_POST['bkm_replace'] : null
1181 } // end store bookmarks
1183 // Gets the number of rows affected/returned
1184 // (This must be done immediately after the query because
1185 // mysql_affected_rows() reports about the last query done)
1186 $num_rows = PMA_getNumberOfRowsAffectedOrChanged(
1187 $analyzed_sql_results['is_affected'], $result
1190 // Grabs the profiling results
1191 if (isset($_SESSION['profiling']) && PMA_Util::profilingSupported()) {
1192 $profiling_results = $GLOBALS['dbi']->fetchResult('SHOW PROFILE;');
1195 $justBrowsing = PMA_isJustBrowsing(
1196 $analyzed_sql_results, isset($find_real_end) ? $find_real_end : null
1199 $unlim_num_rows = PMA_countQueryResults(
1200 $num_rows, $justBrowsing, $db, $table, $analyzed_sql_results
1203 PMA_cleanupRelations(
1204 isset($db) ? $db : '',
1205 isset($table) ? $table : '',
1206 isset($_REQUEST['dropped_column']) ? $_REQUEST['dropped_column'] : null,
1207 isset($_REQUEST['purge']) ? $_REQUEST['purge'] : null
1210 if (isset($_REQUEST['dropped_column'])
1211 && /*overload*/mb_strlen($db)
1212 && /*overload*/mb_strlen($table)
1214 // to refresh the list of indexes (Ajax mode)
1215 $extra_data['indexes_list'] = PMA_Index::getHtmlForIndexes($table, $db);
1219 return array($result, $num_rows, $unlim_num_rows,
1220 isset($profiling_results) ? $profiling_results : null, $extra_data
1224 * Delete related tranformatioinformationn information
1226 * @param String $db current database
1227 * @param String $table current table
1228 * @param array $analyzed_sql_results analyzed sql results
1230 * @return void
1232 function PMA_deleteTransformationInfo($db, $table, $analyzed_sql_results)
1234 include_once 'libraries/transformations.lib.php';
1235 $statement = $analyzed_sql_results['statement'];
1236 if ($statement instanceof SqlParser\Statements\AlterStatement) {
1237 if (!empty($statement->altered[0])
1238 && $statement->altered[0]->options->has('DROP')
1240 if (!empty($statement->altered[0]->field->column)) {
1241 PMA_clearTransformations(
1242 $db,
1243 $table,
1244 $statement->altered[0]->field->column
1248 } elseif ($statement instanceof SqlParser\Statements\DropStatement) {
1249 PMA_clearTransformations($db, $table);
1254 * Function to get the message for the no rows returned case
1256 * @param string $message_to_show message to show
1257 * @param array $analyzed_sql_results analyzed sql results
1258 * @param int $num_rows number of rows
1260 * @return string $message
1262 function PMA_getMessageForNoRowsReturned($message_to_show,
1263 $analyzed_sql_results, $num_rows
1265 if ($analyzed_sql_results['querytype'] == 'DELETE"') {
1266 $message = PMA_Message::getMessageForDeletedRows($num_rows);
1267 } elseif ($analyzed_sql_results['is_insert']) {
1268 if ($analyzed_sql_results['querytype'] == 'REPLACE') {
1269 // For REPLACE we get DELETED + INSERTED row count,
1270 // so we have to call it affected
1271 $message = PMA_Message::getMessageForAffectedRows($num_rows);
1272 } else {
1273 $message = PMA_Message::getMessageForInsertedRows($num_rows);
1275 $insert_id = $GLOBALS['dbi']->insertId();
1276 if ($insert_id != 0) {
1277 // insert_id is id of FIRST record inserted in one insert,
1278 // so if we inserted multiple rows, we had to increment this
1279 $message->addMessage('[br]');
1280 // need to use a temporary because the Message class
1281 // currently supports adding parameters only to the first
1282 // message
1283 $_inserted = PMA_Message::notice(__('Inserted row id: %1$d'));
1284 $_inserted->addParam($insert_id + $num_rows - 1);
1285 $message->addMessage($_inserted);
1287 } elseif ($analyzed_sql_results['is_affected']) {
1288 $message = PMA_Message::getMessageForAffectedRows($num_rows);
1290 // Ok, here is an explanation for the !$is_select.
1291 // The form generated by sql_query_form.lib.php
1292 // and db_sql.php has many submit buttons
1293 // on the same form, and some confusion arises from the
1294 // fact that $message_to_show is sent for every case.
1295 // The $message_to_show containing a success message and sent with
1296 // the form should not have priority over errors
1297 } elseif (! empty($message_to_show)
1298 && $analyzed_sql_results['querytype'] != 'SELECT'
1300 $message = PMA_Message::rawSuccess(htmlspecialchars($message_to_show));
1301 } elseif (! empty($GLOBALS['show_as_php'])) {
1302 $message = PMA_Message::success(__('Showing as PHP code'));
1303 } elseif (isset($GLOBALS['show_as_php'])) {
1304 /* User disable showing as PHP, query is only displayed */
1305 $message = PMA_Message::notice(__('Showing SQL query'));
1306 } else {
1307 $message = PMA_Message::success(
1308 __('MySQL returned an empty result set (i.e. zero rows).')
1312 if (isset($GLOBALS['querytime'])) {
1313 $_querytime = PMA_Message::notice(
1314 '(' . __('Query took %01.4f seconds.') . ')'
1316 $_querytime->addParam($GLOBALS['querytime']);
1317 $message->addMessage($_querytime);
1320 // In case of ROLLBACK, notify the user.
1321 if (isset($_REQUEST['rollback_query'])) {
1322 $message->addMessage(__('[ROLLBACK occurred.]'));
1325 return $message;
1329 * Function to respond back when the query returns zero rows
1330 * This method is called
1331 * 1-> When browsing an empty table
1332 * 2-> When executing a query on a non empty table which returns zero results
1333 * 3-> When executing a query on an empty table
1334 * 4-> When executing an INSERT, UPDATE, DELETE query from the SQL tab
1335 * 5-> When deleting a row from BROWSE tab
1336 * 6-> When searching using the SEARCH tab which returns zero results
1337 * 7-> When changing the structure of the table except change operation
1339 * @param array $analyzed_sql_results analyzed sql results
1340 * @param string $db current database
1341 * @param string $table current table
1342 * @param string $message_to_show message to show
1343 * @param int $num_rows number of rows
1344 * @param PMA_DisplayResults $displayResultsObject DisplayResult instance
1345 * @param array $extra_data extra data
1347 * @return string html
1349 function PMA_getQueryResponseForNoResultsReturned($analyzed_sql_results, $db,
1350 $table, $message_to_show, $num_rows, $displayResultsObject, $extra_data
1352 if (PMA_isDeleteTransformationInfo($analyzed_sql_results)) {
1353 PMA_deleteTransformationInfo($db, $table, $analyzed_sql_results);
1356 $message = PMA_getMessageForNoRowsReturned(
1357 isset($message_to_show) ? $message_to_show : null,
1358 $analyzed_sql_results, $num_rows
1361 $html_output = '';
1362 if (!isset($GLOBALS['show_as_php'])) {
1364 if (! empty($GLOBALS['reload'])) {
1365 $extra_data['reload'] = 1;
1366 $extra_data['db'] = $GLOBALS['db'];
1369 $html_message = PMA_Util::getMessage(
1370 $message, $GLOBALS['sql_query'], 'success'
1372 $html_output .= $html_message;
1374 // For ajax requests add message and sql_query as JSON
1375 if (empty($_REQUEST['ajax_page_request'])) {
1376 $extra_data['message'] = $message;
1377 if ($GLOBALS['cfg']['ShowSQL']) {
1378 $extra_data['sql_query'] = $html_message;
1382 $response = PMA_Response::getInstance();
1383 $response->addJSON(isset($extra_data) ? $extra_data : array());
1385 if (!empty($analyzed_sql_results['is_select'])) {
1386 $html_output .= $displayResultsObject->getCreateViewQueryResultOp(
1387 $analyzed_sql_results
1392 return $html_output;
1396 * Function to send response for ajax grid edit
1398 * @param object $result result of the executed query
1400 * @return void
1402 function PMA_sendResponseForGridEdit($result)
1404 $row = $GLOBALS['dbi']->fetchRow($result);
1405 $field_flags = $GLOBALS['dbi']->fieldFlags($result, 0);
1406 if (stristr($field_flags, PMA_DisplayResults::BINARY_FIELD)) {
1407 $row[0] = bin2hex($row[0]);
1409 $response = PMA_Response::getInstance();
1410 $response->addJSON('value', $row[0]);
1411 exit;
1415 * Function to get html for the sql query results div
1417 * @param string $previous_update_query_html html for the previously
1418 * executed query
1419 * @param string $profiling_chart_html html for profiling
1420 * @param PMA_Message $missing_unique_column_msg message for the missing
1421 * unique column
1422 * @param PMA_Message $bookmark_created_msg message for bookmark creation
1423 * @param string $table_html html for the table for
1424 * displaying sql results
1425 * @param string $indexes_problems_html html for displaying errors
1426 * in indexes
1427 * @param string $bookmark_support_html html for displaying bookmark form
1429 * @return string $html_output
1431 function PMA_getHtmlForSqlQueryResults($previous_update_query_html,
1432 $profiling_chart_html, $missing_unique_column_msg, $bookmark_created_msg,
1433 $table_html, $indexes_problems_html, $bookmark_support_html
1435 //begin the sqlqueryresults div here. container div
1436 $html_output = '<div class="sqlqueryresults ajax">';
1437 $html_output .= isset($previous_update_query_html)
1438 ? $previous_update_query_html : '';
1439 $html_output .= isset($profiling_chart_html) ? $profiling_chart_html : '';
1440 $html_output .= isset($missing_unique_column_msg)
1441 ? $missing_unique_column_msg->getDisplay() : '';
1442 $html_output .= isset($bookmark_created_msg)
1443 ? $bookmark_created_msg->getDisplay() : '';
1444 $html_output .= $table_html;
1445 $html_output .= isset($indexes_problems_html) ? $indexes_problems_html : '';
1446 $html_output .= isset($bookmark_support_html) ? $bookmark_support_html : '';
1447 $html_output .= '</div>'; // end sqlqueryresults div
1449 return $html_output;
1453 * Returns a message for successful creation of a bookmark or null if a bookmark
1454 * was not created
1456 * @return PMA_message $bookmark_created_msg
1458 function PMA_getBookmarkCreatedMessage()
1460 if (isset($_GET['label'])) {
1461 $bookmark_created_msg = PMA_message::success(
1462 __('Bookmark %s has been created.')
1464 $bookmark_created_msg->addParam($_GET['label']);
1465 } else {
1466 $bookmark_created_msg = null;
1469 return $bookmark_created_msg;
1473 * Function to get html for the sql query results table
1475 * @param PMA_DisplayResults $displayResultsObject instance of DisplayResult.class
1476 * @param string $pmaThemeImage theme image uri
1477 * @param string $url_query url query
1478 * @param array $displayParts the parts to display
1479 * @param bool $editable whether the result table is
1480 * editable or not
1481 * @param int $unlim_num_rows unlimited number of rows
1482 * @param int $num_rows number of rows
1483 * @param bool $showtable whether to show table or not
1484 * @param object $result result of the executed query
1485 * @param array $analyzed_sql_results analyzed sql results
1487 * @return String
1489 function PMA_getHtmlForSqlQueryResultsTable($displayResultsObject,
1490 $pmaThemeImage, $url_query, $displayParts,
1491 $editable, $unlim_num_rows, $num_rows, $showtable, $result,
1492 $analyzed_sql_results
1494 $printview = isset($_REQUEST['printview']) ? $_REQUEST['printview'] : null;
1495 $table_html = '';
1496 $browse_dist = ! empty($_REQUEST['is_browse_distinct']);
1498 if ($analyzed_sql_results['is_procedure']) {
1500 do {
1501 if (! isset($result)) {
1502 $result = $GLOBALS['dbi']->storeResult();
1504 $num_rows = $GLOBALS['dbi']->numRows($result);
1506 if ($result !== false && $num_rows > 0) {
1508 $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result);
1509 $fields_cnt = count($fields_meta);
1511 $displayResultsObject->setProperties(
1512 $num_rows,
1513 $fields_meta,
1514 $analyzed_sql_results['is_count'],
1515 $analyzed_sql_results['is_export'],
1516 $analyzed_sql_results['is_func'],
1517 $analyzed_sql_results['is_analyse'],
1518 $num_rows,
1519 $fields_cnt,
1520 $GLOBALS['querytime'],
1521 $pmaThemeImage,
1522 $GLOBALS['text_dir'],
1523 $analyzed_sql_results['is_maint'],
1524 $analyzed_sql_results['is_explain'],
1525 $analyzed_sql_results['is_show'],
1526 $showtable,
1527 $printview,
1528 $url_query,
1529 $editable,
1530 $browse_dist
1533 $displayParts = array(
1534 'edit_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE,
1535 'del_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE,
1536 'sort_lnk' => '1',
1537 'nav_bar' => '1',
1538 'bkm_form' => '1',
1539 'text_btn' => '1',
1540 'pview_lnk' => '1'
1543 $table_html .= $displayResultsObject->getTable(
1544 $result,
1545 $displayParts,
1546 $analyzed_sql_results
1550 $GLOBALS['dbi']->freeResult($result);
1551 unset($result);
1553 } while ($GLOBALS['dbi']->moreResults() && $GLOBALS['dbi']->nextResult());
1555 } else {
1556 if (isset($result) && $result) {
1557 $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result);
1558 $fields_cnt = count($fields_meta);
1560 $_SESSION['is_multi_query'] = false;
1561 $displayResultsObject->setProperties(
1562 $unlim_num_rows,
1563 $fields_meta,
1564 $analyzed_sql_results['is_count'],
1565 $analyzed_sql_results['is_export'],
1566 $analyzed_sql_results['is_func'],
1567 $analyzed_sql_results['is_analyse'],
1568 $num_rows,
1569 $fields_cnt, $GLOBALS['querytime'],
1570 $pmaThemeImage, $GLOBALS['text_dir'],
1571 $analyzed_sql_results['is_maint'],
1572 $analyzed_sql_results['is_explain'],
1573 $analyzed_sql_results['is_show'],
1574 $showtable,
1575 $printview,
1576 $url_query,
1577 $editable,
1578 $browse_dist
1581 $table_html .= $displayResultsObject->getTable(
1582 $result,
1583 $displayParts,
1584 $analyzed_sql_results
1586 $GLOBALS['dbi']->freeResult($result);
1589 return $table_html;
1593 * Function to get html for the previous query if there is such. If not will return
1594 * null
1596 * @param string $disp_query display query
1597 * @param bool $showSql whether to show sql
1598 * @param array $sql_data sql data
1599 * @param string $disp_message display message
1601 * @return string $previous_update_query_html
1603 function PMA_getHtmlForPreviousUpdateQuery($disp_query, $showSql, $sql_data,
1604 $disp_message
1606 // previous update query (from tbl_replace)
1607 if (isset($disp_query) && ($showSql == true) && empty($sql_data)) {
1608 $previous_update_query_html = PMA_Util::getMessage(
1609 $disp_message, $disp_query, 'success'
1611 } else {
1612 $previous_update_query_html = null;
1615 return $previous_update_query_html;
1619 * To get the message if a column index is missing. If not will return null
1621 * @param string $table current table
1622 * @param string $db current database
1623 * @param boolean $editable whether the results table can be editable or not
1624 * @param boolean $has_unique whether there is a unique key
1626 * @return PMA_message $message
1628 function PMA_getMessageIfMissingColumnIndex($table, $db, $editable, $has_unique)
1630 if (!empty($table) && ($GLOBALS['dbi']->isSystemSchema($db) || !$editable)) {
1631 $missing_unique_column_msg = PMA_message::notice(
1632 sprintf(
1634 'Current selection does not contain a unique column.'
1635 . ' Grid edit, checkbox, Edit, Copy and Delete features'
1636 . ' are not available. %s'
1638 PMA_Util::showDocu('config', 'cfg_RowActionLinksWithoutUnique')
1641 } elseif (! empty($table) && ! $has_unique) {
1642 $missing_unique_column_msg = PMA_message::notice(
1643 sprintf(
1645 'Current selection does not contain a unique column.'
1646 . ' Grid edit, Edit, Copy and Delete features may result in'
1647 . ' undesired behavior. %s'
1649 PMA_Util::showDocu('config', 'cfg_RowActionLinksWithoutUnique')
1652 } else {
1653 $missing_unique_column_msg = null;
1656 return $missing_unique_column_msg;
1660 * Function to get html to display problems in indexes
1662 * @param string $query_type query type
1663 * @param array|null $selectedTables array of table names selected from the
1664 * database structure page, for an action
1665 * like check table, optimize table,
1666 * analyze table or repair table
1667 * @param string $db current database
1669 * @return string
1671 function PMA_getHtmlForIndexesProblems($query_type, $selectedTables, $db)
1673 // BEGIN INDEX CHECK See if indexes should be checked.
1674 if (isset($query_type)
1675 && $query_type == 'check_tbl'
1676 && isset($selectedTables)
1677 && is_array($selectedTables)
1679 $indexes_problems_html = '';
1680 foreach ($selectedTables as $tbl_name) {
1681 $check = PMA_Index::findDuplicates($tbl_name, $db);
1682 if (! empty($check)) {
1683 $indexes_problems_html .= sprintf(
1684 __('Problems with indexes of table `%s`'), $tbl_name
1686 $indexes_problems_html .= $check;
1689 } else {
1690 $indexes_problems_html = null;
1693 return $indexes_problems_html;
1697 * Function to display results when the executed query returns non empty results
1699 * @param object $result executed query results
1700 * @param array $analyzed_sql_results analysed sql results
1701 * @param string $db current database
1702 * @param string $table current table
1703 * @param string $message message to show
1704 * @param array $sql_data sql data
1705 * @param PMA_DisplayResults $displayResultsObject Instance of DisplayResults.class
1706 * @param string $pmaThemeImage uri of the theme image
1707 * @param int $unlim_num_rows unlimited number of rows
1708 * @param int $num_rows number of rows
1709 * @param string $disp_query display query
1710 * @param string $disp_message display message
1711 * @param array $profiling_results profiling results
1712 * @param string $query_type query type
1713 * @param array|null $selectedTables array of table names selected
1714 * from
1715 * the database structure page, for
1716 * an action like check table,
1717 * optimize table, analyze table or
1718 * repair table
1719 * @param string $sql_query sql query
1720 * @param string $complete_query complete sql query
1722 * @return string html
1724 function PMA_getQueryResponseForResultsReturned($result, $analyzed_sql_results,
1725 $db, $table, $message, $sql_data, $displayResultsObject, $pmaThemeImage,
1726 $unlim_num_rows, $num_rows, $disp_query, $disp_message, $profiling_results,
1727 $query_type, $selectedTables, $sql_query, $complete_query
1729 // If we are retrieving the full value of a truncated field or the original
1730 // value of a transformed field, show it here
1731 if (isset($_REQUEST['grid_edit']) && $_REQUEST['grid_edit'] == true) {
1732 PMA_sendResponseForGridEdit($result);
1733 // script has exited at this point
1736 // Gets the list of fields properties
1737 if (isset($result) && $result) {
1738 $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result);
1741 // Should be initialized these parameters before parsing
1742 $showtable = isset($showtable) ? $showtable : null;
1743 $url_query = isset($url_query) ? $url_query : null;
1745 $response = PMA_Response::getInstance();
1746 $header = $response->getHeader();
1747 $scripts = $header->getScripts();
1749 // hide edit and delete links:
1750 // - for information_schema
1751 // - if the result set does not contain all the columns of a unique key
1752 // (unless this is an updatable view)
1754 $updatableView = false;
1756 $statement = $analyzed_sql_results['statement'];
1757 if ($statement instanceof SqlParser\Statements\SelectStatement) {
1758 if (!empty($statement->expr)) {
1759 if ($statement->expr[0]->expr === '*') {
1760 $_table = new PMA_Table($table, $db);
1761 $updatableView = $_table->isUpdatableView();
1766 $has_unique = PMA_resultSetContainsUniqueKey(
1767 $db, $table, $fields_meta
1770 $just_one_table = PMA_resultSetHasJustOneTable($fields_meta);
1772 $editable = ($has_unique
1773 || $GLOBALS['cfg']['RowActionLinksWithoutUnique']
1774 || $updatableView)
1775 && $just_one_table;
1777 $displayParts = array(
1778 'edit_lnk' => $displayResultsObject::UPDATE_ROW,
1779 'del_lnk' => $displayResultsObject::DELETE_ROW,
1780 'sort_lnk' => '1',
1781 'nav_bar' => '1',
1782 'bkm_form' => '1',
1783 'text_btn' => '0',
1784 'pview_lnk' => '1'
1787 if (!empty($table) && ($GLOBALS['dbi']->isSystemSchema($db) || !$editable)) {
1788 $displayParts = array(
1789 'edit_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE,
1790 'del_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE,
1791 'sort_lnk' => '1',
1792 'nav_bar' => '1',
1793 'bkm_form' => '1',
1794 'text_btn' => '1',
1795 'pview_lnk' => '1'
1799 if (isset($_REQUEST['printview']) && $_REQUEST['printview'] == '1') {
1800 $displayParts = array(
1801 'edit_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE,
1802 'del_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE,
1803 'sort_lnk' => '0',
1804 'nav_bar' => '0',
1805 'bkm_form' => '0',
1806 'text_btn' => '0',
1807 'pview_lnk' => '0'
1811 if (isset($_REQUEST['table_maintenance'])) {
1812 $scripts->addFile('makegrid.js');
1813 $scripts->addFile('sql.js');
1814 $table_maintenance_html = '';
1815 if (isset($message)) {
1816 $message = PMA_Message::success($message);
1817 $table_maintenance_html = PMA_Util::getMessage(
1818 $message, $GLOBALS['sql_query'], 'success'
1821 $table_maintenance_html .= PMA_getHtmlForSqlQueryResultsTable(
1822 $displayResultsObject,
1823 $pmaThemeImage, $url_query, $displayParts,
1824 false, $unlim_num_rows, $num_rows, $showtable, $result,
1825 $analyzed_sql_results
1827 if (empty($sql_data) || ($sql_data['valid_queries'] = 1)) {
1828 $response->addHTML($table_maintenance_html);
1829 exit();
1833 if (!isset($_REQUEST['printview']) || $_REQUEST['printview'] != '1') {
1834 $scripts->addFile('makegrid.js');
1835 $scripts->addFile('sql.js');
1836 unset($GLOBALS['message']);
1837 //we don't need to buffer the output in getMessage here.
1838 //set a global variable and check against it in the function
1839 $GLOBALS['buffer_message'] = false;
1842 $previous_update_query_html = PMA_getHtmlForPreviousUpdateQuery(
1843 isset($disp_query) ? $disp_query : null,
1844 $GLOBALS['cfg']['ShowSQL'], isset($sql_data) ? $sql_data : null,
1845 isset($disp_message) ? $disp_message : null
1848 $profiling_chart_html = PMA_getHtmlForProfilingChart(
1849 $url_query, $db, isset($profiling_results) ? $profiling_results :array()
1852 $missing_unique_column_msg = PMA_getMessageIfMissingColumnIndex(
1853 $table, $db, $editable, $has_unique
1856 $bookmark_created_msg = PMA_getBookmarkCreatedMessage();
1858 $table_html = PMA_getHtmlForSqlQueryResultsTable(
1859 $displayResultsObject,
1860 $pmaThemeImage, $url_query, $displayParts,
1861 $editable, $unlim_num_rows, $num_rows, $showtable, $result,
1862 $analyzed_sql_results
1865 $indexes_problems_html = PMA_getHtmlForIndexesProblems(
1866 isset($query_type) ? $query_type : null,
1867 isset($selectedTables) ? $selectedTables : null, $db
1870 $cfgBookmark = PMA_Bookmark_getParams();
1871 if ($cfgBookmark) {
1872 $bookmark_support_html = PMA_getHtmlForBookmark(
1873 $displayParts,
1874 $cfgBookmark,
1875 $sql_query, $db, $table,
1876 isset($complete_query) ? $complete_query : $sql_query,
1877 $cfgBookmark['user']
1879 } else {
1880 $bookmark_support_html = '';
1883 $html_output = isset($table_maintenance_html) ? $table_maintenance_html : '';
1885 $html_output .= PMA_getHtmlForSqlQueryResults(
1886 $previous_update_query_html, $profiling_chart_html,
1887 $missing_unique_column_msg, $bookmark_created_msg,
1888 $table_html, $indexes_problems_html, $bookmark_support_html
1891 return $html_output;
1895 * Function to execute the query and send the response
1897 * @param array $analyzed_sql_results analysed sql results
1898 * @param bool $is_gotofile whether goto file or not
1899 * @param string $db current database
1900 * @param string $table current table
1901 * @param bool|null $find_real_end whether to find real end or not
1902 * @param string $sql_query_for_bookmark the sql query to be stored as bookmark
1903 * @param array|null $extra_data extra data
1904 * @param string $message_to_show message to show
1905 * @param string $message message
1906 * @param array|null $sql_data sql data
1907 * @param string $goto goto page url
1908 * @param string $pmaThemeImage uri of the PMA theme image
1909 * @param string $disp_query display query
1910 * @param string $disp_message display message
1911 * @param string $query_type query type
1912 * @param string $sql_query sql query
1913 * @param array|null $selectedTables array of table names selected from the
1914 * database structure page, for an action
1915 * like check table, optimize table,
1916 * analyze table or repair table
1917 * @param string $complete_query complete query
1919 * @return void
1921 function PMA_executeQueryAndSendQueryResponse($analyzed_sql_results,
1922 $is_gotofile, $db, $table, $find_real_end, $sql_query_for_bookmark,
1923 $extra_data, $message_to_show, $message, $sql_data, $goto, $pmaThemeImage,
1924 $disp_query, $disp_message, $query_type, $sql_query, $selectedTables,
1925 $complete_query
1927 $html_output = PMA_executeQueryAndGetQueryResponse(
1928 $analyzed_sql_results, // analyzed_sql_results
1929 $is_gotofile, // is_gotofile
1930 $db, // db
1931 $table, // table
1932 $find_real_end, // find_real_end
1933 $sql_query_for_bookmark, // sql_query_for_bookmark
1934 $extra_data, // extra_data
1935 $message_to_show, // message_to_show
1936 $message, // message
1937 $sql_data, // sql_data
1938 $goto, // goto
1939 $pmaThemeImage, // pmaThemeImage
1940 $disp_query, // disp_query
1941 $disp_message, // disp_message
1942 $query_type, // query_type
1943 $sql_query, // sql_query
1944 $selectedTables, // selectedTables
1945 $complete_query // complete_query
1948 $response = PMA_Response::getInstance();
1949 $response->addHTML($html_output);
1953 * Function to execute the query and send the response
1955 * @param array $analyzed_sql_results analysed sql results
1956 * @param bool $is_gotofile whether goto file or not
1957 * @param string $db current database
1958 * @param string $table current table
1959 * @param bool|null $find_real_end whether to find real end or not
1960 * @param string $sql_query_for_bookmark the sql query to be stored as bookmark
1961 * @param array|null $extra_data extra data
1962 * @param string $message_to_show message to show
1963 * @param string $message message
1964 * @param array|null $sql_data sql data
1965 * @param string $goto goto page url
1966 * @param string $pmaThemeImage uri of the PMA theme image
1967 * @param string $disp_query display query
1968 * @param string $disp_message display message
1969 * @param string $query_type query type
1970 * @param string $sql_query sql query
1971 * @param array|null $selectedTables array of table names selected from the
1972 * database structure page, for an action
1973 * like check table, optimize table,
1974 * analyze table or repair table
1975 * @param string $complete_query complete query
1977 * @return string html
1979 function PMA_executeQueryAndGetQueryResponse($analyzed_sql_results,
1980 $is_gotofile, $db, $table, $find_real_end, $sql_query_for_bookmark,
1981 $extra_data, $message_to_show, $message, $sql_data, $goto, $pmaThemeImage,
1982 $disp_query, $disp_message, $query_type, $sql_query, $selectedTables,
1983 $complete_query
1985 // Include PMA_Index class for use in PMA_DisplayResults class
1986 include_once './libraries/Index.class.php';
1988 include_once 'libraries/DisplayResults.class.php';
1990 // Handle disable/enable foreign key checks
1991 $default_fk_check = PMA_Util::handleDisableFKCheckInit();
1993 // Handle remembered sorting order, only for single table query.
1994 // Handling is not required when it's a union query
1995 // (the parser never sets the 'union' key to 0).
1996 // Handling is also not required if we came from the "Sort by key"
1997 // drop-down.
1998 if (PMA_isRememberSortingOrder($analyzed_sql_results)
1999 && empty($analyzed_sql_results['union'])
2000 && ! isset($_REQUEST['sort_by_key'])
2002 if (! isset($_SESSION['sql_from_query_box'])) {
2003 PMA_handleSortOrder($db, $table, $analyzed_sql_results, $sql_query);
2004 } else {
2005 unset($_SESSION['sql_from_query_box']);
2010 $displayResultsObject = new PMA_DisplayResults(
2011 $GLOBALS['db'], $GLOBALS['table'], $GLOBALS['goto'], $sql_query
2013 $displayResultsObject->setConfigParamsForDisplayTable();
2015 // assign default full_sql_query
2016 $full_sql_query = $sql_query;
2018 // Do append a "LIMIT" clause?
2019 if (PMA_isAppendLimitClause($analyzed_sql_results)) {
2020 $full_sql_query = PMA_getSqlWithLimitClause($analyzed_sql_results);
2023 $GLOBALS['reload'] = PMA_hasCurrentDbChanged($db);
2024 $GLOBALS['dbi']->selectDb($db);
2026 // Execute the query
2027 list($result, $num_rows, $unlim_num_rows, $profiling_results, $extra_data)
2028 = PMA_executeTheQuery(
2029 $analyzed_sql_results,
2030 $full_sql_query,
2031 $is_gotofile,
2032 $db,
2033 $table,
2034 isset($find_real_end) ? $find_real_end : null,
2035 isset($sql_query_for_bookmark) ? $sql_query_for_bookmark : null,
2036 isset($extra_data) ? $extra_data : null
2039 // No rows returned -> move back to the calling page
2040 if ((0 == $num_rows && 0 == $unlim_num_rows)
2041 || $analyzed_sql_results['is_affected']
2043 $html_output = PMA_getQueryResponseForNoResultsReturned(
2044 $analyzed_sql_results, $db, $table,
2045 isset($message_to_show) ? $message_to_show : null,
2046 $num_rows, $displayResultsObject, $extra_data
2048 } else {
2049 // At least one row is returned -> displays a table with results
2050 $html_output = PMA_getQueryResponseForResultsReturned(
2051 isset($result) ? $result : null,
2052 $analyzed_sql_results,
2053 $db,
2054 $table,
2055 isset($message) ? $message : null,
2056 isset($sql_data) ? $sql_data : null,
2057 $displayResultsObject,
2058 $pmaThemeImage,
2059 $unlim_num_rows,
2060 $num_rows,
2061 isset($disp_query) ? $disp_query : null,
2062 isset($disp_message) ? $disp_message : null,
2063 $profiling_results,
2064 isset($query_type) ? $query_type : null,
2065 isset($selectedTables) ? $selectedTables : null,
2066 $sql_query,
2067 isset($complete_query) ? $complete_query : null
2071 // Handle disable/enable foreign key checks
2072 PMA_Util::handleDisableFKCheckCleanup($default_fk_check);
2074 return $html_output;
2078 * Function to define pos to display a row
2080 * @param Int $number_of_line Number of the line to display
2081 * @param Int $max_rows Number of rows by page
2083 * @return Int Start position to display the line
2085 function PMA_getStartPosToDisplayRow($number_of_line, $max_rows = null)
2087 if (null === $max_rows) {
2088 $max_rows = $_SESSION['tmpval']['max_rows'];
2091 return @((ceil($number_of_line / $max_rows) - 1) * $max_rows);
2095 * Function to calculate new pos if pos is higher than number of rows
2096 * of displayed table
2098 * @param String $db Database name
2099 * @param String $table Table name
2100 * @param Int|null $pos Initial position
2102 * @return Int Number of pos to display last page
2104 function PMA_calculatePosForLastPage($db, $table, $pos)
2106 if (null === $pos) {
2107 $pos = $_SESSION['tmpval']['pos'];
2110 $_table = new PMA_Table($table, $db);
2111 $unlim_num_rows = $_table->countRecords(true);
2112 //If position is higher than number of rows
2113 if ($unlim_num_rows <= $pos && 0 != $pos) {
2114 $pos = PMA_getStartPosToDisplayRow($unlim_num_rows);
2117 return $pos;