Removing old documentation
[openemr.git] / phpmyadmin / libraries / sql.lib.php
blobba054d36741959bbd207bbe26fac3c08dea24a4f
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 value of a column for a specific row (marked by $where_clause)
402 * @param string $db current database
403 * @param string $table current table
404 * @param string $column current column
405 * @param string $where_clause where clause to select a particular row
408 function PMA_getFullValuesForSetColumn($db, $table, $column, $where_clause)
410 $result = $GLOBALS['dbi']->fetchSingleRow(
411 "SELECT `$column` FROM `$db`.`$table` WHERE $where_clause"
414 return $result[$column];
418 * Get the HTML for the set column dropdown
419 * During grid edit, if we have a set field, returns the html for the
420 * dropdown
422 * @param string $db current database
423 * @param string $table current table
424 * @param string $column current column
425 * @param string $curr_value currently selected value
427 * @return string $dropdown html for the set column
429 function PMA_getHtmlForSetColumn($db, $table, $column, $curr_value)
431 $values = PMA_getValuesForColumn($db, $table, $column);
432 $dropdown = '';
433 $full_values =
434 isset($_REQUEST['get_full_values']) ? $_REQUEST['get_full_values'] : false;
435 $where_clause =
436 isset($_REQUEST['where_clause']) ? $_REQUEST['where_clause'] : null;
438 // If the $curr_value was truncated, we should
439 // fetch the correct full values from the table
440 if ($full_values && ! empty($where_clause)) {
441 $curr_value = PMA_getFullValuesForSetColumn(
442 $db, $table, $column, $where_clause
446 //converts characters of $curr_value to HTML entities
447 $converted_curr_value = htmlentities(
448 $curr_value, ENT_COMPAT, "UTF-8"
451 $selected_values = explode(',', $converted_curr_value);
453 $dropdown .= PMA_getHtmlForOptionsList($values, $selected_values);
455 $select_size = (sizeof($values) > 10) ? 10 : sizeof($values);
456 $dropdown = '<select multiple="multiple" size="' . $select_size . '">'
457 . $dropdown . '</select>';
459 return $dropdown;
463 * Get all the values for a enum column or set column in a table
465 * @param string $db current database
466 * @param string $table current table
467 * @param string $column current column
469 * @return array $values array containing the value list for the column
471 function PMA_getValuesForColumn($db, $table, $column)
473 $field_info_query = $GLOBALS['dbi']->getColumnsSql($db, $table, $column);
475 $field_info_result = $GLOBALS['dbi']->fetchResult(
476 $field_info_query, null, null, null, PMA_DatabaseInterface::QUERY_STORE
479 $values = PMA_Util::parseEnumSetValues($field_info_result[0]['Type']);
481 return $values;
485 * Get HTML for options list
487 * @param array $values set of values
488 * @param array $selected_values currently selected values
490 * @return string $options HTML for options list
492 function PMA_getHtmlForOptionsList($values, $selected_values)
494 $options = '';
495 foreach ($values as $value) {
496 $options .= '<option value="' . $value . '"';
497 if (in_array($value, $selected_values, true)) {
498 $options .= ' selected="selected" ';
500 $options .= '>' . $value . '</option>';
502 return $options;
506 * Function to get html for bookmark support if bookmarks are enabled. Else will
507 * return null
509 * @param array $displayParts the parts to display
510 * @param bool $cfgBookmark configuration setting for bookmarking
511 * @param string $sql_query sql query
512 * @param string $db current database
513 * @param string $table current table
514 * @param string $complete_query complete query
515 * @param string $bkm_user bookmarking user
517 * @return string $html
519 function PMA_getHtmlForBookmark($displayParts, $cfgBookmark, $sql_query, $db,
520 $table, $complete_query, $bkm_user
522 if ($displayParts['bkm_form'] == '1'
523 && (! empty($cfgBookmark) && empty($_GET['id_bookmark']))
524 && ! empty($sql_query)
526 $goto = 'sql.php'
527 . PMA_URL_getCommon(
528 array(
529 'db' => $db,
530 'table' => $table,
531 'sql_query' => $sql_query,
532 'id_bookmark'=> 1,
535 $bkm_sql_query = urlencode(
536 isset($complete_query) ? $complete_query : $sql_query
538 $html = '<form action="sql.php" method="post"'
539 . ' onsubmit="return ! emptyCheckTheField(this,'
540 . '\'bkm_fields[bkm_label]\');"'
541 . ' class="bookmarkQueryForm print_ignore">';
542 $html .= PMA_URL_getHiddenInputs();
543 $html .= '<input type="hidden" name="db"'
544 . ' value="' . htmlspecialchars($db) . '" />';
545 $html .= '<input type="hidden" name="goto" value="' . $goto . '" />';
546 $html .= '<input type="hidden" name="bkm_fields[bkm_database]"'
547 . ' value="' . htmlspecialchars($db) . '" />';
548 $html .= '<input type="hidden" name="bkm_fields[bkm_user]"'
549 . ' value="' . $bkm_user . '" />';
550 $html .= '<input type="hidden" name="bkm_fields[bkm_sql_query]"'
551 . ' value="'
552 . $bkm_sql_query
553 . '" />';
554 $html .= '<fieldset>';
555 $html .= '<legend>';
556 $html .= PMA_Util::getIcon(
557 'b_bookmark.png', __('Bookmark this SQL query'), true
559 $html .= '</legend>';
560 $html .= '<div class="formelement">';
561 $html .= '<label>' . __('Label:') . '</label>';
562 $html .= '<input type="text" name="bkm_fields[bkm_label]" value="" />';
563 $html .= '</div>';
564 $html .= '<div class="formelement">';
565 $html .= '<input type="checkbox" name="bkm_all_users" value="true" />';
566 $html .= '<label>' . __('Let every user access this bookmark') . '</label>';
567 $html .= '</div>';
568 $html .= '<div class="clearfloat"></div>';
569 $html .= '</fieldset>';
570 $html .= '<fieldset class="tblFooters">';
571 $html .= '<input type="hidden" name="store_bkm" value="1" />';
572 $html .= '<input type="submit"'
573 . ' value="' . __('Bookmark this SQL query') . '" />';
574 $html .= '</fieldset>';
575 $html .= '</form>';
577 } else {
578 $html = null;
581 return $html;
585 * Function to check whether to remember the sorting order or not
587 * @param array $analyzed_sql_results the analyzed query and other variables set
588 * after analyzing the query
590 * @return boolean
592 function PMA_isRememberSortingOrder($analyzed_sql_results)
594 return $GLOBALS['cfg']['RememberSorting']
595 && ! ($analyzed_sql_results['is_count']
596 || $analyzed_sql_results['is_export']
597 || $analyzed_sql_results['is_func']
598 || $analyzed_sql_results['is_analyse'])
599 && $analyzed_sql_results['select_from']
600 && ((empty($analyzed_sql_results['select_expr']))
601 || (count($analyzed_sql_results['select_expr'] == 1)
602 && ($analyzed_sql_results['select_expr'][0] == '*')))
603 && count($analyzed_sql_results['select_tables']) == 1;
607 * Function to check whether the LIMIT clause should be appended or not
609 * @param array $analyzed_sql_results the analyzed query and other variables set
610 * after analyzing the query
612 * @return boolean
614 function PMA_isAppendLimitClause($analyzed_sql_results)
616 return ($_SESSION['tmpval']['max_rows'] != 'all')
617 && ! ($analyzed_sql_results['is_export']
618 || $analyzed_sql_results['is_analyse'])
619 && ($analyzed_sql_results['select_from']
620 || $analyzed_sql_results['is_subquery'])
621 && empty($analyzed_sql_results['limit']);
625 * Function to check whether this query is for just browsing
627 * @param array $analyzed_sql_results the analyzed query and other variables set
628 * after analyzing the query
629 * @param boolean $find_real_end whether the real end should be found
631 * @return boolean
633 function PMA_isJustBrowsing($analyzed_sql_results, $find_real_end)
635 return ! $analyzed_sql_results['is_group']
636 && ! $analyzed_sql_results['is_func']
637 && empty($analyzed_sql_results['union'])
638 && empty($analyzed_sql_results['distinct'])
639 && $analyzed_sql_results['select_from']
640 && (count($analyzed_sql_results['select_tables']) <= 1)
641 && (empty($analyzed_sql_results['statement']->where)
642 || (count($analyzed_sql_results['statement']->where) == 1
643 && $analyzed_sql_results['statement']->where[0]->expr ==='1'))
644 && empty($analyzed_sql_results['group'])
645 && ! isset($find_real_end)
646 && ! $analyzed_sql_results['is_subquery']
647 && empty($analyzed_sql_results['having']);
651 * Function to check whether the related transformation information should be deleted
653 * @param array $analyzed_sql_results the analyzed query and other variables set
654 * after analyzing the query
656 * @return boolean
658 function PMA_isDeleteTransformationInfo($analyzed_sql_results)
660 return !empty($analyzed_sql_results['querytype'])
661 && (($analyzed_sql_results['querytype'] == 'ALTER')
662 || ($analyzed_sql_results['querytype'] == 'DROP'));
666 * Function to check whether the user has rights to drop the database
668 * @param array $analyzed_sql_results the analyzed query and other variables set
669 * after analyzing the query
670 * @param boolean $allowUserDropDatabase whether the user is allowed to drop db
671 * @param boolean $is_superuser whether this user is a superuser
673 * @return boolean
675 function PMA_hasNoRightsToDropDatabase($analyzed_sql_results,
676 $allowUserDropDatabase, $is_superuser
678 return ! defined('PMA_CHK_DROP')
679 && ! $allowUserDropDatabase
680 && isset($analyzed_sql_results['drop_database'])
681 && $analyzed_sql_results['drop_database']
682 && ! $is_superuser;
686 * Function to set a column property
688 * @param PMA_Table $pmatable PMA_Table instance
689 * @param string $request_index col_order|col_visib
691 * @return boolean $retval
693 function PMA_setColumnProperty($pmatable, $request_index)
695 $property_value = explode(',', $_REQUEST[$request_index]);
696 switch($request_index) {
697 case 'col_order':
698 $property_to_set = PMA_Table::PROP_COLUMN_ORDER;
699 break;
700 case 'col_visib':
701 $property_to_set = PMA_Table::PROP_COLUMN_VISIB;
702 break;
703 default:
704 $property_to_set = '';
706 $retval = $pmatable->setUiProp(
707 $property_to_set,
708 $property_value,
709 $_REQUEST['table_create_time']
711 if (gettype($retval) != 'boolean') {
712 $response = PMA_Response::getInstance();
713 $response->isSuccess(false);
714 $response->addJSON('message', $retval->getString());
715 exit;
718 return $retval;
722 * Function to check the request for setting the column order or visibility
724 * @param String $table the current table
725 * @param String $db the current database
727 * @return void
729 function PMA_setColumnOrderOrVisibility($table, $db)
731 $pmatable = new PMA_Table($table, $db);
732 $retval = false;
734 // set column order
735 if (isset($_REQUEST['col_order'])) {
736 $retval = PMA_setColumnProperty($pmatable, 'col_order');
739 // set column visibility
740 if ($retval === true && isset($_REQUEST['col_visib'])) {
741 $retval = PMA_setColumnProperty($pmatable, 'col_visib');
744 $response = PMA_Response::getInstance();
745 $response->isSuccess($retval == true);
746 exit;
750 * Function to add a bookmark
752 * @param String $pmaAbsoluteUri absolute URI
753 * @param String $goto goto page URL
755 * @return void
757 function PMA_addBookmark($pmaAbsoluteUri, $goto)
759 $result = PMA_Bookmark_save(
760 $_POST['bkm_fields'],
761 (isset($_POST['bkm_all_users'])
762 && $_POST['bkm_all_users'] == 'true' ? true : false
765 $response = PMA_Response::getInstance();
766 if ($response->isAjax()) {
767 if ($result) {
768 $msg = PMA_message::success(__('Bookmark %s has been created.'));
769 $msg->addParam($_POST['bkm_fields']['bkm_label']);
770 $response->addJSON('message', $msg);
771 } else {
772 $msg = PMA_message::error(__('Bookmark not created!'));
773 $response->isSuccess(false);
774 $response->addJSON('message', $msg);
776 exit;
777 } else {
778 // go back to sql.php to redisplay query; do not use &amp; in this case:
780 * @todo In which scenario does this happen?
782 PMA_sendHeaderLocation(
783 $pmaAbsoluteUri . $goto
784 . '&label=' . $_POST['bkm_fields']['bkm_label']
790 * Function to find the real end of rows
792 * @param String $db the current database
793 * @param String $table the current table
795 * @return mixed the number of rows if "retain" param is true, otherwise true
797 function PMA_findRealEndOfRows($db, $table)
799 $unlim_num_rows = $GLOBALS['dbi']->getTable($db, $table)->countRecords(true);
800 $_SESSION['tmpval']['pos'] = PMA_getStartPosToDisplayRow($unlim_num_rows);
802 return $unlim_num_rows;
806 * Function to get values for the relational columns
808 * @param String $db the current database
809 * @param String $table the current table
811 * @return void
813 function PMA_getRelationalValues($db, $table)
815 $column = $_REQUEST['column'];
816 if ($_SESSION['tmpval']['relational_display'] == 'D'
817 && isset($_REQUEST['relation_key_or_display_column'])
818 && $_REQUEST['relation_key_or_display_column']
820 $curr_value = $_REQUEST['relation_key_or_display_column'];
821 } else {
822 $curr_value = $_REQUEST['curr_value'];
824 $dropdown = PMA_getHtmlForRelationalColumnDropdown(
825 $db, $table, $column, $curr_value
827 $response = PMA_Response::getInstance();
828 $response->addJSON('dropdown', $dropdown);
829 exit;
833 * Function to get values for Enum or Set Columns
835 * @param String $db the current database
836 * @param String $table the current table
837 * @param String $columnType whether enum or set
839 * @return void
841 function PMA_getEnumOrSetValues($db, $table, $columnType)
843 $column = $_REQUEST['column'];
844 $curr_value = $_REQUEST['curr_value'];
845 $response = PMA_Response::getInstance();
846 if ($columnType == "enum") {
847 $dropdown = PMA_getHtmlForEnumColumnDropdown(
848 $db, $table, $column, $curr_value
850 $response->addJSON('dropdown', $dropdown);
851 } else {
852 $select = PMA_getHtmlForSetColumn(
853 $db, $table, $column, $curr_value
855 $response->addJSON('select', $select);
857 exit;
861 * Function to get the default sql query for browsing page
863 * @param String $db the current database
864 * @param String $table the current table
866 * @return String $sql_query the default $sql_query for browse page
868 function PMA_getDefaultSqlQueryForBrowse($db, $table)
870 include_once 'libraries/bookmark.lib.php';
871 $book_sql_query = PMA_Bookmark_get(
872 $db,
873 '\'' . PMA_Util::sqlAddSlashes($table) . '\'',
874 'label',
875 false,
876 true
879 if (! empty($book_sql_query)) {
880 $GLOBALS['using_bookmark_message'] = PMA_message::notice(
881 __('Using bookmark "%s" as default browse query.')
883 $GLOBALS['using_bookmark_message']->addParam($table);
884 $GLOBALS['using_bookmark_message']->addMessage(
885 PMA_Util::showDocu('faq', 'faq6-22')
887 $sql_query = $book_sql_query;
888 } else {
890 $defaultOrderByClause = '';
892 if (isset($GLOBALS['cfg']['TablePrimaryKeyOrder'])
893 && ($GLOBALS['cfg']['TablePrimaryKeyOrder'] !== 'NONE')
896 $primaryKey = null;
897 $primary = PMA_Index::getPrimary($table, $db);
899 if ($primary !== false) {
901 $primarycols = $primary->getColumns();
903 foreach ($primarycols as $col) {
904 $primaryKey = $col->getName();
905 break;
908 if ($primaryKey != null) {
909 $defaultOrderByClause = ' ORDER BY '
910 . PMA_Util::backquote($table) . '.'
911 . PMA_Util::backquote($primaryKey) . ' '
912 . $GLOBALS['cfg']['TablePrimaryKeyOrder'];
919 $sql_query = 'SELECT * FROM ' . PMA_Util::backquote($table)
920 . $defaultOrderByClause;
923 unset($book_sql_query);
925 return $sql_query;
929 * Responds an error when an error happens when executing the query
931 * @param boolean $is_gotofile whether goto file or not
932 * @param String $error error after executing the query
933 * @param String $full_sql_query full sql query
935 * @return void
937 function PMA_handleQueryExecuteError($is_gotofile, $error, $full_sql_query)
939 if ($is_gotofile) {
940 $message = PMA_Message::rawError($error);
941 $response = PMA_Response::getInstance();
942 $response->isSuccess(false);
943 $response->addJSON('message', $message);
944 } else {
945 PMA_Util::mysqlDie($error, $full_sql_query, '', '');
947 exit;
951 * Function to store the query as a bookmark
953 * @param String $db the current database
954 * @param String $bkm_user the bookmarking user
955 * @param String $sql_query_for_bookmark the query to be stored in bookmark
956 * @param String $bkm_label bookmark label
957 * @param boolean $bkm_replace whether to replace existing bookmarks
959 * @return void
961 function PMA_storeTheQueryAsBookmark($db, $bkm_user, $sql_query_for_bookmark,
962 $bkm_label, $bkm_replace
964 include_once 'libraries/bookmark.lib.php';
965 $bfields = array(
966 'bkm_database' => $db,
967 'bkm_user' => $bkm_user,
968 'bkm_sql_query' => urlencode($sql_query_for_bookmark),
969 'bkm_label' => $bkm_label
972 // Should we replace bookmark?
973 if (isset($bkm_replace)) {
974 $bookmarks = PMA_Bookmark_getList($db);
975 foreach ($bookmarks as $key => $val) {
976 if ($val['label'] == $bkm_label) {
977 PMA_Bookmark_delete($key);
982 PMA_Bookmark_save($bfields, isset($_POST['bkm_all_users']));
987 * Function to execute the SQL query and set the execution time
989 * @param String $full_sql_query the full sql query
991 * @return mixed $result the results after running the query
993 function PMA_executeQueryAndStoreResults($full_sql_query)
995 // close session in case the query takes too long
996 session_write_close();
998 // Measure query time.
999 $querytime_before = array_sum(explode(' ', microtime()));
1001 $result = @$GLOBALS['dbi']->tryQuery(
1002 $full_sql_query, null, PMA_DatabaseInterface::QUERY_STORE
1004 $querytime_after = array_sum(explode(' ', microtime()));
1006 // reopen session
1007 session_start();
1009 $GLOBALS['querytime'] = $querytime_after - $querytime_before;
1011 return $result;
1015 * Function to get the affected or changed number of rows after executing a query
1017 * @param boolean $is_affected whether the query affected a table
1018 * @param mixed $result results of executing the query
1020 * @return int $num_rows number of rows affected or changed
1022 function PMA_getNumberOfRowsAffectedOrChanged($is_affected, $result)
1024 if (! $is_affected) {
1025 $num_rows = ($result) ? @$GLOBALS['dbi']->numRows($result) : 0;
1026 } else {
1027 $num_rows = @$GLOBALS['dbi']->affectedRows();
1030 return $num_rows;
1034 * Checks if the current database has changed
1035 * This could happen if the user sends a query like "USE `database`;"
1037 * @param String $db the database in the query
1039 * @return int $reload whether to reload the navigation(1) or not(0)
1041 function PMA_hasCurrentDbChanged($db)
1043 if (/*overload*/mb_strlen($db)) {
1044 $current_db = $GLOBALS['dbi']->fetchValue('SELECT DATABASE()');
1045 // $current_db is false, except when a USE statement was sent
1046 return ($current_db != false) && ($db !== $current_db);
1049 return false;
1053 * If a table, database or column gets dropped, clean comments.
1055 * @param String $db current database
1056 * @param String $table current table
1057 * @param String $column current column
1058 * @param bool $purge whether purge set or not
1060 * @return array $extra_data
1062 function PMA_cleanupRelations($db, $table, $column, $purge)
1064 include_once 'libraries/relation_cleanup.lib.php';
1066 if (! empty($purge) && /*overload*/mb_strlen($db)) {
1067 if (/*overload*/mb_strlen($table)) {
1068 if (isset($column) && /*overload*/mb_strlen($column)) {
1069 PMA_relationsCleanupColumn($db, $table, $column);
1070 } else {
1071 PMA_relationsCleanupTable($db, $table);
1073 } else {
1074 PMA_relationsCleanupDatabase($db);
1080 * Function to count the total number of rows for the same 'SELECT' query without
1081 * the 'LIMIT' clause that may have been programatically added
1083 * @param int $num_rows number of rows affected/changed by the query
1084 * @param bool $justBrowsing whether just browsing or not
1085 * @param string $db the current database
1086 * @param string $table the current table
1087 * @param array $analyzed_sql_results the analyzed query and other variables set
1088 * after analyzing the query
1090 * @return int $unlim_num_rows unlimited number of rows
1092 function PMA_countQueryResults(
1093 $num_rows, $justBrowsing, $db, $table, $analyzed_sql_results
1096 /* Shortcut for not analyzed/empty query */
1097 if (empty($analyzed_sql_results)) {
1098 return 0;
1101 if (!PMA_isAppendLimitClause($analyzed_sql_results)) {
1102 // if we did not append a limit, set this to get a correct
1103 // "Showing rows..." message
1104 // $_SESSION['tmpval']['max_rows'] = 'all';
1105 $unlim_num_rows = $num_rows;
1106 } elseif ($analyzed_sql_results['querytype'] == 'SELECT'
1107 || $analyzed_sql_results['is_subquery']
1109 // c o u n t q u e r y
1111 // If we are "just browsing", there is only one table,
1112 // and no WHERE clause (or just 'WHERE 1 '),
1113 // we do a quick count (which uses MaxExactCount) because
1114 // SQL_CALC_FOUND_ROWS is not quick on large InnoDB tables
1116 // However, do not count again if we did it previously
1117 // due to $find_real_end == true
1118 if ($justBrowsing) {
1119 // Get row count (is approximate for InnoDB)
1120 $unlim_num_rows = $GLOBALS['dbi']->getTable($db, $table)->countRecords();
1122 * @todo Can we know at this point that this is InnoDB,
1123 * (in this case there would be no need for getting
1124 * an exact count)?
1126 if ($unlim_num_rows < $GLOBALS['cfg']['MaxExactCount']) {
1127 // Get the exact count if approximate count
1128 // is less than MaxExactCount
1130 * @todo In countRecords(), MaxExactCount is also verified,
1131 * so can we avoid checking it twice?
1133 $unlim_num_rows = $GLOBALS['dbi']->getTable($db, $table)
1134 ->countRecords(true);
1137 } else {
1139 // The SQL_CALC_FOUND_ROWS option of the SELECT statement is used.
1141 // For UNION statements, only a SQL_CALC_FOUND_ROWS is required
1142 // after the first SELECT.
1144 $count_query = SqlParser\Utils\Query::replaceClause(
1145 $analyzed_sql_results['statement'],
1146 $analyzed_sql_results['parser']->list,
1147 'SELECT SQL_CALC_FOUND_ROWS',
1148 null,
1149 true
1152 // Another LIMIT clause is added to avoid long delays.
1153 // A complete result will be returned anyway, but the LIMIT would
1154 // stop the query as soon as the result that is required has been
1155 // computed.
1157 if (empty($analyzed_sql_results['union'])) {
1158 $count_query .= ' LIMIT 1';
1161 // Running the count query.
1162 $GLOBALS['dbi']->tryQuery($count_query);
1164 $unlim_num_rows = $GLOBALS['dbi']->fetchValue('SELECT FOUND_ROWS()');
1165 } // end else "just browsing"
1166 } else {// not $is_select
1167 $unlim_num_rows = 0;
1170 return $unlim_num_rows;
1174 * Function to handle all aspects relating to executing the query
1176 * @param array $analyzed_sql_results analyzed sql results
1177 * @param String $full_sql_query full sql query
1178 * @param boolean $is_gotofile whether to go to a file
1179 * @param String $db current database
1180 * @param String $table current table
1181 * @param boolean $find_real_end whether to find the real end
1182 * @param String $sql_query_for_bookmark sql query to be stored as bookmark
1183 * @param array $extra_data extra data
1185 * @return mixed
1187 function PMA_executeTheQuery($analyzed_sql_results, $full_sql_query, $is_gotofile,
1188 $db, $table, $find_real_end, $sql_query_for_bookmark, $extra_data
1190 $response = PMA_Response::getInstance();
1191 $response->getHeader()->getMenu()->setTable($table);
1193 // Only if we ask to see the php code
1194 if (isset($GLOBALS['show_as_php'])) {
1195 $result = null;
1196 $num_rows = 0;
1197 $unlim_num_rows = 0;
1198 } else { // If we don't ask to see the php code
1199 if (isset($_SESSION['profiling']) && PMA_Util::profilingSupported()) {
1200 $GLOBALS['dbi']->query('SET PROFILING=1;');
1203 $result = PMA_executeQueryAndStoreResults($full_sql_query);
1205 // Displays an error message if required and stop parsing the script
1206 $error = $GLOBALS['dbi']->getError();
1207 if ($error) {
1208 PMA_handleQueryExecuteError($is_gotofile, $error, $full_sql_query);
1211 // If there are no errors and bookmarklabel was given,
1212 // store the query as a bookmark
1213 if (! empty($_POST['bkm_label']) && ! empty($sql_query_for_bookmark)) {
1214 $cfgBookmark = PMA_Bookmark_getParams();
1215 PMA_storeTheQueryAsBookmark(
1216 $db, $cfgBookmark['user'],
1217 $sql_query_for_bookmark, $_POST['bkm_label'],
1218 isset($_POST['bkm_replace']) ? $_POST['bkm_replace'] : null
1220 } // end store bookmarks
1222 // Gets the number of rows affected/returned
1223 // (This must be done immediately after the query because
1224 // mysql_affected_rows() reports about the last query done)
1225 $num_rows = PMA_getNumberOfRowsAffectedOrChanged(
1226 $analyzed_sql_results['is_affected'], $result
1229 // Grabs the profiling results
1230 if (isset($_SESSION['profiling']) && PMA_Util::profilingSupported()) {
1231 $profiling_results = $GLOBALS['dbi']->fetchResult('SHOW PROFILE;');
1234 $justBrowsing = PMA_isJustBrowsing(
1235 $analyzed_sql_results, isset($find_real_end) ? $find_real_end : null
1238 $unlim_num_rows = PMA_countQueryResults(
1239 $num_rows, $justBrowsing, $db, $table, $analyzed_sql_results
1242 PMA_cleanupRelations(
1243 isset($db) ? $db : '',
1244 isset($table) ? $table : '',
1245 isset($_REQUEST['dropped_column']) ? $_REQUEST['dropped_column'] : null,
1246 isset($_REQUEST['purge']) ? $_REQUEST['purge'] : null
1249 if (isset($_REQUEST['dropped_column'])
1250 && /*overload*/mb_strlen($db)
1251 && /*overload*/mb_strlen($table)
1253 // to refresh the list of indexes (Ajax mode)
1254 $extra_data['indexes_list'] = PMA_Index::getHtmlForIndexes($table, $db);
1258 return array($result, $num_rows, $unlim_num_rows,
1259 isset($profiling_results) ? $profiling_results : null, $extra_data
1263 * Delete related tranformatioinformationn information
1265 * @param String $db current database
1266 * @param String $table current table
1267 * @param array $analyzed_sql_results analyzed sql results
1269 * @return void
1271 function PMA_deleteTransformationInfo($db, $table, $analyzed_sql_results)
1273 include_once 'libraries/transformations.lib.php';
1274 $statement = $analyzed_sql_results['statement'];
1275 if ($statement instanceof SqlParser\Statements\AlterStatement) {
1276 if (!empty($statement->altered[0])
1277 && $statement->altered[0]->options->has('DROP')
1279 if (!empty($statement->altered[0]->field->column)) {
1280 PMA_clearTransformations(
1281 $db,
1282 $table,
1283 $statement->altered[0]->field->column
1287 } elseif ($statement instanceof SqlParser\Statements\DropStatement) {
1288 PMA_clearTransformations($db, $table);
1293 * Function to get the message for the no rows returned case
1295 * @param string $message_to_show message to show
1296 * @param array $analyzed_sql_results analyzed sql results
1297 * @param int $num_rows number of rows
1299 * @return string $message
1301 function PMA_getMessageForNoRowsReturned($message_to_show,
1302 $analyzed_sql_results, $num_rows
1304 if ($analyzed_sql_results['querytype'] == 'DELETE"') {
1305 $message = PMA_Message::getMessageForDeletedRows($num_rows);
1306 } elseif ($analyzed_sql_results['is_insert']) {
1307 if ($analyzed_sql_results['querytype'] == 'REPLACE') {
1308 // For REPLACE we get DELETED + INSERTED row count,
1309 // so we have to call it affected
1310 $message = PMA_Message::getMessageForAffectedRows($num_rows);
1311 } else {
1312 $message = PMA_Message::getMessageForInsertedRows($num_rows);
1314 $insert_id = $GLOBALS['dbi']->insertId();
1315 if ($insert_id != 0) {
1316 // insert_id is id of FIRST record inserted in one insert,
1317 // so if we inserted multiple rows, we had to increment this
1318 $message->addMessage('[br]');
1319 // need to use a temporary because the Message class
1320 // currently supports adding parameters only to the first
1321 // message
1322 $_inserted = PMA_Message::notice(__('Inserted row id: %1$d'));
1323 $_inserted->addParam($insert_id + $num_rows - 1);
1324 $message->addMessage($_inserted);
1326 } elseif ($analyzed_sql_results['is_affected']) {
1327 $message = PMA_Message::getMessageForAffectedRows($num_rows);
1329 // Ok, here is an explanation for the !$is_select.
1330 // The form generated by sql_query_form.lib.php
1331 // and db_sql.php has many submit buttons
1332 // on the same form, and some confusion arises from the
1333 // fact that $message_to_show is sent for every case.
1334 // The $message_to_show containing a success message and sent with
1335 // the form should not have priority over errors
1336 } elseif (! empty($message_to_show)
1337 && $analyzed_sql_results['querytype'] != 'SELECT'
1339 $message = PMA_Message::rawSuccess(htmlspecialchars($message_to_show));
1340 } elseif (! empty($GLOBALS['show_as_php'])) {
1341 $message = PMA_Message::success(__('Showing as PHP code'));
1342 } elseif (isset($GLOBALS['show_as_php'])) {
1343 /* User disable showing as PHP, query is only displayed */
1344 $message = PMA_Message::notice(__('Showing SQL query'));
1345 } else {
1346 $message = PMA_Message::success(
1347 __('MySQL returned an empty result set (i.e. zero rows).')
1351 if (isset($GLOBALS['querytime'])) {
1352 $_querytime = PMA_Message::notice(
1353 '(' . __('Query took %01.4f seconds.') . ')'
1355 $_querytime->addParam($GLOBALS['querytime']);
1356 $message->addMessage($_querytime);
1359 // In case of ROLLBACK, notify the user.
1360 if (isset($_REQUEST['rollback_query'])) {
1361 $message->addMessage(__('[ROLLBACK occurred.]'));
1364 return $message;
1368 * Function to respond back when the query returns zero rows
1369 * This method is called
1370 * 1-> When browsing an empty table
1371 * 2-> When executing a query on a non empty table which returns zero results
1372 * 3-> When executing a query on an empty table
1373 * 4-> When executing an INSERT, UPDATE, DELETE query from the SQL tab
1374 * 5-> When deleting a row from BROWSE tab
1375 * 6-> When searching using the SEARCH tab which returns zero results
1376 * 7-> When changing the structure of the table except change operation
1378 * @param array $analyzed_sql_results analyzed sql results
1379 * @param string $db current database
1380 * @param string $table current table
1381 * @param string $message_to_show message to show
1382 * @param int $num_rows number of rows
1383 * @param PMA_DisplayResults $displayResultsObject DisplayResult instance
1384 * @param array $extra_data extra data
1386 * @return string html
1388 function PMA_getQueryResponseForNoResultsReturned($analyzed_sql_results, $db,
1389 $table, $message_to_show, $num_rows, $displayResultsObject, $extra_data
1391 if (PMA_isDeleteTransformationInfo($analyzed_sql_results)) {
1392 PMA_deleteTransformationInfo($db, $table, $analyzed_sql_results);
1395 $message = PMA_getMessageForNoRowsReturned(
1396 isset($message_to_show) ? $message_to_show : null,
1397 $analyzed_sql_results, $num_rows
1400 $html_output = '';
1401 if (!isset($GLOBALS['show_as_php'])) {
1403 if (! empty($GLOBALS['reload'])) {
1404 $extra_data['reload'] = 1;
1405 $extra_data['db'] = $GLOBALS['db'];
1408 $html_message = PMA_Util::getMessage(
1409 $message, $GLOBALS['sql_query'], 'success'
1411 $html_output .= $html_message;
1413 // For ajax requests add message and sql_query as JSON
1414 if (empty($_REQUEST['ajax_page_request'])) {
1415 $extra_data['message'] = $message;
1416 if ($GLOBALS['cfg']['ShowSQL']) {
1417 $extra_data['sql_query'] = $html_message;
1421 $response = PMA_Response::getInstance();
1422 $response->addJSON(isset($extra_data) ? $extra_data : array());
1424 if (!empty($analyzed_sql_results['is_select'])) {
1425 $html_output .= $displayResultsObject->getCreateViewQueryResultOp(
1426 $analyzed_sql_results
1431 return $html_output;
1435 * Function to send response for ajax grid edit
1437 * @param object $result result of the executed query
1439 * @return void
1441 function PMA_sendResponseForGridEdit($result)
1443 $row = $GLOBALS['dbi']->fetchRow($result);
1444 $field_flags = $GLOBALS['dbi']->fieldFlags($result, 0);
1445 if (stristr($field_flags, PMA_DisplayResults::BINARY_FIELD)) {
1446 $row[0] = bin2hex($row[0]);
1448 $response = PMA_Response::getInstance();
1449 $response->addJSON('value', $row[0]);
1450 exit;
1454 * Function to get html for the sql query results div
1456 * @param string $previous_update_query_html html for the previously
1457 * executed query
1458 * @param string $profiling_chart_html html for profiling
1459 * @param PMA_Message $missing_unique_column_msg message for the missing
1460 * unique column
1461 * @param PMA_Message $bookmark_created_msg message for bookmark creation
1462 * @param string $table_html html for the table for
1463 * displaying sql results
1464 * @param string $indexes_problems_html html for displaying errors
1465 * in indexes
1466 * @param string $bookmark_support_html html for displaying bookmark form
1468 * @return string $html_output
1470 function PMA_getHtmlForSqlQueryResults($previous_update_query_html,
1471 $profiling_chart_html, $missing_unique_column_msg, $bookmark_created_msg,
1472 $table_html, $indexes_problems_html, $bookmark_support_html
1474 //begin the sqlqueryresults div here. container div
1475 $html_output = '<div class="sqlqueryresults ajax">';
1476 $html_output .= isset($previous_update_query_html)
1477 ? $previous_update_query_html : '';
1478 $html_output .= isset($profiling_chart_html) ? $profiling_chart_html : '';
1479 $html_output .= isset($missing_unique_column_msg)
1480 ? $missing_unique_column_msg->getDisplay() : '';
1481 $html_output .= isset($bookmark_created_msg)
1482 ? $bookmark_created_msg->getDisplay() : '';
1483 $html_output .= $table_html;
1484 $html_output .= isset($indexes_problems_html) ? $indexes_problems_html : '';
1485 $html_output .= isset($bookmark_support_html) ? $bookmark_support_html : '';
1486 $html_output .= '</div>'; // end sqlqueryresults div
1488 return $html_output;
1492 * Returns a message for successful creation of a bookmark or null if a bookmark
1493 * was not created
1495 * @return PMA_message $bookmark_created_msg
1497 function PMA_getBookmarkCreatedMessage()
1499 if (isset($_GET['label'])) {
1500 $bookmark_created_msg = PMA_message::success(
1501 __('Bookmark %s has been created.')
1503 $bookmark_created_msg->addParam($_GET['label']);
1504 } else {
1505 $bookmark_created_msg = null;
1508 return $bookmark_created_msg;
1512 * Function to get html for the sql query results table
1514 * @param PMA_DisplayResults $displayResultsObject instance of DisplayResult.class
1515 * @param string $pmaThemeImage theme image uri
1516 * @param string $url_query url query
1517 * @param array $displayParts the parts to display
1518 * @param bool $editable whether the result table is
1519 * editable or not
1520 * @param int $unlim_num_rows unlimited number of rows
1521 * @param int $num_rows number of rows
1522 * @param bool $showtable whether to show table or not
1523 * @param object $result result of the executed query
1524 * @param array $analyzed_sql_results analyzed sql results
1526 * @return String
1528 function PMA_getHtmlForSqlQueryResultsTable($displayResultsObject,
1529 $pmaThemeImage, $url_query, $displayParts,
1530 $editable, $unlim_num_rows, $num_rows, $showtable, $result,
1531 $analyzed_sql_results
1533 $printview = isset($_REQUEST['printview']) ? $_REQUEST['printview'] : null;
1534 $table_html = '';
1535 $browse_dist = ! empty($_REQUEST['is_browse_distinct']);
1537 if ($analyzed_sql_results['is_procedure']) {
1539 do {
1540 if (! isset($result)) {
1541 $result = $GLOBALS['dbi']->storeResult();
1543 $num_rows = $GLOBALS['dbi']->numRows($result);
1545 if ($result !== false && $num_rows > 0) {
1547 $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result);
1548 $fields_cnt = count($fields_meta);
1550 $displayResultsObject->setProperties(
1551 $num_rows,
1552 $fields_meta,
1553 $analyzed_sql_results['is_count'],
1554 $analyzed_sql_results['is_export'],
1555 $analyzed_sql_results['is_func'],
1556 $analyzed_sql_results['is_analyse'],
1557 $num_rows,
1558 $fields_cnt,
1559 $GLOBALS['querytime'],
1560 $pmaThemeImage,
1561 $GLOBALS['text_dir'],
1562 $analyzed_sql_results['is_maint'],
1563 $analyzed_sql_results['is_explain'],
1564 $analyzed_sql_results['is_show'],
1565 $showtable,
1566 $printview,
1567 $url_query,
1568 $editable,
1569 $browse_dist
1572 $displayParts = array(
1573 'edit_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE,
1574 'del_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE,
1575 'sort_lnk' => '1',
1576 'nav_bar' => '1',
1577 'bkm_form' => '1',
1578 'text_btn' => '1',
1579 'pview_lnk' => '1'
1582 $table_html .= $displayResultsObject->getTable(
1583 $result,
1584 $displayParts,
1585 $analyzed_sql_results
1589 $GLOBALS['dbi']->freeResult($result);
1590 unset($result);
1592 } while ($GLOBALS['dbi']->moreResults() && $GLOBALS['dbi']->nextResult());
1594 } else {
1595 if (isset($result) && $result) {
1596 $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result);
1597 $fields_cnt = count($fields_meta);
1599 $_SESSION['is_multi_query'] = false;
1600 $displayResultsObject->setProperties(
1601 $unlim_num_rows,
1602 $fields_meta,
1603 $analyzed_sql_results['is_count'],
1604 $analyzed_sql_results['is_export'],
1605 $analyzed_sql_results['is_func'],
1606 $analyzed_sql_results['is_analyse'],
1607 $num_rows,
1608 $fields_cnt, $GLOBALS['querytime'],
1609 $pmaThemeImage, $GLOBALS['text_dir'],
1610 $analyzed_sql_results['is_maint'],
1611 $analyzed_sql_results['is_explain'],
1612 $analyzed_sql_results['is_show'],
1613 $showtable,
1614 $printview,
1615 $url_query,
1616 $editable,
1617 $browse_dist
1620 $table_html .= $displayResultsObject->getTable(
1621 $result,
1622 $displayParts,
1623 $analyzed_sql_results
1625 $GLOBALS['dbi']->freeResult($result);
1628 return $table_html;
1632 * Function to get html for the previous query if there is such. If not will return
1633 * null
1635 * @param string $disp_query display query
1636 * @param bool $showSql whether to show sql
1637 * @param array $sql_data sql data
1638 * @param string $disp_message display message
1640 * @return string $previous_update_query_html
1642 function PMA_getHtmlForPreviousUpdateQuery($disp_query, $showSql, $sql_data,
1643 $disp_message
1645 // previous update query (from tbl_replace)
1646 if (isset($disp_query) && ($showSql == true) && empty($sql_data)) {
1647 $previous_update_query_html = PMA_Util::getMessage(
1648 $disp_message, $disp_query, 'success'
1650 } else {
1651 $previous_update_query_html = null;
1654 return $previous_update_query_html;
1658 * To get the message if a column index is missing. If not will return null
1660 * @param string $table current table
1661 * @param string $db current database
1662 * @param boolean $editable whether the results table can be editable or not
1663 * @param boolean $has_unique whether there is a unique key
1665 * @return PMA_message $message
1667 function PMA_getMessageIfMissingColumnIndex($table, $db, $editable, $has_unique)
1669 if (!empty($table) && ($GLOBALS['dbi']->isSystemSchema($db) || !$editable)) {
1670 $missing_unique_column_msg = PMA_message::notice(
1671 sprintf(
1673 'Current selection does not contain a unique column.'
1674 . ' Grid edit, checkbox, Edit, Copy and Delete features'
1675 . ' are not available. %s'
1677 PMA_Util::showDocu('config', 'cfg_RowActionLinksWithoutUnique')
1680 } elseif (! empty($table) && ! $has_unique) {
1681 $missing_unique_column_msg = PMA_message::notice(
1682 sprintf(
1684 'Current selection does not contain a unique column.'
1685 . ' Grid edit, Edit, Copy and Delete features may result in'
1686 . ' undesired behavior. %s'
1688 PMA_Util::showDocu('config', 'cfg_RowActionLinksWithoutUnique')
1691 } else {
1692 $missing_unique_column_msg = null;
1695 return $missing_unique_column_msg;
1699 * Function to get html to display problems in indexes
1701 * @param string $query_type query type
1702 * @param array|null $selectedTables array of table names selected from the
1703 * database structure page, for an action
1704 * like check table, optimize table,
1705 * analyze table or repair table
1706 * @param string $db current database
1708 * @return string
1710 function PMA_getHtmlForIndexesProblems($query_type, $selectedTables, $db)
1712 // BEGIN INDEX CHECK See if indexes should be checked.
1713 if (isset($query_type)
1714 && $query_type == 'check_tbl'
1715 && isset($selectedTables)
1716 && is_array($selectedTables)
1718 $indexes_problems_html = '';
1719 foreach ($selectedTables as $tbl_name) {
1720 $check = PMA_Index::findDuplicates($tbl_name, $db);
1721 if (! empty($check)) {
1722 $indexes_problems_html .= sprintf(
1723 __('Problems with indexes of table `%s`'), $tbl_name
1725 $indexes_problems_html .= $check;
1728 } else {
1729 $indexes_problems_html = null;
1732 return $indexes_problems_html;
1736 * Function to display results when the executed query returns non empty results
1738 * @param object $result executed query results
1739 * @param array $analyzed_sql_results analysed sql results
1740 * @param string $db current database
1741 * @param string $table current table
1742 * @param string $message message to show
1743 * @param array $sql_data sql data
1744 * @param PMA_DisplayResults $displayResultsObject Instance of DisplayResults.class
1745 * @param string $pmaThemeImage uri of the theme image
1746 * @param int $unlim_num_rows unlimited number of rows
1747 * @param int $num_rows number of rows
1748 * @param string $disp_query display query
1749 * @param string $disp_message display message
1750 * @param array $profiling_results profiling results
1751 * @param string $query_type query type
1752 * @param array|null $selectedTables array of table names selected
1753 * from
1754 * the database structure page, for
1755 * an action like check table,
1756 * optimize table, analyze table or
1757 * repair table
1758 * @param string $sql_query sql query
1759 * @param string $complete_query complete sql query
1761 * @return string html
1763 function PMA_getQueryResponseForResultsReturned($result, $analyzed_sql_results,
1764 $db, $table, $message, $sql_data, $displayResultsObject, $pmaThemeImage,
1765 $unlim_num_rows, $num_rows, $disp_query, $disp_message, $profiling_results,
1766 $query_type, $selectedTables, $sql_query, $complete_query
1768 // If we are retrieving the full value of a truncated field or the original
1769 // value of a transformed field, show it here
1770 if (isset($_REQUEST['grid_edit']) && $_REQUEST['grid_edit'] == true) {
1771 PMA_sendResponseForGridEdit($result);
1772 // script has exited at this point
1775 // Gets the list of fields properties
1776 if (isset($result) && $result) {
1777 $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result);
1780 // Should be initialized these parameters before parsing
1781 $showtable = isset($showtable) ? $showtable : null;
1782 $url_query = isset($url_query) ? $url_query : null;
1784 $response = PMA_Response::getInstance();
1785 $header = $response->getHeader();
1786 $scripts = $header->getScripts();
1788 // hide edit and delete links:
1789 // - for information_schema
1790 // - if the result set does not contain all the columns of a unique key
1791 // (unless this is an updatable view)
1793 $updatableView = false;
1795 $statement = $analyzed_sql_results['statement'];
1796 if ($statement instanceof SqlParser\Statements\SelectStatement) {
1797 if (!empty($statement->expr)) {
1798 if ($statement->expr[0]->expr === '*') {
1799 $_table = new PMA_Table($table, $db);
1800 $updatableView = $_table->isUpdatableView();
1805 $has_unique = PMA_resultSetContainsUniqueKey(
1806 $db, $table, $fields_meta
1809 $just_one_table = PMA_resultSetHasJustOneTable($fields_meta);
1811 $editable = ($has_unique
1812 || $GLOBALS['cfg']['RowActionLinksWithoutUnique']
1813 || $updatableView)
1814 && $just_one_table;
1816 $displayParts = array(
1817 'edit_lnk' => $displayResultsObject::UPDATE_ROW,
1818 'del_lnk' => $displayResultsObject::DELETE_ROW,
1819 'sort_lnk' => '1',
1820 'nav_bar' => '1',
1821 'bkm_form' => '1',
1822 'text_btn' => '0',
1823 'pview_lnk' => '1'
1826 if (!empty($table) && ($GLOBALS['dbi']->isSystemSchema($db) || !$editable)) {
1827 $displayParts = array(
1828 'edit_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE,
1829 'del_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE,
1830 'sort_lnk' => '1',
1831 'nav_bar' => '1',
1832 'bkm_form' => '1',
1833 'text_btn' => '1',
1834 'pview_lnk' => '1'
1838 if (isset($_REQUEST['printview']) && $_REQUEST['printview'] == '1') {
1839 $displayParts = array(
1840 'edit_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE,
1841 'del_lnk' => $displayResultsObject::NO_EDIT_OR_DELETE,
1842 'sort_lnk' => '0',
1843 'nav_bar' => '0',
1844 'bkm_form' => '0',
1845 'text_btn' => '0',
1846 'pview_lnk' => '0'
1850 if (isset($_REQUEST['table_maintenance'])) {
1851 $scripts->addFile('makegrid.js');
1852 $scripts->addFile('sql.js');
1853 $table_maintenance_html = '';
1854 if (isset($message)) {
1855 $message = PMA_Message::success($message);
1856 $table_maintenance_html = PMA_Util::getMessage(
1857 $message, $GLOBALS['sql_query'], 'success'
1860 $table_maintenance_html .= PMA_getHtmlForSqlQueryResultsTable(
1861 $displayResultsObject,
1862 $pmaThemeImage, $url_query, $displayParts,
1863 false, $unlim_num_rows, $num_rows, $showtable, $result,
1864 $analyzed_sql_results
1866 if (empty($sql_data) || ($sql_data['valid_queries'] = 1)) {
1867 $response->addHTML($table_maintenance_html);
1868 exit();
1872 if (!isset($_REQUEST['printview']) || $_REQUEST['printview'] != '1') {
1873 $scripts->addFile('makegrid.js');
1874 $scripts->addFile('sql.js');
1875 unset($GLOBALS['message']);
1876 //we don't need to buffer the output in getMessage here.
1877 //set a global variable and check against it in the function
1878 $GLOBALS['buffer_message'] = false;
1881 $previous_update_query_html = PMA_getHtmlForPreviousUpdateQuery(
1882 isset($disp_query) ? $disp_query : null,
1883 $GLOBALS['cfg']['ShowSQL'], isset($sql_data) ? $sql_data : null,
1884 isset($disp_message) ? $disp_message : null
1887 $profiling_chart_html = PMA_getHtmlForProfilingChart(
1888 $url_query, $db, isset($profiling_results) ? $profiling_results :array()
1891 $missing_unique_column_msg = PMA_getMessageIfMissingColumnIndex(
1892 $table, $db, $editable, $has_unique
1895 $bookmark_created_msg = PMA_getBookmarkCreatedMessage();
1897 $table_html = PMA_getHtmlForSqlQueryResultsTable(
1898 $displayResultsObject,
1899 $pmaThemeImage, $url_query, $displayParts,
1900 $editable, $unlim_num_rows, $num_rows, $showtable, $result,
1901 $analyzed_sql_results
1904 $indexes_problems_html = PMA_getHtmlForIndexesProblems(
1905 isset($query_type) ? $query_type : null,
1906 isset($selectedTables) ? $selectedTables : null, $db
1909 $cfgBookmark = PMA_Bookmark_getParams();
1910 if ($cfgBookmark) {
1911 $bookmark_support_html = PMA_getHtmlForBookmark(
1912 $displayParts,
1913 $cfgBookmark,
1914 $sql_query, $db, $table,
1915 isset($complete_query) ? $complete_query : $sql_query,
1916 $cfgBookmark['user']
1918 } else {
1919 $bookmark_support_html = '';
1922 $html_output = isset($table_maintenance_html) ? $table_maintenance_html : '';
1924 $html_output .= PMA_getHtmlForSqlQueryResults(
1925 $previous_update_query_html, $profiling_chart_html,
1926 $missing_unique_column_msg, $bookmark_created_msg,
1927 $table_html, $indexes_problems_html, $bookmark_support_html
1930 return $html_output;
1934 * Function to execute the query and send the response
1936 * @param array $analyzed_sql_results analysed sql results
1937 * @param bool $is_gotofile whether goto file or not
1938 * @param string $db current database
1939 * @param string $table current table
1940 * @param bool|null $find_real_end whether to find real end or not
1941 * @param string $sql_query_for_bookmark the sql query to be stored as bookmark
1942 * @param array|null $extra_data extra data
1943 * @param string $message_to_show message to show
1944 * @param string $message message
1945 * @param array|null $sql_data sql data
1946 * @param string $goto goto page url
1947 * @param string $pmaThemeImage uri of the PMA theme image
1948 * @param string $disp_query display query
1949 * @param string $disp_message display message
1950 * @param string $query_type query type
1951 * @param string $sql_query sql query
1952 * @param array|null $selectedTables array of table names selected from the
1953 * database structure page, for an action
1954 * like check table, optimize table,
1955 * analyze table or repair table
1956 * @param string $complete_query complete query
1958 * @return void
1960 function PMA_executeQueryAndSendQueryResponse($analyzed_sql_results,
1961 $is_gotofile, $db, $table, $find_real_end, $sql_query_for_bookmark,
1962 $extra_data, $message_to_show, $message, $sql_data, $goto, $pmaThemeImage,
1963 $disp_query, $disp_message, $query_type, $sql_query, $selectedTables,
1964 $complete_query
1966 $html_output = PMA_executeQueryAndGetQueryResponse(
1967 $analyzed_sql_results, // analyzed_sql_results
1968 $is_gotofile, // is_gotofile
1969 $db, // db
1970 $table, // table
1971 $find_real_end, // find_real_end
1972 $sql_query_for_bookmark, // sql_query_for_bookmark
1973 $extra_data, // extra_data
1974 $message_to_show, // message_to_show
1975 $message, // message
1976 $sql_data, // sql_data
1977 $goto, // goto
1978 $pmaThemeImage, // pmaThemeImage
1979 $disp_query, // disp_query
1980 $disp_message, // disp_message
1981 $query_type, // query_type
1982 $sql_query, // sql_query
1983 $selectedTables, // selectedTables
1984 $complete_query // complete_query
1987 $response = PMA_Response::getInstance();
1988 $response->addHTML($html_output);
1992 * Function to execute the query and send the response
1994 * @param array $analyzed_sql_results analysed sql results
1995 * @param bool $is_gotofile whether goto file or not
1996 * @param string $db current database
1997 * @param string $table current table
1998 * @param bool|null $find_real_end whether to find real end or not
1999 * @param string $sql_query_for_bookmark the sql query to be stored as bookmark
2000 * @param array|null $extra_data extra data
2001 * @param string $message_to_show message to show
2002 * @param string $message message
2003 * @param array|null $sql_data sql data
2004 * @param string $goto goto page url
2005 * @param string $pmaThemeImage uri of the PMA theme image
2006 * @param string $disp_query display query
2007 * @param string $disp_message display message
2008 * @param string $query_type query type
2009 * @param string $sql_query sql query
2010 * @param array|null $selectedTables array of table names selected from the
2011 * database structure page, for an action
2012 * like check table, optimize table,
2013 * analyze table or repair table
2014 * @param string $complete_query complete query
2016 * @return string html
2018 function PMA_executeQueryAndGetQueryResponse($analyzed_sql_results,
2019 $is_gotofile, $db, $table, $find_real_end, $sql_query_for_bookmark,
2020 $extra_data, $message_to_show, $message, $sql_data, $goto, $pmaThemeImage,
2021 $disp_query, $disp_message, $query_type, $sql_query, $selectedTables,
2022 $complete_query
2024 // Include PMA_Index class for use in PMA_DisplayResults class
2025 include_once './libraries/Index.class.php';
2027 include_once 'libraries/DisplayResults.class.php';
2029 // Handle disable/enable foreign key checks
2030 $default_fk_check = PMA_Util::handleDisableFKCheckInit();
2032 // Handle remembered sorting order, only for single table query.
2033 // Handling is not required when it's a union query
2034 // (the parser never sets the 'union' key to 0).
2035 // Handling is also not required if we came from the "Sort by key"
2036 // drop-down.
2037 if (! empty($analyzed_sql_results)
2038 && PMA_isRememberSortingOrder($analyzed_sql_results)
2039 && empty($analyzed_sql_results['union'])
2040 && ! isset($_REQUEST['sort_by_key'])
2042 if (! isset($_SESSION['sql_from_query_box'])) {
2043 PMA_handleSortOrder($db, $table, $analyzed_sql_results, $sql_query);
2044 } else {
2045 unset($_SESSION['sql_from_query_box']);
2050 $displayResultsObject = new PMA_DisplayResults(
2051 $GLOBALS['db'], $GLOBALS['table'], $GLOBALS['goto'], $sql_query
2053 $displayResultsObject->setConfigParamsForDisplayTable();
2055 // assign default full_sql_query
2056 $full_sql_query = $sql_query;
2058 // Do append a "LIMIT" clause?
2059 if (PMA_isAppendLimitClause($analyzed_sql_results)) {
2060 $full_sql_query = PMA_getSqlWithLimitClause($analyzed_sql_results);
2063 $GLOBALS['reload'] = PMA_hasCurrentDbChanged($db);
2064 $GLOBALS['dbi']->selectDb($db);
2066 // Execute the query
2067 list($result, $num_rows, $unlim_num_rows, $profiling_results, $extra_data)
2068 = PMA_executeTheQuery(
2069 $analyzed_sql_results,
2070 $full_sql_query,
2071 $is_gotofile,
2072 $db,
2073 $table,
2074 isset($find_real_end) ? $find_real_end : null,
2075 isset($sql_query_for_bookmark) ? $sql_query_for_bookmark : null,
2076 isset($extra_data) ? $extra_data : null
2079 // No rows returned -> move back to the calling page
2080 if ((0 == $num_rows && 0 == $unlim_num_rows)
2081 || $analyzed_sql_results['is_affected']
2083 $html_output = PMA_getQueryResponseForNoResultsReturned(
2084 $analyzed_sql_results, $db, $table,
2085 isset($message_to_show) ? $message_to_show : null,
2086 $num_rows, $displayResultsObject, $extra_data
2088 } else {
2089 // At least one row is returned -> displays a table with results
2090 $html_output = PMA_getQueryResponseForResultsReturned(
2091 isset($result) ? $result : null,
2092 $analyzed_sql_results,
2093 $db,
2094 $table,
2095 isset($message) ? $message : null,
2096 isset($sql_data) ? $sql_data : null,
2097 $displayResultsObject,
2098 $pmaThemeImage,
2099 $unlim_num_rows,
2100 $num_rows,
2101 isset($disp_query) ? $disp_query : null,
2102 isset($disp_message) ? $disp_message : null,
2103 $profiling_results,
2104 isset($query_type) ? $query_type : null,
2105 isset($selectedTables) ? $selectedTables : null,
2106 $sql_query,
2107 isset($complete_query) ? $complete_query : null
2111 // Handle disable/enable foreign key checks
2112 PMA_Util::handleDisableFKCheckCleanup($default_fk_check);
2114 return $html_output;
2118 * Function to define pos to display a row
2120 * @param Int $number_of_line Number of the line to display
2121 * @param Int $max_rows Number of rows by page
2123 * @return Int Start position to display the line
2125 function PMA_getStartPosToDisplayRow($number_of_line, $max_rows = null)
2127 if (null === $max_rows) {
2128 $max_rows = $_SESSION['tmpval']['max_rows'];
2131 return @((ceil($number_of_line / $max_rows) - 1) * $max_rows);
2135 * Function to calculate new pos if pos is higher than number of rows
2136 * of displayed table
2138 * @param String $db Database name
2139 * @param String $table Table name
2140 * @param Int|null $pos Initial position
2142 * @return Int Number of pos to display last page
2144 function PMA_calculatePosForLastPage($db, $table, $pos)
2146 if (null === $pos) {
2147 $pos = $_SESSION['tmpval']['pos'];
2150 $_table = new PMA_Table($table, $db);
2151 $unlim_num_rows = $_table->countRecords(true);
2152 //If position is higher than number of rows
2153 if ($unlim_num_rows <= $pos && 0 != $pos) {
2154 $pos = PMA_getStartPosToDisplayRow($unlim_num_rows);
2157 return $pos;