Translated using Weblate (Bulgarian)
[phpmyadmin.git] / sql.php
blob63528bdf77df427c85f1d72cfb5f9134b10e5879
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * SQL executor
6 * @todo we must handle the case if sql.php is called directly with a query
7 * that returns 0 rows - to prevent cyclic redirects or includes
8 * @package PhpMyAdmin
9 */
11 /**
12 * Gets some core libraries
14 require_once 'libraries/common.inc.php';
15 require_once 'libraries/Table.class.php';
16 require_once 'libraries/Header.class.php';
17 require_once 'libraries/check_user_privileges.lib.php';
18 require_once 'libraries/bookmark.lib.php';
19 require_once 'libraries/sql.lib.php';
21 $response = PMA_Response::getInstance();
22 $header = $response->getHeader();
23 $scripts = $header->getScripts();
24 $scripts->addFile('jquery/jquery-ui-timepicker-addon.js');
25 $scripts->addFile('tbl_change.js');
26 // the next one needed because sql.php may do a "goto" to tbl_structure.php
27 $scripts->addFile('tbl_structure.js');
28 $scripts->addFile('indexes.js');
29 $scripts->addFile('gis_data_editor.js');
31 /**
32 * Set ajax_reload in the response if it was already set
34 if (isset($ajax_reload) && $ajax_reload['reload'] === true) {
35 $response->addJSON('ajax_reload', $ajax_reload);
38 /**
39 * Sets globals from $_POST
41 $post_params = array(
42 'bkm_all_users',
43 'fields',
44 'store_bkm'
46 foreach ($post_params as $one_post_param) {
47 if (isset($_POST[$one_post_param])) {
48 $GLOBALS[$one_post_param] = $_POST[$one_post_param];
52 /**
53 * Sets globals from $_GET
55 $get_params = array(
56 'id_bookmark',
57 'label',
58 'sql_query'
60 foreach ($get_params as $one_get_param) {
61 if (isset($_GET[$one_get_param])) {
62 $GLOBALS[$one_get_param] = $_GET[$one_get_param];
67 if (isset($_REQUEST['printview'])) {
68 $GLOBALS['printview'] = $_REQUEST['printview'];
71 if (!isset($_SESSION['is_multi_query'])) {
72 $_SESSION['is_multi_query'] = false;
75 /**
76 * Defines the url to return to in case of error in a sql statement
78 // Security checkings
79 if (! empty($goto)) {
80 $is_gotofile = preg_replace('@^([^?]+).*$@s', '\\1', $goto);
81 if (! @file_exists('' . $is_gotofile)) {
82 unset($goto);
83 } else {
84 $is_gotofile = ($is_gotofile == $goto);
86 } else {
87 if (empty($table)) {
88 $goto = $cfg['DefaultTabDatabase'];
89 } else {
90 $goto = $cfg['DefaultTabTable'];
92 $is_gotofile = true;
93 } // end if
95 if (! isset($err_url)) {
96 $err_url = (! empty($back) ? $back : $goto)
97 . '?' . PMA_generate_common_url($db)
98 . ((strpos(' ' . $goto, 'db_') != 1 && strlen($table))
99 ? '&amp;table=' . urlencode($table)
100 : ''
102 } // end if
104 // Coming from a bookmark dialog
105 if (isset($fields['query'])) {
106 $sql_query = $fields['query'];
109 // This one is just to fill $db
110 if (isset($fields['dbase'])) {
111 $db = $fields['dbase'];
115 // During grid edit, if we have a relational field, show the dropdown for it.
116 if (isset($_REQUEST['get_relational_values'])
117 && $_REQUEST['get_relational_values'] == true
119 $column = $_REQUEST['column'];
120 if ($_SESSION['tmp_user_values']['relational_display'] == 'D'
121 && isset($display_field)
122 && strlen($display_field)
123 && isset($_REQUEST['relation_key_or_display_column'])
124 && $_REQUEST['relation_key_or_display_column']
126 $curr_value = $_REQUEST['relation_key_or_display_column'];
127 } else {
128 $curr_value = $_REQUEST['curr_value'];
130 $dropdown = PMA_getHtmlForRelationalColumnDropdown(
131 $db, $table, $column, $curr_value
133 $response = PMA_Response::getInstance();
134 $response->addJSON('dropdown', $dropdown);
135 exit;
138 // Just like above, find possible values for enum fields during grid edit.
139 if (isset($_REQUEST['get_enum_values']) && $_REQUEST['get_enum_values'] == true) {
140 $column = $_REQUEST['column'];
141 $curr_value = $_REQUEST['curr_value'];
142 $dropdown = PMA_getHtmlForEnumColumnDropdown($db, $table, $column, $curr_value);
143 $response = PMA_Response::getInstance();
144 $response->addJSON('dropdown', $dropdown);
145 exit;
149 // Find possible values for set fields during grid edit.
150 if (isset($_REQUEST['get_set_values']) && $_REQUEST['get_set_values'] == true) {
151 $column = $_REQUEST['column'];
152 $curr_value = $_REQUEST['curr_value'];
153 $select = PMA_getHtmlForSetColumn($db, $table, $column, $curr_value);
154 $response = PMA_Response::getInstance();
155 $response->addJSON('select', $select);
156 exit;
160 * Check ajax request to set the column order
162 if (isset($_REQUEST['set_col_prefs']) && $_REQUEST['set_col_prefs'] == true) {
163 $pmatable = new PMA_Table($table, $db);
164 $retval = false;
166 // set column order
167 if (isset($_REQUEST['col_order'])) {
168 $col_order = explode(',', $_REQUEST['col_order']);
169 $retval = $pmatable->setUiProp(
170 PMA_Table::PROP_COLUMN_ORDER,
171 $col_order,
172 $_REQUEST['table_create_time']
174 if (gettype($retval) != 'boolean') {
175 $response = PMA_Response::getInstance();
176 $response->isSuccess(false);
177 $response->addJSON('message', $retval->getString());
178 exit;
182 // set column visibility
183 if ($retval === true && isset($_REQUEST['col_visib'])) {
184 $col_visib = explode(',', $_REQUEST['col_visib']);
185 $retval = $pmatable->setUiProp(
186 PMA_Table::PROP_COLUMN_VISIB, $col_visib,
187 $_REQUEST['table_create_time']
189 if (gettype($retval) != 'boolean') {
190 $response = PMA_Response::getInstance();
191 $response->isSuccess(false);
192 $response->addJSON('message', $retval->getString());
193 exit;
197 $response = PMA_Response::getInstance();
198 $response->isSuccess($retval == true);
199 exit;
202 // Default to browse if no query set and we have table
203 // (needed for browsing from DefaultTabTable)
204 if (empty($sql_query) && strlen($table) && strlen($db)) {
205 include_once 'libraries/bookmark.lib.php';
206 $book_sql_query = PMA_Bookmark_get(
207 $db,
208 '\'' . PMA_Util::sqlAddSlashes($table) . '\'',
209 'label',
210 false,
211 true
214 if (! empty($book_sql_query)) {
215 $GLOBALS['using_bookmark_message'] = PMA_message::notice(
216 __('Using bookmark "%s" as default browse query.')
218 $GLOBALS['using_bookmark_message']->addParam($table);
219 $GLOBALS['using_bookmark_message']->addMessage(
220 PMA_Util::showDocu('faq', 'faq6-22')
222 $sql_query = $book_sql_query;
223 } else {
224 $sql_query = 'SELECT * FROM ' . PMA_Util::backquote($table);
226 unset($book_sql_query);
228 // set $goto to what will be displayed if query returns 0 rows
229 $goto = '';
230 } else {
231 // Now we can check the parameters
232 PMA_Util::checkParameters(array('sql_query'));
235 // instead of doing the test twice
236 $is_drop_database = preg_match(
237 '/DROP[[:space:]]+(DATABASE|SCHEMA)[[:space:]]+/i',
238 $sql_query
242 * Check rights in case of DROP DATABASE
244 * This test may be bypassed if $is_js_confirmed = 1 (already checked with js)
245 * but since a malicious user may pass this variable by url/form, we don't take
246 * into account this case.
248 if (! defined('PMA_CHK_DROP')
249 && ! $cfg['AllowUserDropDatabase']
250 && $is_drop_database
251 && ! $is_superuser
253 PMA_Util::mysqlDie(
254 __('"DROP DATABASE" statements are disabled.'),
257 $err_url
259 } // end if
261 // Include PMA_Index class for use in PMA_DisplayResults class
262 require_once './libraries/Index.class.php';
264 require_once 'libraries/DisplayResults.class.php';
266 $displayResultsObject = new PMA_DisplayResults(
267 $GLOBALS['db'], $GLOBALS['table'], $GLOBALS['goto'], $GLOBALS['sql_query']
270 $displayResultsObject->setConfigParamsForDisplayTable();
273 * Need to find the real end of rows?
275 if (isset($find_real_end) && $find_real_end) {
276 $unlim_num_rows = PMA_Table::countRecords($db, $table, true);
277 $_SESSION['tmp_user_values']['pos'] = @((ceil(
278 $unlim_num_rows / $_SESSION['tmp_user_values']['max_rows']
279 ) - 1) * $_SESSION['tmp_user_values']['max_rows']);
284 * Bookmark add
286 if (isset($store_bkm)) {
287 $result = PMA_Bookmark_save(
288 $fields,
289 (isset($bkm_all_users) && $bkm_all_users == 'true' ? true : false)
291 $response = PMA_Response::getInstance();
292 if ($response->isAjax()) {
293 if ($result) {
294 $msg = PMA_message::success(__('Bookmark %s created'));
295 $msg->addParam($fields['label']);
296 $response->addJSON('message', $msg);
297 } else {
298 $msg = PMA_message::error(__('Bookmark not created'));
299 $response->isSuccess(false);
300 $response->addJSON('message', $msg);
302 exit;
303 } else {
304 // go back to sql.php to redisplay query; do not use &amp; in this case:
305 PMA_sendHeaderLocation(
306 $cfg['PmaAbsoluteUri'] . $goto . '&label=' . $fields['label']
309 } // end if
312 * Parse and analyze the query
314 require_once 'libraries/parse_analyze.lib.php';
317 * Sets or modifies the $goto variable if required
319 if ($goto == 'sql.php') {
320 $is_gotofile = false;
321 $goto = 'sql.php?'
322 . PMA_generate_common_url($db, $table)
323 . '&amp;sql_query=' . urlencode($sql_query);
324 } // end if
327 * Go back to further page if table should not be dropped
329 if (isset($_REQUEST['btnDrop']) && $_REQUEST['btnDrop'] == __('No')) {
330 if (! empty($back)) {
331 $goto = $back;
333 if ($is_gotofile) {
334 if (strpos($goto, 'db_') === 0 && strlen($table)) {
335 $table = '';
337 $active_page = $goto;
338 include '' . PMA_securePath($goto);
339 } else {
340 PMA_sendHeaderLocation(
341 $cfg['PmaAbsoluteUri'] . str_replace('&amp;', '&', $goto)
344 exit();
345 } // end if
349 * Displays the confirm page if required
351 * This part of the script is bypassed if $is_js_confirmed = 1 (already checked
352 * with js) because possible security issue is not so important here: at most,
353 * the confirm message isn't displayed.
355 * Also bypassed if only showing php code.or validating a SQL query
357 // if we are coming from a "Create PHP code" or a "Without PHP Code"
358 // dialog, we won't execute the query anyway, so don't confirm
359 if (! $cfg['Confirm']
360 || isset($_REQUEST['is_js_confirmed'])
361 || isset($_REQUEST['btnDrop'])
362 || isset($GLOBALS['show_as_php'])
363 || ! empty($GLOBALS['validatequery'])
365 $do_confirm = false;
366 } else {
367 $do_confirm = isset($analyzed_sql[0]['queryflags']['need_confirm']);
370 if ($do_confirm) {
371 $stripped_sql_query = $sql_query;
372 $input = '<input type="hidden" name="%s" value="%s" />';
373 $output = '';
374 if ($is_drop_database) {
375 $output .= '<h1 class="error">';
376 $output .= __('You are about to DESTROY a complete database!');
377 $output .= '</h1>';
379 $form = '<form class="disableAjax" action="sql.php" method="post">';
380 $form .= PMA_generate_common_hidden_inputs($db, $table);
382 $form .= sprintf(
383 $input, 'sql_query', htmlspecialchars($sql_query)
385 $form .= sprintf(
386 $input, 'message_to_show',
387 (isset($message_to_show) ? PMA_sanitize($message_to_show, true) : '')
389 $form .= sprintf(
390 $input, 'goto', $goto
392 $form .= sprintf(
393 $input, 'back',
394 (isset($back) ? PMA_sanitize($back, true) : '')
396 $form .= sprintf(
397 $input, 'reload',
398 (isset($reload) ? PMA_sanitize($reload, true) : '')
400 $form .= sprintf(
401 $input, 'purge',
402 (isset($purge) ? PMA_sanitize($purge, true) : '')
404 $form .= sprintf(
405 $input, 'dropped_column',
406 (isset($dropped_column) ? PMA_sanitize($dropped_column, true) : '')
408 $form .= sprintf(
409 $input, 'show_query',
410 (isset($message_to_show) ? PMA_sanitize($show_query, true) : '')
412 $form = str_replace('%', '%%', $form) . '%s</form>';
414 $output .='<fieldset class="confirmation">'
415 .'<legend>'
416 . __('Do you really want to execute the following query?')
417 . '</legend>'
418 .'<code>' . htmlspecialchars($stripped_sql_query) . '</code>'
419 .'</fieldset>'
420 .'<fieldset class="tblFooters">';
422 $yes_input = sprintf($input, 'btnDrop', __('Yes'));
423 $yes_input .= '<input type="submit" value="' . __('Yes') . '" id="buttonYes" />';
424 $no_input = sprintf($input, 'btnDrop', __('No'));
425 $no_input .= '<input type="submit" value="' . __('No') . '" id="buttonNo" />';
427 $output .= sprintf($form, $yes_input);
428 $output .= sprintf($form, $no_input);
430 $output .='</fieldset>';
431 $output .= '';
433 PMA_Response::getInstance()->addHTML($output);
435 exit;
436 } // end if $do_confirm
439 // Defines some variables
440 // A table has to be created, renamed, dropped -> navi frame should be reloaded
442 * @todo use the parser/analyzer
445 if (empty($reload)
446 && preg_match('/^(CREATE|ALTER|DROP)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $sql_query)
448 $reload = 1;
451 // $is_group added for use in calculation of total number of rows.
452 // $is_count is changed for more correct "LIMIT" clause
453 // appending in queries like
454 // "SELECT COUNT(...) FROM ... GROUP BY ..."
457 * @todo detect all this with the parser, to avoid problems finding
458 * those strings in comments or backquoted identifiers
460 list($is_group, $is_func, $is_count, $is_export, $is_analyse, $is_explain,
461 $is_delete, $is_affected, $is_insert, $is_replace, $is_show, $is_maint)
462 = PMA_getDisplayPropertyParams(
463 $sql_query, $is_select
466 // assign default full_sql_query
467 $full_sql_query = $sql_query;
469 // Handle remembered sorting order, only for single table query
470 if ($GLOBALS['cfg']['RememberSorting']
471 && ! ($is_count || $is_export || $is_func || $is_analyse)
472 && isset($analyzed_sql[0]['select_expr'])
473 && (count($analyzed_sql[0]['select_expr']) == 0)
474 && isset($analyzed_sql[0]['queryflags']['select_from'])
475 && count($analyzed_sql[0]['table_ref']) == 1
477 PMA_handleSortOrder($db, $table, $analyzed_sql, $full_sql_query);
480 $sql_limit_to_append = '';
481 // Do append a "LIMIT" clause?
482 if (($_SESSION['tmp_user_values']['max_rows'] != 'all')
483 && ! ($is_count || $is_export || $is_func || $is_analyse)
484 && isset($analyzed_sql[0]['queryflags']['select_from'])
485 && ! isset($analyzed_sql[0]['queryflags']['offset'])
486 && empty($analyzed_sql[0]['limit_clause'])
488 $sql_limit_to_append = ' LIMIT ' . $_SESSION['tmp_user_values']['pos']
489 . ', ' . $_SESSION['tmp_user_values']['max_rows'] . " ";
490 $full_sql_query = PMA_getSqlWithLimitClause(
491 $full_sql_query,
492 $analyzed_sql,
493 $sql_limit_to_append
497 * @todo pretty printing of this modified query
499 if (isset($display_query)) {
500 // if the analysis of the original query revealed that we found
501 // a section_after_limit, we now have to analyze $display_query
502 // to display it correctly
504 if (! empty($analyzed_sql[0]['section_after_limit'])
505 && trim($analyzed_sql[0]['section_after_limit']) != ';'
507 $analyzed_display_query = PMA_SQP_analyze(
508 PMA_SQP_parse($display_query)
510 $display_query = $analyzed_display_query[0]['section_before_limit']
511 . "\n" . $sql_limit_to_append
512 . $analyzed_display_query[0]['section_after_limit'];
517 if (strlen($db)) {
518 $GLOBALS['dbi']->selectDb($db);
521 // E x e c u t e t h e q u e r y
523 // Only if we didn't ask to see the php code
524 if (isset($GLOBALS['show_as_php']) || ! empty($GLOBALS['validatequery'])) {
525 unset($result);
526 $num_rows = 0;
527 $unlim_num_rows = 0;
528 } else {
529 if (isset($_SESSION['profiling']) && PMA_Util::profilingSupported()) {
530 $GLOBALS['dbi']->query('SET PROFILING=1;');
533 // Measure query time.
534 $querytime_before = array_sum(explode(' ', microtime()));
536 $result = @$GLOBALS['dbi']->tryQuery(
537 $full_sql_query, null, PMA_DatabaseInterface::QUERY_STORE
540 // If a stored procedure was called, there may be more results that are
541 // queued up and waiting to be flushed from the buffer. So let's do that.
542 do {
543 $GLOBALS['dbi']->storeResult();
544 if (! $GLOBALS['dbi']->moreResults()) {
545 break;
547 } while ($GLOBALS['dbi']->nextResult());
549 $is_procedure = false;
551 // Since multiple query execution is anyway handled,
552 // ignore the WHERE clause of the first sql statement
553 // which might contain a phrase like 'call '
554 if (preg_match("/\bcall\b/i", $full_sql_query)
555 && empty($analyzed_sql[0]['where_clause'])
557 $is_procedure = true;
560 $querytime_after = array_sum(explode(' ', microtime()));
562 $GLOBALS['querytime'] = $querytime_after - $querytime_before;
564 // Displays an error message if required and stop parsing the script
565 $error = $GLOBALS['dbi']->getError();
566 if ($error) {
567 if ($is_gotofile) {
568 if (strpos($goto, 'db_') === 0 && strlen($table)) {
569 $table = '';
571 $active_page = $goto;
572 $message = PMA_Message::rawError($error);
574 if ($GLOBALS['is_ajax_request'] == true) {
575 $response = PMA_Response::getInstance();
576 $response->isSuccess(false);
577 $response->addJSON('message', $message);
578 exit;
582 * Go to target path.
584 include '' . PMA_securePath($goto);
585 } else {
586 $full_err_url = $err_url;
587 if (preg_match('@^(db|tbl)_@', $err_url)) {
588 $full_err_url .= '&amp;show_query=1&amp;sql_query='
589 . urlencode($sql_query);
591 PMA_Util::mysqlDie($error, $full_sql_query, '', $full_err_url);
593 exit;
595 unset($error);
597 // If there are no errors and bookmarklabel was given,
598 // store the query as a bookmark
599 if (! empty($bkm_label) && ! empty($import_text)) {
600 include_once 'libraries/bookmark.lib.php';
601 $bfields = array(
602 'dbase' => $db,
603 'user' => $cfg['Bookmark']['user'],
604 'query' => urlencode($import_text),
605 'label' => $bkm_label
608 // Should we replace bookmark?
609 if (isset($bkm_replace)) {
610 $bookmarks = PMA_Bookmark_getList($db);
611 foreach ($bookmarks as $key => $val) {
612 if ($val == $bkm_label) {
613 PMA_Bookmark_delete($db, $key);
618 PMA_Bookmark_save($bfields, isset($bkm_all_users));
620 $bookmark_created = true;
621 } // end store bookmarks
623 // Gets the number of rows affected/returned
624 // (This must be done immediately after the query because
625 // mysql_affected_rows() reports about the last query done)
627 if (! $is_affected) {
628 $num_rows = ($result) ? @$GLOBALS['dbi']->numRows($result) : 0;
629 } elseif (! isset($num_rows)) {
630 $num_rows = @$GLOBALS['dbi']->affectedRows();
633 // Grabs the profiling results
634 if (isset($_SESSION['profiling']) && PMA_Util::profilingSupported()) {
635 $profiling_results = $GLOBALS['dbi']->fetchResult('SHOW PROFILE;');
638 // Checks if the current database has changed
639 // This could happen if the user sends a query like "USE `database`;"
641 * commented out auto-switching to active database - really required?
642 * bug #2558 win: table list disappears (mixed case db names)
643 * https://sourceforge.net/p/phpmyadmin/bugs/2558/
644 * @todo RELEASE test and comit or rollback before release
645 $current_db = $GLOBALS['dbi']->fetchValue('SELECT DATABASE()');
646 if ($db !== $current_db) {
647 $db = $current_db;
648 $reload = 1;
650 unset($current_db);
653 // tmpfile remove after convert encoding appended by Y.Kawada
654 if (function_exists('PMA_Kanji_fileConv')
655 && (isset($textfile) && file_exists($textfile))
657 unlink($textfile);
660 // Counts the total number of rows for the same 'SELECT' query without the
661 // 'LIMIT' clause that may have been programatically added
663 $justBrowsing = false;
664 if (empty($sql_limit_to_append)) {
665 $unlim_num_rows = $num_rows;
666 // if we did not append a limit, set this to get a correct
667 // "Showing rows..." message
668 //$_SESSION['tmp_user_values']['max_rows'] = 'all';
669 } elseif ($is_select) {
671 // c o u n t q u e r y
673 // If we are "just browsing", there is only one table,
674 // and no WHERE clause (or just 'WHERE 1 '),
675 // we do a quick count (which uses MaxExactCount) because
676 // SQL_CALC_FOUND_ROWS is not quick on large InnoDB tables
678 // However, do not count again if we did it previously
679 // due to $find_real_end == true
680 if (! $is_group
681 && ! isset($analyzed_sql[0]['queryflags']['union'])
682 && ! isset($analyzed_sql[0]['queryflags']['distinct'])
683 && ! isset($analyzed_sql[0]['table_ref'][1]['table_name'])
684 && (empty($analyzed_sql[0]['where_clause'])
685 || $analyzed_sql[0]['where_clause'] == '1 ')
686 && ! isset($find_real_end)
688 // "j u s t b r o w s i n g"
689 $justBrowsing = true;
690 $unlim_num_rows = PMA_Table::countRecords($db, $table);
692 } else { // n o t " j u s t b r o w s i n g "
694 // add select expression after the SQL_CALC_FOUND_ROWS
696 // for UNION, just adding SQL_CALC_FOUND_ROWS
697 // after the first SELECT works.
699 // take the left part, could be:
700 // SELECT
701 // (SELECT
702 $count_query = PMA_SQP_format(
703 $parsed_sql,
704 'query_only',
706 $analyzed_sql[0]['position_of_first_select'] + 1
708 $count_query .= ' SQL_CALC_FOUND_ROWS ';
709 // add everything that was after the first SELECT
710 $count_query .= PMA_SQP_format(
711 $parsed_sql,
712 'query_only',
713 $analyzed_sql[0]['position_of_first_select'] + 1
715 // ensure there is no semicolon at the end of the
716 // count query because we'll probably add
717 // a LIMIT 1 clause after it
718 $count_query = rtrim($count_query);
719 $count_query = rtrim($count_query, ';');
721 // if using SQL_CALC_FOUND_ROWS, add a LIMIT to avoid
722 // long delays. Returned count will be complete anyway.
723 // (but a LIMIT would disrupt results in an UNION)
725 if (! isset($analyzed_sql[0]['queryflags']['union'])) {
726 $count_query .= ' LIMIT 1';
729 // run the count query
731 $GLOBALS['dbi']->tryQuery($count_query);
732 // if (mysql_error()) {
733 // void.
734 // I tried the case
735 // (SELECT `User`, `Host`, `Db`, `Select_priv` FROM `db`)
736 // UNION (SELECT `User`, `Host`, "%" AS "Db",
737 // `Select_priv`
738 // FROM `user`) ORDER BY `User`, `Host`, `Db`;
739 // and although the generated count_query is wrong
740 // the SELECT FOUND_ROWS() work! (maybe it gets the
741 // count from the latest query that worked)
743 // another case where the count_query is wrong:
744 // SELECT COUNT(*), f1 from t1 group by f1
745 // and you click to sort on count(*)
746 // }
747 $unlim_num_rows = $GLOBALS['dbi']->fetchValue('SELECT FOUND_ROWS()');
748 } // end else "just browsing"
750 } else { // not $is_select
751 $unlim_num_rows = 0;
752 } // end rows total count
754 // if a table or database gets dropped, check column comments.
755 if (isset($purge) && $purge == '1') {
757 * Cleanup relations.
759 include_once 'libraries/relation_cleanup.lib.php';
761 if (strlen($table) && strlen($db)) {
762 PMA_relationsCleanupTable($db, $table);
763 } elseif (strlen($db)) {
764 PMA_relationsCleanupDatabase($db);
765 } else {
766 // VOID. No DB/Table gets deleted.
767 } // end if relation-stuff
768 } // end if ($purge)
770 // If a column gets dropped, do relation magic.
771 if (isset($dropped_column)
772 && strlen($db)
773 && strlen($table)
774 && ! empty($dropped_column)
776 include_once 'libraries/relation_cleanup.lib.php';
777 PMA_relationsCleanupColumn($db, $table, $dropped_column);
778 // to refresh the list of indexes (Ajax mode)
779 $extra_data['indexes_list'] = PMA_Index::getView($table, $db);
780 } // end if column was dropped
781 } // end else "didn't ask to see php code"
783 // No rows returned -> move back to the calling page
784 if ((0 == $num_rows && 0 == $unlim_num_rows) || $is_affected) {
785 // Delete related tranformation information
786 if (!empty($analyzed_sql[0]['querytype'])
787 && (($analyzed_sql[0]['querytype'] == 'ALTER')
788 || ($analyzed_sql[0]['querytype'] == 'DROP'))
790 include_once 'libraries/transformations.lib.php';
791 if ($analyzed_sql[0]['querytype'] == 'ALTER') {
792 if (stripos($analyzed_sql[0]['unsorted_query'], 'DROP') !== false) {
793 $drop_column = PMA_getColumnNameInColumnDropSql(
794 $analyzed_sql[0]['unsorted_query']
797 if ($drop_column != '') {
798 PMA_clearTransformations($db, $table, $drop_column);
802 } else if (($analyzed_sql[0]['querytype'] == 'DROP') && ($table != '')) {
803 PMA_clearTransformations($db, $table);
807 if ($is_delete) {
808 $message = PMA_Message::getMessageForDeletedRows($num_rows);
809 } elseif ($is_insert) {
810 if ($is_replace) {
811 // For replace we get DELETED + INSERTED row count,
812 // so we have to call it affected
813 $message = PMA_Message::getMessageForAffectedRows($num_rows);
814 } else {
815 $message = PMA_Message::getMessageForInsertedRows($num_rows);
817 $insert_id = $GLOBALS['dbi']->insertId();
818 if ($insert_id != 0) {
819 // insert_id is id of FIRST record inserted in one insert,
820 // so if we inserted multiple rows, we had to increment this
821 $message->addMessage('[br]');
822 // need to use a temporary because the Message class
823 // currently supports adding parameters only to the first
824 // message
825 $_inserted = PMA_Message::notice(__('Inserted row id: %1$d'));
826 $_inserted->addParam($insert_id + $num_rows - 1);
827 $message->addMessage($_inserted);
829 } elseif ($is_affected) {
830 $message = PMA_Message::getMessageForAffectedRows($num_rows);
832 // Ok, here is an explanation for the !$is_select.
833 // The form generated by sql_query_form.lib.php
834 // and db_sql.php has many submit buttons
835 // on the same form, and some confusion arises from the
836 // fact that $message_to_show is sent for every case.
837 // The $message_to_show containing a success message and sent with
838 // the form should not have priority over errors
839 } elseif (! empty($message_to_show) && ! $is_select) {
840 $message = PMA_Message::rawSuccess(htmlspecialchars($message_to_show));
841 } elseif (! empty($GLOBALS['show_as_php'])) {
842 $message = PMA_Message::success(__('Showing as PHP code'));
843 } elseif (isset($GLOBALS['show_as_php'])) {
844 /* User disable showing as PHP, query is only displayed */
845 $message = PMA_Message::notice(__('Showing SQL query'));
846 } elseif (! empty($GLOBALS['validatequery'])) {
847 $message = PMA_Message::notice(__('Validated SQL'));
848 } else {
849 $message = PMA_Message::success(
850 __('MySQL returned an empty result set (i.e. zero rows).')
854 if (isset($GLOBALS['querytime'])) {
855 $_querytime = PMA_Message::notice('(' . __('Query took %01.4f sec') . ')');
856 $_querytime->addParam($GLOBALS['querytime']);
857 $message->addMessage($_querytime);
860 if ($GLOBALS['is_ajax_request'] == true) {
861 if ($cfg['ShowSQL']) {
862 $extra_data['sql_query'] = PMA_Util::getMessage(
863 $message, $GLOBALS['sql_query'], 'success'
866 if (isset($GLOBALS['reload']) && $GLOBALS['reload'] == 1) {
867 $extra_data['reload'] = 1;
868 $extra_data['db'] = $GLOBALS['db'];
870 $response = PMA_Response::getInstance();
871 $response->isSuccess($message->isSuccess());
872 // No need to manually send the message
873 // The Response class will handle that automatically
874 $query__type = PMA_DisplayResults::QUERY_TYPE_SELECT;
875 if ($analyzed_sql[0]['querytype'] == $query__type) {
876 $createViewHTML = $displayResultsObject->getCreateViewQueryResultOp(
877 $analyzed_sql
879 $response->addHTML($createViewHTML.'<br />');
882 $response->addJSON(isset($extra_data) ? $extra_data : array());
883 if (empty($_REQUEST['ajax_page_request'])) {
884 $response->addJSON('message', $message);
885 exit;
889 if ($is_gotofile) {
890 $goto = PMA_securePath($goto);
891 // Checks for a valid target script
892 $is_db = $is_table = false;
893 if (isset($_REQUEST['purge']) && $_REQUEST['purge'] == '1') {
894 $table = '';
895 unset($url_params['table']);
897 include 'libraries/db_table_exists.lib.php';
899 if (strpos($goto, 'tbl_') === 0 && ! $is_table) {
900 if (strlen($table)) {
901 $table = '';
903 $goto = 'db_sql.php';
905 if (strpos($goto, 'db_') === 0 && ! $is_db) {
906 if (strlen($db)) {
907 $db = '';
909 $goto = 'index.php';
911 // Loads to target script
912 if (strlen($goto) > 0) {
913 $active_page = $goto;
914 include '' . $goto;
915 } else {
916 // Echo at least one character to prevent showing last page from history
917 echo " ";
920 } else {
921 // avoid a redirect loop when last record was deleted
922 if (0 == $num_rows && 'sql.php' == $cfg['DefaultTabTable']) {
923 $goto = str_replace('sql.php', 'tbl_structure.php', $goto);
925 PMA_sendHeaderLocation(
926 $cfg['PmaAbsoluteUri'] . str_replace('&amp;', '&', $goto)
927 . '&message=' . urlencode($message)
929 } // end else
930 exit();
931 // end no rows returned
932 } else {
933 $html_output='';
934 // At least one row is returned -> displays a table with results
935 //If we are retrieving the full value of a truncated field or the original
936 // value of a transformed field, show it here and exit
937 if ($GLOBALS['grid_edit'] == true) {
938 $row = $GLOBALS['dbi']->fetchRow($result);
939 $response = PMA_Response::getInstance();
940 $response->addJSON('value', $row[0]);
941 exit;
944 if (isset($_REQUEST['ajax_request']) && isset($_REQUEST['table_maintenance'])) {
945 $response = PMA_Response::getInstance();
946 $header = $response->getHeader();
947 $scripts = $header->getScripts();
948 $scripts->addFile('makegrid.js');
949 $scripts->addFile('sql.js');
951 // Gets the list of fields properties
952 if (isset($result) && $result) {
953 $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result);
954 $fields_cnt = count($fields_meta);
957 if (empty($disp_mode)) {
958 // see the "PMA_setDisplayMode()" function in
959 // libraries/DisplayResults.class.php
960 $disp_mode = 'urdr111101';
963 // hide edit and delete links for information_schema
964 if ($GLOBALS['dbi']->isSystemSchema($db)) {
965 $disp_mode = 'nnnn110111';
968 if (isset($message)) {
969 $message = PMA_Message::success($message);
970 $html_output .= PMA_Util::getMessage(
971 $message, $GLOBALS['sql_query'], 'success'
975 // Should be initialized these parameters before parsing
976 $showtable = isset($showtable) ? $showtable : null;
977 $printview = isset($printview) ? $printview : null;
978 $url_query = isset($url_query) ? $url_query : null;
980 if (!empty($sql_data) && ($sql_data['valid_queries'] > 1)) {
982 $_SESSION['is_multi_query'] = true;
983 $html_output .= getTableHtmlForMultipleQueries(
984 $displayResultsObject, $db, $sql_data, $goto,
985 $pmaThemeImage, $text_dir, $printview, $url_query,
986 $disp_mode, $sql_limit_to_append, false
988 } else {
989 $_SESSION['is_multi_query'] = false;
990 $displayResultsObject->setProperties(
991 $unlim_num_rows, $fields_meta, $is_count, $is_export, $is_func,
992 $is_analyse, $num_rows, $fields_cnt, $querytime, $pmaThemeImage,
993 $text_dir, $is_maint, $is_explain, $is_show, $showtable,
994 $printview, $url_query, false
997 $html_output .= $displayResultsObject->getTable(
998 $result, $disp_mode, $analyzed_sql
1000 $response = PMA_Response::getInstance();
1001 $response->addHTML($html_output);
1002 exit();
1006 // Displays the headers
1007 if (isset($show_query)) {
1008 unset($show_query);
1010 if (isset($printview) && $printview == '1') {
1011 PMA_Util::checkParameters(array('db', 'full_sql_query'));
1013 $response = PMA_Response::getInstance();
1014 $header = $response->getHeader();
1015 $header->enablePrintView();
1017 $html_output .= PMA_getHtmlForPrintViewHeader(
1018 $db, $full_sql_query, $num_rows
1020 } else {
1021 $response = PMA_Response::getInstance();
1022 $header = $response->getHeader();
1023 $scripts = $header->getScripts();
1024 $scripts->addFile('makegrid.js');
1025 $scripts->addFile('sql.js');
1027 unset($message);
1029 if (! $GLOBALS['is_ajax_request']) {
1030 if (strlen($table)) {
1031 include 'libraries/tbl_common.inc.php';
1032 $url_query .= '&amp;goto=tbl_sql.php&amp;back=tbl_sql.php';
1033 include 'libraries/tbl_info.inc.php';
1034 } elseif (strlen($db)) {
1035 include 'libraries/db_common.inc.php';
1036 include 'libraries/db_info.inc.php';
1037 } else {
1038 include 'libraries/server_common.inc.php';
1040 } else {
1041 //we don't need to buffer the output in getMessage here.
1042 //set a global variable and check against it in the function
1043 $GLOBALS['buffer_message'] = false;
1047 if (strlen($db)) {
1048 $cfgRelation = PMA_getRelationsParam();
1051 // Gets the list of fields properties
1052 if (isset($result) && $result) {
1053 $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result);
1054 $fields_cnt = count($fields_meta);
1057 //begin the sqlqueryresults div here. container div
1058 $html_output .= '<div id="sqlqueryresults"';
1059 $html_output .= ' class="ajax"';
1060 $html_output .= '>';
1062 // Display previous update query (from tbl_replace)
1063 if (isset($disp_query) && ($cfg['ShowSQL'] == true) && empty($sql_data)) {
1064 $html_output .= PMA_Util::getMessage($disp_message, $disp_query, 'success');
1067 if (isset($profiling_results)) {
1068 // pma_token/url_query needed for chart export
1069 $token = $_SESSION[' PMA_token '];
1070 $url = (isset($url_query) ? $url_query : PMA_generate_common_url($db));
1072 $html_output .= PMA_getHtmlForProfilingChart(
1073 $url, $token, $profiling_results
1077 // Displays the results in a table
1078 if (empty($disp_mode)) {
1079 // see the "PMA_setDisplayMode()" function in
1080 // libraries/DisplayResults.class.php
1081 $disp_mode = 'urdr111101';
1084 $has_unique = PMA_resultSetContainsUniqueKey(
1085 $db, $table, $fields_meta
1088 // hide edit and delete links:
1089 // - for information_schema
1090 // - if the result set does not contain all the columns of a unique key
1091 // and we are not just browing all the columns of an updatable view
1092 $updatableView
1093 = $justBrowsing
1094 && trim($analyzed_sql[0]['select_expr_clause']) == '*'
1095 && PMA_Table::isUpdatableView($db, $table);
1096 $editable = $has_unique || $updatableView;
1097 if ($GLOBALS['dbi']->isSystemSchema($db) || ! $editable) {
1098 $disp_mode = 'nnnn110111';
1099 $msg = PMA_message::notice(
1101 'This table does not contain a unique column.'
1102 . ' Grid edit, checkbox, Edit, Copy and Delete features'
1103 . ' are not available.'
1106 $html_output .= $msg->getDisplay();
1109 if (isset($label)) {
1110 $msg = PMA_message::success(__('Bookmark %s created'));
1111 $msg->addParam($label);
1112 $html_output .= $msg->getDisplay();
1115 // Should be initialized these parameters before parsing
1116 $showtable = isset($showtable) ? $showtable : null;
1117 $printview = isset($printview) ? $printview : null;
1118 $url_query = isset($url_query) ? $url_query : null;
1120 if (! empty($sql_data) && ($sql_data['valid_queries'] > 1) || $is_procedure) {
1122 $_SESSION['is_multi_query'] = true;
1123 $html_output .= getTableHtmlForMultipleQueries(
1124 $displayResultsObject, $db, $sql_data, $goto,
1125 $pmaThemeImage, $text_dir, $printview, $url_query,
1126 $disp_mode, $sql_limit_to_append, $editable
1128 } else {
1129 $_SESSION['is_multi_query'] = false;
1130 $displayResultsObject->setProperties(
1131 $unlim_num_rows, $fields_meta, $is_count, $is_export, $is_func,
1132 $is_analyse, $num_rows, $fields_cnt, $querytime, $pmaThemeImage,
1133 $text_dir, $is_maint, $is_explain, $is_show, $showtable,
1134 $printview, $url_query, $editable
1137 $html_output .= $displayResultsObject->getTable(
1138 $result, $disp_mode, $analyzed_sql
1140 $GLOBALS['dbi']->freeResult($result);
1143 // BEGIN INDEX CHECK See if indexes should be checked.
1144 if (isset($query_type)
1145 && $query_type == 'check_tbl'
1146 && isset($selected)
1147 && is_array($selected)
1149 foreach ($selected as $idx => $tbl_name) {
1150 $check = PMA_Index::findDuplicates($tbl_name, $db);
1151 if (! empty($check)) {
1152 $html_output .= sprintf(
1153 __('Problems with indexes of table `%s`'), $tbl_name
1155 $html_output .= $check;
1158 } // End INDEX CHECK
1160 // Bookmark support if required
1161 if ($disp_mode[7] == '1'
1162 && (! empty($cfg['Bookmark']) && empty($id_bookmark))
1163 && ! empty($sql_query)
1165 $html_output .= "\n";
1166 $goto = 'sql.php?'
1167 . PMA_generate_common_url($db, $table)
1168 . '&amp;sql_query=' . urlencode($sql_query)
1169 . '&amp;id_bookmark=1';
1171 $html_output .= '<form action="sql.php" method="post"'
1172 . ' onsubmit="return ! emptyFormElements(this, \'fields[label]\');"'
1173 . ' id="bookmarkQueryForm">';
1174 $html_output .= PMA_generate_common_hidden_inputs();
1175 $html_output .= '<input type="hidden" name="goto" value="' . $goto . '" />';
1176 $html_output .= '<input type="hidden" name="fields[dbase]"'
1177 . ' value="' . htmlspecialchars($db) . '" />';
1178 $html_output .= '<input type="hidden" name="fields[user]"'
1179 . ' value="' . $cfg['Bookmark']['user'] . '" />';
1180 $html_output .= '<input type="hidden" name="fields[query]"' . ' value="'
1181 . urlencode(isset($complete_query) ? $complete_query : $sql_query)
1182 . '" />';
1183 $html_output .= '<fieldset>';
1184 $html_output .= '<legend>';
1185 $html_output .= PMA_Util::getIcon(
1186 'b_bookmark.png', __('Bookmark this SQL query'), true
1188 $html_output .= '</legend>';
1189 $html_output .= '<div class="formelement">';
1190 $html_output .= '<label for="fields_label_">' . __('Label:') . '</label>';
1191 $html_output .= '<input type="text" id="fields_label_"'
1192 . ' name="fields[label]" value="" />';
1193 $html_output .= '</div>';
1194 $html_output .= '<div class="formelement">';
1195 $html_output .= '<input type="checkbox" name="bkm_all_users"'
1196 . ' id="bkm_all_users" value="true" />';
1197 $html_output .= '<label for="bkm_all_users">'
1198 . __('Let every user access this bookmark')
1199 . '</label>';
1200 $html_output .= '</div>';
1201 $html_output .= '<div class="clearfloat"></div>';
1202 $html_output .= '</fieldset>';
1203 $html_output .= '<fieldset class="tblFooters">';
1204 $html_output .= '<input type="hidden" name="store_bkm" value="1" />';
1205 $html_output .= '<input type="submit"'
1206 . ' value="' . __('Bookmark this SQL query') . '" />';
1207 $html_output .= '</fieldset>';
1208 $html_output .= '</form>';
1209 } // end bookmark support
1211 // Do print the page if required
1212 if (isset($printview) && $printview == '1') {
1213 $html_output .= PMA_Util::getButton();
1214 } // end print case
1215 $html_output .= '</div>'; // end sqlqueryresults div
1216 $response = PMA_Response::getInstance();
1217 $response->addHTML($html_output);
1218 } // end rows returned
1220 $_SESSION['is_multi_query'] = false;
1223 * Displays the footer
1225 if (! isset($_REQUEST['table_maintenance'])) {
1226 exit;