2 /* vim: set expandtab sw=4 ts=4 sts=4: */
4 * Holds the PhpMyAdmin\Operations class
10 use PhpMyAdmin\Charsets
;
12 use PhpMyAdmin\Engines\Innodb
;
13 use PhpMyAdmin\Message
;
14 use PhpMyAdmin\Partition
;
15 use PhpMyAdmin\Plugins\Export\ExportSql
;
16 use PhpMyAdmin\Relation
;
17 use PhpMyAdmin\Response
;
18 use PhpMyAdmin\StorageEngine
;
24 * Set of functions with the operations section in phpMyAdmin
31 * @var Relation $relation
38 public function __construct()
40 $this->relation
= new Relation();
44 * Get HTML output for database comment
46 * @param string $db database name
48 * @return string $html_output
50 public function getHtmlForDatabaseComment($db)
52 $html_output = '<div>'
53 . '<form method="post" action="db_operations.php" id="formDatabaseComment">'
54 . Url
::getHiddenInputs($db)
57 if (Util
::showIcons('ActionLinksMode')) {
58 $html_output .= Util
::getImage('b_comment') . ' ';
60 $html_output .= __('Database comment');
61 $html_output .= '</legend>';
62 $html_output .= '<input type="text" name="comment" '
64 . 'value="' . htmlspecialchars($this->relation
->getDbComment($db)) . '" />'
66 $html_output .= '<fieldset class="tblFooters">'
67 . '<input type="submit" value="' . __('Go') . '" />'
76 * Get HTML output for rename database
78 * @param string $db database name
79 * @param string $db_collation dataset collation
81 * @return string $html_output
83 public function getHtmlForRenameDatabase($db, $db_collation)
85 $html_output = '<div>'
86 . '<form id="rename_db_form" '
88 . 'method="post" action="db_operations.php" '
89 . 'onsubmit="return emptyCheckTheField(this, \'newname\')">';
90 if (isset($db_collation)) {
91 $html_output .= '<input type="hidden" name="db_collation" '
92 . 'value="' . $db_collation
95 $html_output .= '<input type="hidden" name="what" value="data" />'
96 . '<input type="hidden" name="db_rename" value="true" />'
97 . Url
::getHiddenInputs($db)
101 if (Util
::showIcons('ActionLinksMode')) {
102 $html_output .= Util
::getImage('b_edit') . ' ';
104 $html_output .= __('Rename database to')
107 $html_output .= '<input id="new_db_name" type="text" name="newname" '
108 . 'maxlength="64" class="textfield" required="required"/>';
109 $html_output .= '<br />';
111 if ($GLOBALS['db_priv'] && $GLOBALS['table_priv']
112 && $GLOBALS['col_priv'] && $GLOBALS['proc_priv']
113 && $GLOBALS['is_reload_priv']
115 $html_output .= '<input type="checkbox" name="adjust_privileges" '
116 . 'value="1" id="checkbox_adjust_privileges" checked="checked" />';
118 $html_output .= '<input type="checkbox" name="adjust_privileges" '
119 . 'value="1" id="checkbox_adjust_privileges" title="' . __(
120 'You don\'t have sufficient privileges to perform this '
121 . 'operation; Please refer to the documentation for more details'
126 $html_output .= '<label for="checkbox_adjust_privileges">'
127 . __('Adjust privileges') . Util
::showDocu('faq', 'faq6-39')
132 . '<fieldset class="tblFooters">'
133 . '<input id="rename_db_input" type="submit" value="' . __('Go') . '" />'
142 * Get HTML for database drop link
144 * @param string $db database name
146 * @return string $html_output
148 public function getHtmlForDropDatabaseLink($db)
150 $this_sql_query = 'DROP DATABASE ' . Util
::backquote($db);
151 $this_url_params = array(
152 'sql_query' => $this_sql_query,
153 'back' => 'db_operations.php',
154 'goto' => 'index.php',
157 'message_to_show' => sprintf(
158 __('Database %s has been dropped.'),
159 htmlspecialchars(Util
::backquote($db))
164 $html_output = '<div>'
165 . '<fieldset class="caution">';
166 $html_output .= '<legend>';
167 if (Util
::showIcons('ActionLinksMode')) {
168 $html_output .= Util
::getImage('b_deltbl') . ' ';
170 $html_output .= __('Remove database')
172 $html_output .= '<ul>';
173 $html_output .= $this->getDeleteDataOrTablelink(
176 __('Drop the database (DROP)'),
179 $html_output .= '</ul></fieldset>'
186 * Get HTML snippet for copy database
188 * @param string $db database name
189 * @param string $db_collation dataset collation
191 * @return string $html_output
193 public function getHtmlForCopyDatabase($db, $db_collation)
195 $drop_clause = 'DROP TABLE / DROP VIEW';
197 'structure' => __('Structure only'),
198 'data' => __('Structure and data'),
199 'dataonly' => __('Data only')
202 $pma_switch_to_new = isset($_SESSION['pma_switch_to_new']) && $_SESSION['pma_switch_to_new'];
204 $html_output = '<div>';
205 $html_output .= '<form id="copy_db_form" '
207 . 'method="post" action="db_operations.php" '
208 . 'onsubmit="return emptyCheckTheField(this, \'newname\')">';
210 if (isset($db_collation)) {
211 $html_output .= '<input type="hidden" name="db_collation" '
212 . 'value="' . $db_collation . '" />' . "\n";
214 $html_output .= '<input type="hidden" name="db_copy" value="true" />' . "\n"
215 . Url
::getHiddenInputs($db);
216 $html_output .= '<fieldset>'
219 if (Util
::showIcons('ActionLinksMode')) {
220 $html_output .= Util
::getImage('b_edit') . ' ';
222 $html_output .= __('Copy database to')
224 . '<input type="text" maxlength="64" name="newname" '
225 . 'class="textfield" required="required" /><br />'
226 . Util
::getRadioFields(
227 'what', $choices, 'data', true
229 $html_output .= '<br />';
230 $html_output .= '<input type="checkbox" name="create_database_before_copying" '
231 . 'value="1" id="checkbox_create_database_before_copying"'
232 . 'checked="checked" />';
233 $html_output .= '<label for="checkbox_create_database_before_copying">'
234 . __('CREATE DATABASE before copying') . '</label><br />';
235 $html_output .= '<input type="checkbox" name="drop_if_exists" value="true"'
236 . 'id="checkbox_drop" />';
237 $html_output .= '<label for="checkbox_drop">'
238 . sprintf(__('Add %s'), $drop_clause)
240 $html_output .= '<input type="checkbox" name="sql_auto_increment" value="1" '
241 . 'checked="checked" id="checkbox_auto_increment" />';
242 $html_output .= '<label for="checkbox_auto_increment">'
243 . __('Add AUTO_INCREMENT value') . '</label><br />';
244 $html_output .= '<input type="checkbox" name="add_constraints" value="1"'
245 . 'id="checkbox_constraints" checked="checked"/>';
246 $html_output .= '<label for="checkbox_constraints">'
247 . __('Add constraints') . '</label><br />';
248 $html_output .= '<br />';
250 if ($GLOBALS['db_priv'] && $GLOBALS['table_priv']
251 && $GLOBALS['col_priv'] && $GLOBALS['proc_priv']
252 && $GLOBALS['is_reload_priv']
254 $html_output .= '<input type="checkbox" name="adjust_privileges" '
255 . 'value="1" id="checkbox_privileges" checked="checked" />';
257 $html_output .= '<input type="checkbox" name="adjust_privileges" '
258 . 'value="1" id="checkbox_privileges" title="' . __(
259 'You don\'t have sufficient privileges to perform this '
260 . 'operation; Please refer to the documentation for more details'
264 $html_output .= '<label for="checkbox_privileges">'
265 . __('Adjust privileges') . Util
::showDocu('faq', 'faq6-39')
268 $html_output .= '<input type="checkbox" name="switch_to_new" value="true"'
269 . 'id="checkbox_switch"'
270 . ($pma_switch_to_new ?
' checked="checked"' : '') . '/>';
271 $html_output .= '<label for="checkbox_switch">'
272 . __('Switch to copied database') . '</label>'
274 $html_output .= '<fieldset class="tblFooters">'
275 . '<input type="submit" name="submit_copy" value="' . __('Go') . '" />'
284 * Get HTML snippet for change database charset
286 * @param string $db database name
287 * @param string $db_collation dataset collation
289 * @return string $html_output
291 public function getHtmlForChangeDatabaseCharset($db, $db_collation)
293 $html_output = '<div>'
294 . '<form id="change_db_charset_form" ';
295 $html_output .= 'class="ajax" ';
296 $html_output .= 'method="post" action="db_operations.php">';
298 $html_output .= Url
::getHiddenInputs($db);
300 $html_output .= '<fieldset>' . "\n"
302 if (Util
::showIcons('ActionLinksMode')) {
303 $html_output .= Util
::getImage('s_asci') . ' ';
305 $html_output .= '<label for="select_db_collation">' . __('Collation')
308 . Charsets
::getCollationDropdownBox(
310 $GLOBALS['cfg']['Server']['DisableIS'],
312 'select_db_collation',
313 isset($db_collation) ?
$db_collation : '',
317 . '<input type="checkbox" name="change_all_tables_collations"'
318 . 'id="checkbox_change_all_tables_collations" />'
319 . '<label for="checkbox_change_all_tables_collations">'
320 . __('Change all tables collations')
323 . '<span id="span_change_all_tables_columns_collations"><input type="checkbox" name="change_all_tables_columns_collations"'
324 . 'id="checkbox_change_all_tables_columns_collations" />'
325 . '<label for="checkbox_change_all_tables_columns_collations">'
326 . __('Change all tables columns collations')
329 . '<fieldset class="tblFooters">'
330 . '<input type="submit" name="submitcollation"'
331 . ' value="' . __('Go') . '" />' . "\n"
332 . '</fieldset>' . "\n"
333 . '</form></div>' . "\n";
339 * Run the Procedure definitions and function definitions
341 * to avoid selecting alternatively the current and new db
342 * we would need to modify the CREATE definitions to qualify
345 * @param string $db database name
349 public function runProcedureAndFunctionDefinitions($db)
351 $procedure_names = $GLOBALS['dbi']->getProceduresOrFunctions($db, 'PROCEDURE');
352 if ($procedure_names) {
353 foreach ($procedure_names as $procedure_name) {
354 $GLOBALS['dbi']->selectDb($db);
355 $tmp_query = $GLOBALS['dbi']->getDefinition(
356 $db, 'PROCEDURE', $procedure_name
358 if ($tmp_query !== false) {
359 // collect for later display
360 $GLOBALS['sql_query'] .= "\n" . $tmp_query;
361 $GLOBALS['dbi']->selectDb($_POST['newname']);
362 $GLOBALS['dbi']->query($tmp_query);
367 $function_names = $GLOBALS['dbi']->getProceduresOrFunctions($db, 'FUNCTION');
368 if ($function_names) {
369 foreach ($function_names as $function_name) {
370 $GLOBALS['dbi']->selectDb($db);
371 $tmp_query = $GLOBALS['dbi']->getDefinition(
372 $db, 'FUNCTION', $function_name
374 if ($tmp_query !== false) {
375 // collect for later display
376 $GLOBALS['sql_query'] .= "\n" . $tmp_query;
377 $GLOBALS['dbi']->selectDb($_POST['newname']);
378 $GLOBALS['dbi']->query($tmp_query);
385 * Create database before copy
389 public function createDbBeforeCopy()
391 $local_query = 'CREATE DATABASE IF NOT EXISTS '
392 . Util
::backquote($_POST['newname']);
393 if (isset($_POST['db_collation'])) {
394 $local_query .= ' DEFAULT'
395 . Util
::getCharsetQueryPart($_POST['db_collation']);
398 $GLOBALS['sql_query'] .= $local_query;
400 // save the original db name because Tracker.php which
401 // may be called under $GLOBALS['dbi']->query() changes $GLOBALS['db']
402 // for some statements, one of which being CREATE DATABASE
403 $original_db = $GLOBALS['db'];
404 $GLOBALS['dbi']->query($local_query);
405 $GLOBALS['db'] = $original_db;
407 // Set the SQL mode to NO_AUTO_VALUE_ON_ZERO to prevent MySQL from creating
408 // export statements it cannot import
409 $sql_set_mode = "SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO'";
410 $GLOBALS['dbi']->query($sql_set_mode);
412 // rebuild the database list because Table::moveCopy
413 // checks in this list if the target db exists
414 $GLOBALS['dblist']->databases
->build();
418 * Get views as an array and create SQL view stand-in
420 * @param array $tables_full array of all tables in given db or dbs
421 * @param ExportSql $export_sql_plugin export plugin instance
422 * @param string $db database name
424 * @return array $views
426 public function getViewsAndCreateSqlViewStandIn(
427 array $tables_full, $export_sql_plugin, $db
430 foreach ($tables_full as $each_table => $tmp) {
431 // to be able to rename a db containing views,
432 // first all the views are collected and a stand-in is created
433 // the real views are created after the tables
434 if ($GLOBALS['dbi']->getTable($db, $each_table)->isView()) {
436 // If view exists, and 'add drop view' is selected: Drop it!
437 if ($_POST['what'] != 'nocopy'
438 && isset($_POST['drop_if_exists'])
439 && $_POST['drop_if_exists'] == 'true'
441 $drop_query = 'DROP VIEW IF EXISTS '
442 . Util
::backquote($_POST['newname']) . '.'
443 . Util
::backquote($each_table);
444 $GLOBALS['dbi']->query($drop_query);
446 $GLOBALS['sql_query'] .= "\n" . $drop_query . ';';
449 $views[] = $each_table;
450 // Create stand-in definition to resolve view dependencies
451 $sql_view_standin = $export_sql_plugin->getTableDefStandIn(
452 $db, $each_table, "\n"
454 $GLOBALS['dbi']->selectDb($_POST['newname']);
455 $GLOBALS['dbi']->query($sql_view_standin);
456 $GLOBALS['sql_query'] .= "\n" . $sql_view_standin;
463 * Get sql query for copy/rename table and boolean for whether copy/rename or not
465 * @param array $tables_full array of all tables in given db or dbs
466 * @param boolean $move whether database name is empty or not
467 * @param string $db database name
469 * @return array SQL queries for the constraints
471 public function copyTables(array $tables_full, $move, $db)
473 $sqlContraints = array();
474 foreach ($tables_full as $each_table => $tmp) {
475 // skip the views; we have created stand-in definitions
476 if ($GLOBALS['dbi']->getTable($db, $each_table)->isView()) {
480 // value of $what for this table only
481 $this_what = $_POST['what'];
483 // do not copy the data from a Merge table
484 // note: on the calling FORM, 'data' means 'structure and data'
485 if ($GLOBALS['dbi']->getTable($db, $each_table)->isMerge()) {
486 if ($this_what == 'data') {
487 $this_what = 'structure';
489 if ($this_what == 'dataonly') {
490 $this_what = 'nocopy';
494 if ($this_what != 'nocopy') {
495 // keep the triggers from the original db+table
496 // (third param is empty because delimiters are only intended
497 // for importing via the mysql client or our Import feature)
498 $triggers = $GLOBALS['dbi']->getTriggers($db, $each_table, '');
500 if (! Table
::moveCopy(
501 $db, $each_table, $_POST['newname'], $each_table,
502 (isset($this_what) ?
$this_what : 'data'),
505 $GLOBALS['_error'] = true;
508 // apply the triggers to the destination db+table
510 $GLOBALS['dbi']->selectDb($_POST['newname']);
511 foreach ($triggers as $trigger) {
512 $GLOBALS['dbi']->query($trigger['create']);
513 $GLOBALS['sql_query'] .= "\n" . $trigger['create'] . ';';
517 // this does not apply to a rename operation
518 if (isset($_POST['add_constraints'])
519 && ! empty($GLOBALS['sql_constraints_query'])
521 $sqlContraints[] = $GLOBALS['sql_constraints_query'];
522 unset($GLOBALS['sql_constraints_query']);
526 return $sqlContraints;
530 * Run the EVENT definition for selected database
532 * to avoid selecting alternatively the current and new db
533 * we would need to modify the CREATE definitions to qualify
536 * @param string $db database name
540 public function runEventDefinitionsForDb($db)
542 $event_names = $GLOBALS['dbi']->fetchResult(
543 'SELECT EVENT_NAME FROM information_schema.EVENTS WHERE EVENT_SCHEMA= \''
544 . $GLOBALS['dbi']->escapeString($db) . '\';'
547 foreach ($event_names as $event_name) {
548 $GLOBALS['dbi']->selectDb($db);
549 $tmp_query = $GLOBALS['dbi']->getDefinition($db, 'EVENT', $event_name);
550 // collect for later display
551 $GLOBALS['sql_query'] .= "\n" . $tmp_query;
552 $GLOBALS['dbi']->selectDb($_POST['newname']);
553 $GLOBALS['dbi']->query($tmp_query);
559 * Handle the views, return the boolean value whether table rename/copy or not
561 * @param array $views views as an array
562 * @param boolean $move whether database name is empty or not
563 * @param string $db database name
567 public function handleTheViews(array $views, $move, $db)
569 // temporarily force to add DROP IF EXIST to CREATE VIEW query,
570 // to remove stand-in VIEW that was created earlier
571 // ( $_POST['drop_if_exists'] is used in moveCopy() )
572 if (isset($_POST['drop_if_exists'])) {
573 $temp_drop_if_exists = $_POST['drop_if_exists'];
576 $_POST['drop_if_exists'] = 'true';
577 foreach ($views as $view) {
578 $copying_succeeded = Table
::moveCopy(
579 $db, $view, $_POST['newname'], $view, 'structure', $move, 'db_copy'
581 if (! $copying_succeeded) {
582 $GLOBALS['_error'] = true;
586 unset($_POST['drop_if_exists']);
588 if (isset($temp_drop_if_exists)) {
589 // restore previous value
590 $_POST['drop_if_exists'] = $temp_drop_if_exists;
595 * Adjust the privileges after Renaming the db
597 * @param string $oldDb Database name before renaming
598 * @param string $newname New Database name requested
602 public function adjustPrivilegesMoveDb($oldDb, $newname)
604 if ($GLOBALS['db_priv'] && $GLOBALS['table_priv']
605 && $GLOBALS['col_priv'] && $GLOBALS['proc_priv']
606 && $GLOBALS['is_reload_priv']
608 $GLOBALS['dbi']->selectDb('mysql');
609 $newname = str_replace("_", "\_", $newname);
610 $oldDb = str_replace("_", "\_", $oldDb);
612 // For Db specific privileges
613 $query_db_specific = 'UPDATE ' . Util
::backquote('db')
614 . 'SET Db = \'' . $GLOBALS['dbi']->escapeString($newname)
615 . '\' where Db = \'' . $GLOBALS['dbi']->escapeString($oldDb) . '\';';
616 $GLOBALS['dbi']->query($query_db_specific);
618 // For table specific privileges
619 $query_table_specific = 'UPDATE ' . Util
::backquote('tables_priv')
620 . 'SET Db = \'' . $GLOBALS['dbi']->escapeString($newname)
621 . '\' where Db = \'' . $GLOBALS['dbi']->escapeString($oldDb) . '\';';
622 $GLOBALS['dbi']->query($query_table_specific);
624 // For column specific privileges
625 $query_col_specific = 'UPDATE ' . Util
::backquote('columns_priv')
626 . 'SET Db = \'' . $GLOBALS['dbi']->escapeString($newname)
627 . '\' where Db = \'' . $GLOBALS['dbi']->escapeString($oldDb) . '\';';
628 $GLOBALS['dbi']->query($query_col_specific);
630 // For procedures specific privileges
631 $query_proc_specific = 'UPDATE ' . Util
::backquote('procs_priv')
632 . 'SET Db = \'' . $GLOBALS['dbi']->escapeString($newname)
633 . '\' where Db = \'' . $GLOBALS['dbi']->escapeString($oldDb) . '\';';
634 $GLOBALS['dbi']->query($query_proc_specific);
636 // Finally FLUSH the new privileges
637 $flush_query = "FLUSH PRIVILEGES;";
638 $GLOBALS['dbi']->query($flush_query);
643 * Adjust the privileges after Copying the db
645 * @param string $oldDb Database name before copying
646 * @param string $newname New Database name requested
650 public function adjustPrivilegesCopyDb($oldDb, $newname)
652 if ($GLOBALS['db_priv'] && $GLOBALS['table_priv']
653 && $GLOBALS['col_priv'] && $GLOBALS['proc_priv']
654 && $GLOBALS['is_reload_priv']
656 $GLOBALS['dbi']->selectDb('mysql');
657 $newname = str_replace("_", "\_", $newname);
658 $oldDb = str_replace("_", "\_", $oldDb);
660 $query_db_specific_old = 'SELECT * FROM '
661 . Util
::backquote('db') . ' WHERE '
662 . 'Db = "' . $oldDb . '";';
664 $old_privs_db = $GLOBALS['dbi']->fetchResult($query_db_specific_old, 0);
666 foreach ($old_privs_db as $old_priv) {
667 $newDb_db_privs_query = 'INSERT INTO ' . Util
::backquote('db')
668 . ' VALUES("' . $old_priv[0] . '", "' . $newname . '", "'
669 . $old_priv[2] . '", "' . $old_priv[3] . '", "' . $old_priv[4]
670 . '", "' . $old_priv[5] . '", "' . $old_priv[6] . '", "'
671 . $old_priv[7] . '", "' . $old_priv[8] . '", "' . $old_priv[9]
672 . '", "' . $old_priv[10] . '", "' . $old_priv[11] . '", "'
673 . $old_priv[12] . '", "' . $old_priv[13] . '", "' . $old_priv[14]
674 . '", "' . $old_priv[15] . '", "' . $old_priv[16] . '", "'
675 . $old_priv[17] . '", "' . $old_priv[18] . '", "' . $old_priv[19]
676 . '", "' . $old_priv[20] . '", "' . $old_priv[21] . '");';
678 $GLOBALS['dbi']->query($newDb_db_privs_query);
681 // For Table Specific privileges
682 $query_table_specific_old = 'SELECT * FROM '
683 . Util
::backquote('tables_priv') . ' WHERE '
684 . 'Db = "' . $oldDb . '";';
686 $old_privs_table = $GLOBALS['dbi']->fetchResult(
687 $query_table_specific_old,
691 foreach ($old_privs_table as $old_priv) {
692 $newDb_table_privs_query = 'INSERT INTO ' . Util
::backquote(
694 ) . ' VALUES("' . $old_priv[0] . '", "' . $newname . '", "'
695 . $old_priv[2] . '", "' . $old_priv[3] . '", "' . $old_priv[4]
696 . '", "' . $old_priv[5] . '", "' . $old_priv[6] . '", "'
697 . $old_priv[7] . '");';
699 $GLOBALS['dbi']->query($newDb_table_privs_query);
702 // For Column Specific privileges
703 $query_col_specific_old = 'SELECT * FROM '
704 . Util
::backquote('columns_priv') . ' WHERE '
705 . 'Db = "' . $oldDb . '";';
707 $old_privs_col = $GLOBALS['dbi']->fetchResult(
708 $query_col_specific_old,
712 foreach ($old_privs_col as $old_priv) {
713 $newDb_col_privs_query = 'INSERT INTO ' . Util
::backquote(
715 ) . ' VALUES("' . $old_priv[0] . '", "' . $newname . '", "'
716 . $old_priv[2] . '", "' . $old_priv[3] . '", "' . $old_priv[4]
717 . '", "' . $old_priv[5] . '", "' . $old_priv[6] . '");';
719 $GLOBALS['dbi']->query($newDb_col_privs_query);
722 // For Procedure Specific privileges
723 $query_proc_specific_old = 'SELECT * FROM '
724 . Util
::backquote('procs_priv') . ' WHERE '
725 . 'Db = "' . $oldDb . '";';
727 $old_privs_proc = $GLOBALS['dbi']->fetchResult(
728 $query_proc_specific_old,
732 foreach ($old_privs_proc as $old_priv) {
733 $newDb_proc_privs_query = 'INSERT INTO ' . Util
::backquote(
735 ) . ' VALUES("' . $old_priv[0] . '", "' . $newname . '", "'
736 . $old_priv[2] . '", "' . $old_priv[3] . '", "' . $old_priv[4]
737 . '", "' . $old_priv[5] . '", "' . $old_priv[6] . '", "'
738 . $old_priv[7] . '");';
740 $GLOBALS['dbi']->query($newDb_proc_privs_query);
743 // Finally FLUSH the new privileges
744 $flush_query = "FLUSH PRIVILEGES;";
745 $GLOBALS['dbi']->query($flush_query);
750 * Create all accumulated constraints
752 * @param array $sqlConstratints array of sql constraints for the database
756 public function createAllAccumulatedConstraints(array $sqlConstratints)
758 $GLOBALS['dbi']->selectDb($_POST['newname']);
759 foreach ($sqlConstratints as $one_query) {
760 $GLOBALS['dbi']->query($one_query);
761 // and prepare to display them
762 $GLOBALS['sql_query'] .= "\n" . $one_query;
767 * Duplicate the bookmarks for the db (done once for each db)
769 * @param boolean $_error whether table rename/copy or not
770 * @param string $db database name
774 public function duplicateBookmarks($_error, $db)
776 if (! $_error && $db != $_POST['newname']) {
777 $get_fields = array('user', 'label', 'query');
778 $where_fields = array('dbase' => $db);
779 $new_fields = array('dbase' => $_POST['newname']);
780 Table
::duplicateInfo(
781 'bookmarkwork', 'bookmark', $get_fields,
782 $where_fields, $new_fields
788 * Get the HTML snippet for order the table
790 * @param array $columns columns array
792 * @return string $html_out
794 public function getHtmlForOrderTheTable(array $columns)
796 $html_output = '<div>';
797 $html_output .= '<form method="post" id="alterTableOrderby" '
798 . 'action="tbl_operations.php">';
799 $html_output .= Url
::getHiddenInputs(
800 $GLOBALS['db'], $GLOBALS['table']
802 $html_output .= '<fieldset id="fieldset_table_order">'
803 . '<legend>' . __('Alter table order by') . '</legend>'
804 . '<select name="order_field">';
806 foreach ($columns as $fieldname) {
807 $html_output .= '<option '
808 . 'value="' . htmlspecialchars($fieldname['Field']) . '">'
809 . htmlspecialchars($fieldname['Field']) . '</option>' . "\n";
811 $html_output .= '</select> ' . __('(singly)') . ' '
813 . '<input id="order_order_asc" name="order_order"'
814 . ' type="radio" value="asc" checked="checked" />'
815 . '<label for="order_order_asc">' . __('Ascending') . '</label>'
816 . '<input id="order_order_desc" name="order_order"'
817 . ' type="radio" value="desc" />'
818 . '<label for="order_order_desc">' . __('Descending') . '</label>'
820 . '<fieldset class="tblFooters">'
821 . '<input type="hidden" name="submitorderby" value="1" />'
822 . '<input type="submit" value="' . __('Go') . '" />'
831 * Get the HTML snippet for move table
833 * @return string $html_output
835 public function getHtmlForMoveTable()
837 $html_output = '<div>';
838 $html_output .= '<form method="post" action="tbl_operations.php"'
839 . ' id="moveTableForm" class="ajax"'
840 . ' onsubmit="return emptyCheckTheField(this, \'new_name\')">'
841 . Url
::getHiddenInputs($GLOBALS['db'], $GLOBALS['table']);
843 $html_output .= '<input type="hidden" name="reload" value="1" />'
844 . '<input type="hidden" name="what" value="data" />'
845 . '<fieldset id="fieldset_table_rename">';
847 $html_output .= '<legend>' . __('Move table to (database<b>.</b>table)')
850 if (count($GLOBALS['dblist']->databases
) > $GLOBALS['cfg']['MaxDbList']) {
851 $html_output .= '<input type="text" maxlength="100" '
852 . 'name="target_db" value="' . htmlspecialchars($GLOBALS['db'])
855 $html_output .= '<select class="halfWidth" name="target_db">'
856 . $GLOBALS['dblist']->databases
->getHtmlOptions(true, false)
859 $html_output .= ' <strong>.</strong> ';
860 $html_output .= '<input class="halfWidth" type="text" name="new_name"'
861 . ' maxlength="64" required="required" '
862 . 'value="' . htmlspecialchars($GLOBALS['table']) . '" /><br />';
864 // starting with MySQL 5.0.24, SHOW CREATE TABLE includes the AUTO_INCREMENT
865 // next value but users can decide if they want it or not for the operation
867 $html_output .= '<input type="checkbox" name="sql_auto_increment" '
868 . 'value="1" id="checkbox_auto_increment_mv" checked="checked" />'
869 . '<label for="checkbox_auto_increment_mv">'
870 . __('Add AUTO_INCREMENT value')
873 if ($GLOBALS['table_priv'] && $GLOBALS['col_priv']
874 && $GLOBALS['is_reload_priv']
876 $html_output .= '<input type="checkbox" name="adjust_privileges" '
877 . 'value="1" id="checkbox_privileges_tables_move" '
878 . 'checked="checked" />';
880 $html_output .= '<input type="checkbox" name="adjust_privileges" '
881 . 'value="1" id="checkbox_privileges_tables_move" title="' . __(
882 'You don\'t have sufficient privileges to perform this '
883 . 'operation; Please refer to the documentation for more details'
887 $html_output .= '<label for="checkbox_privileges_tables_move">'
888 . __('Adjust privileges') . Util
::showDocu('faq', 'faq6-39')
891 $html_output .= '</fieldset><fieldset class="tblFooters">'
892 . '<input type="submit" name="submit_move" value="' . __('Go') . '" />'
901 * Get the HTML div for Table option
903 * @param Table $pma_table Table object
904 * @param string $comment Comment
905 * @param array $tbl_collation table collation
906 * @param string $tbl_storage_engine table storage engine
907 * @param string $pack_keys pack keys
908 * @param string $auto_increment value of auto increment
909 * @param string $delay_key_write delay key write
910 * @param string $transactional value of transactional
911 * @param string $page_checksum value of page checksum
912 * @param string $checksum the checksum
914 * @return string $html_output
916 public function getTableOptionDiv($pma_table, $comment, $tbl_collation, $tbl_storage_engine,
917 $pack_keys, $auto_increment, $delay_key_write,
918 $transactional, $page_checksum, $checksum
920 $html_output = '<div>';
921 $html_output .= '<form method="post" action="tbl_operations.php"';
922 $html_output .= ' id="tableOptionsForm" class="ajax">';
923 $html_output .= Url
::getHiddenInputs(
924 $GLOBALS['db'], $GLOBALS['table']
926 $html_output .= '<input type="hidden" name="reload" value="1" />';
928 $html_output .= $this->getTableOptionFieldset(
929 $pma_table, $comment, $tbl_collation,
930 $tbl_storage_engine, $pack_keys,
931 $delay_key_write, $auto_increment, $transactional, $page_checksum,
935 $html_output .= '<fieldset class="tblFooters">'
936 . '<input type="hidden" name="submitoptions" value="1" />'
937 . '<input type="submit" value="' . __('Go') . '" />'
946 * Get HTML for the rename table part of table options
948 * @return string $html_output
950 private function getHtmlForRenameTable()
952 $html_output = '<tr><td class="vmiddle">' . __('Rename table to') . '</td>'
954 . '<input type="text" name="new_name" maxlength="64" '
955 . 'value="' . htmlspecialchars($GLOBALS['table'])
956 . '" required="required" />'
958 . '<tr><td></td><td>';
960 if ($GLOBALS['table_priv'] && $GLOBALS['col_priv']
961 && $GLOBALS['is_reload_priv']
963 $html_output .= '<input type="checkbox" name="adjust_privileges" '
964 . 'value="1" id="checkbox_privileges_table_options" '
965 . 'checked="checked" />';
967 $html_output .= '<input type="checkbox" name="adjust_privileges" '
968 . 'value="1" id="checkbox_privileges_table_options" title="' . __(
969 'You don\'t have sufficient privileges to perform this '
970 . 'operation; Please refer to the documentation for more details'
974 $html_output .= '<label for="checkbox_privileges_table_options">'
975 . __('Adjust privileges') . ' '
976 . Util
::showDocu('faq', 'faq6-39') . '</label>';
978 $html_output .= '</td></tr>';
983 * Get HTML for the table comments part of table options
985 * @param string $current_value of the table comments
987 * @return string $html_output
989 private function getHtmlForTableComments($current_value)
991 $commentLength = $GLOBALS['dbi']->getVersion() >= 50503 ?
2048 : 60;
992 $html_output = '<tr><td class="vmiddle">' . __('Table comments') . '</td>'
993 . '<td><input type="text" name="comment" '
994 . 'maxlength="' . $commentLength . '"'
995 . 'value="' . htmlspecialchars($current_value) . '" />'
996 . '<input type="hidden" name="prev_comment" value="'
997 . htmlspecialchars($current_value) . '" />'
1001 return $html_output;
1005 * Get HTML for the PACK KEYS part of table options
1007 * @param string $current_value of the pack keys option
1009 * @return string $html_output
1011 private function getHtmlForPackKeys($current_value)
1013 $html_output = '<tr>'
1014 . '<td class="vmiddle"><label for="new_pack_keys">PACK_KEYS</label></td>'
1015 . '<td><select name="new_pack_keys" id="new_pack_keys">';
1017 $html_output .= '<option value="DEFAULT"';
1018 if ($current_value == 'DEFAULT') {
1019 $html_output .= 'selected="selected"';
1021 $html_output .= '>DEFAULT</option>
1023 if ($current_value == '0') {
1024 $html_output .= 'selected="selected"';
1026 $html_output .= '>0</option>
1027 <option value="1" ';
1028 if ($current_value == '1') {
1029 $html_output .= 'selected="selected"';
1031 $html_output .= '>1</option>'
1036 return $html_output;
1040 * Get HTML fieldset for Table option, it contains HTML table for options
1042 * @param Table $pma_table Table object
1043 * @param string $comment Comment
1044 * @param array $tbl_collation table collation
1045 * @param string $tbl_storage_engine table storage engine
1046 * @param string $pack_keys pack keys
1047 * @param string $delay_key_write delay key write
1048 * @param string $auto_increment value of auto increment
1049 * @param string $transactional value of transactional
1050 * @param string $page_checksum value of page checksum
1051 * @param string $checksum the checksum
1053 * @return string $html_output
1055 private function getTableOptionFieldset($pma_table, $comment, $tbl_collation,
1056 $tbl_storage_engine, $pack_keys,
1057 $delay_key_write, $auto_increment, $transactional,
1058 $page_checksum, $checksum
1060 $html_output = '<fieldset>'
1061 . '<legend>' . __('Table options') . '</legend>';
1063 $html_output .= '<table>';
1064 $html_output .= $this->getHtmlForRenameTable();
1065 $html_output .= $this->getHtmlForTableComments($comment);
1068 $html_output .= '<tr><td class="vmiddle">' . __('Storage Engine')
1069 . ' ' . Util
::showMySQLDocu('Storage_engines')
1072 . StorageEngine
::getHtmlSelect(
1073 'new_tbl_storage_engine', null, $tbl_storage_engine
1078 //Table character set
1079 $html_output .= '<tr><td class="vmiddle">' . __('Collation') . '</td>'
1081 . Charsets
::getCollationDropdownBox(
1083 $GLOBALS['cfg']['Server']['DisableIS'],
1092 // Change all Column collations
1093 $html_output .= '<tr><td></td><td>'
1094 . '<input type="checkbox" name="change_all_collations" value="1" '
1095 . 'id="checkbox_change_all_collations" />'
1096 . '<label for="checkbox_change_all_collations">'
1097 . __('Change all column collations')
1101 if ($pma_table->isEngine(array('MYISAM', 'ARIA', 'ISAM'))) {
1102 $html_output .= $this->getHtmlForPackKeys($pack_keys);
1103 } // end if (MYISAM|ISAM)
1105 if ($pma_table->isEngine(array('MYISAM', 'ARIA'))) {
1106 $html_output .= $this->getHtmlForTableRow(
1112 $html_output .= $this->getHtmlForTableRow(
1113 'new_delay_key_write',
1117 } // end if (MYISAM)
1119 if ($pma_table->isEngine('ARIA')) {
1120 $html_output .= $this->getHtmlForTableRow(
1121 'new_transactional',
1126 $html_output .= $this->getHtmlForTableRow(
1127 'new_page_checksum',
1133 if (strlen($auto_increment) > 0
1134 && $pma_table->isEngine(array('MYISAM', 'ARIA', 'INNODB', 'PBXT', 'ROCKSDB'))
1136 $html_output .= '<tr><td class="vmiddle">'
1137 . '<label for="auto_increment_opt">AUTO_INCREMENT</label></td>'
1138 . '<td><input type="number" name="new_auto_increment" '
1139 . 'id="auto_increment_opt"'
1140 . 'value="' . $auto_increment . '" /></td>'
1142 } // end if (MYISAM|INNODB)
1144 $possible_row_formats = $this->getPossibleRowFormat();
1146 // for MYISAM there is also COMPRESSED but it can be set only by the
1147 // myisampack utility, so don't offer here the choice because if we
1148 // try it inside an ALTER TABLE, MySQL (at least in 5.1.23-maria)
1149 // does not return a warning
1150 // (if the table was compressed, it can be seen on the Structure page)
1152 if (isset($possible_row_formats[$tbl_storage_engine])) {
1154 = mb_strtoupper($GLOBALS['showtable']['Row_format']);
1155 $html_output .= '<tr><td class="vmiddle">'
1156 . '<label for="new_row_format">ROW_FORMAT</label></td>'
1158 $html_output .= Util
::getDropdown(
1159 'new_row_format', $possible_row_formats[$tbl_storage_engine],
1160 $current_row_format, 'new_row_format'
1162 $html_output .= '</td></tr>';
1164 $html_output .= '</table>'
1167 return $html_output;
1171 * Get the common HTML table row (tr) for new_checksum, new_delay_key_write,
1172 * new_transactional and new_page_checksum
1174 * @param string $attribute class, name and id attribute
1175 * @param string $label label value
1176 * @param string $val checksum, delay_key_write, transactional, page_checksum
1178 * @return string $html_output
1180 private function getHtmlForTableRow($attribute, $label, $val)
1183 . '<td class="vmiddle">'
1184 . '<label for="' . $attribute . '">' . $label . '</label>'
1187 . '<input type="checkbox" name="' . $attribute . '" id="' . $attribute . '"'
1188 . ' value="1"' . ((!empty($val) && $val == 1) ?
' checked="checked"' : '')
1195 * Get array of possible row formats
1197 * @return array $possible_row_formats
1199 private function getPossibleRowFormat()
1201 // the outer array is for engines, the inner array contains the dropdown
1202 // option values as keys then the dropdown option labels
1204 $possible_row_formats = array(
1206 'COMPRESSED' => 'COMPRESSED',
1210 'DYNAMIC' => 'DYNAMIC',
1215 'DYNAMIC' => 'DYNAMIC',
1220 'DYNAMIC' => 'DYNAMIC'
1224 'DYNAMIC' => 'DYNAMIC'
1227 'COMPACT' => 'COMPACT',
1228 'REDUNDANT' => 'REDUNDANT'
1232 /** @var Innodb $innodbEnginePlugin */
1233 $innodbEnginePlugin = StorageEngine
::getEngine('Innodb');
1234 $innodbPluginVersion = $innodbEnginePlugin->getInnodbPluginVersion();
1235 if (!empty($innodbPluginVersion)) {
1236 $innodb_file_format = $innodbEnginePlugin->getInnodbFileFormat();
1238 $innodb_file_format = '';
1241 * Newer MySQL/MariaDB always return empty a.k.a '' on $innodb_file_format otherwise
1242 * old versions of MySQL/MariaDB must be returning something or not empty.
1243 * This patch is to support newer MySQL/MariaDB while also for backward compatibilities.
1245 if (( ('Barracuda' == $innodb_file_format) ||
($innodb_file_format == '') )
1246 && $innodbEnginePlugin->supportsFilePerTable()
1248 $possible_row_formats['INNODB']['DYNAMIC'] = 'DYNAMIC';
1249 $possible_row_formats['INNODB']['COMPRESSED'] = 'COMPRESSED';
1252 return $possible_row_formats;
1256 * Get HTML div for copy table
1258 * @return string $html_output
1260 public function getHtmlForCopytable()
1262 $html_output = '<div>';
1263 $html_output .= '<form method="post" action="tbl_operations.php" '
1264 . 'name="copyTable" '
1267 . 'onsubmit="return emptyCheckTheField(this, \'new_name\')">'
1268 . Url
::getHiddenInputs($GLOBALS['db'], $GLOBALS['table'])
1269 . '<input type="hidden" name="reload" value="1" />';
1271 $html_output .= '<fieldset>';
1272 $html_output .= '<legend>'
1273 . __('Copy table to (database<b>.</b>table)') . '</legend>';
1275 if (count($GLOBALS['dblist']->databases
) > $GLOBALS['cfg']['MaxDbList']) {
1276 $html_output .= '<input class="halfWidth" type="text" maxlength="100" '
1277 . 'name="target_db" '
1278 . 'value="' . htmlspecialchars($GLOBALS['db']) . '"/>';
1280 $html_output .= '<select class="halfWidth" name="target_db">'
1281 . $GLOBALS['dblist']->databases
->getHtmlOptions(true, false)
1284 $html_output .= ' <strong>.</strong> ';
1285 $html_output .= '<input class="halfWidth" type="text" required="required" '
1286 . 'name="new_name" maxlength="64" '
1287 . 'value="' . htmlspecialchars($GLOBALS['table']) . '"/><br />';
1290 'structure' => __('Structure only'),
1291 'data' => __('Structure and data'),
1292 'dataonly' => __('Data only')
1295 $html_output .= Util
::getRadioFields(
1296 'what', $choices, 'data', true
1298 $html_output .= '<br />';
1300 $html_output .= '<input type="checkbox" name="drop_if_exists" '
1301 . 'value="true" id="checkbox_drop" />'
1302 . '<label for="checkbox_drop">'
1303 . sprintf(__('Add %s'), 'DROP TABLE') . '</label><br />'
1304 . '<input type="checkbox" name="sql_auto_increment" '
1305 . 'value="1" id="checkbox_auto_increment_cp" />'
1306 . '<label for="checkbox_auto_increment_cp">'
1307 . __('Add AUTO_INCREMENT value') . '</label><br />';
1309 // display "Add constraints" choice only if there are
1311 if ($this->relation
->getForeigners($GLOBALS['db'], $GLOBALS['table'], '', 'foreign')) {
1312 $html_output .= '<input type="checkbox" name="add_constraints" '
1313 . 'value="1" id="checkbox_constraints" checked="checked"/>';
1314 $html_output .= '<label for="checkbox_constraints">'
1315 . __('Add constraints') . '</label><br />';
1318 $html_output .= '<br />';
1320 if ($GLOBALS['table_priv'] && $GLOBALS['col_priv']
1321 && $GLOBALS['is_reload_priv']
1323 $html_output .= '<input type="checkbox" name="adjust_privileges" '
1324 . 'value="1" id="checkbox_adjust_privileges" checked="checked" />';
1326 $html_output .= '<input type="checkbox" name="adjust_privileges" '
1327 . 'value="1" id="checkbox_adjust_privileges" title="' . __(
1328 'You don\'t have sufficient privileges to perform this '
1329 . 'operation; Please refer to the documentation for more details'
1333 $html_output .= '<label for="checkbox_adjust_privileges">'
1334 . __('Adjust privileges') . Util
::showDocu('faq', 'faq6-39')
1337 $pma_switch_to_new = isset($_SESSION['pma_switch_to_new']) && $_SESSION['pma_switch_to_new'];
1339 $html_output .= '<input type="checkbox" name="switch_to_new" value="true"'
1340 . 'id="checkbox_switch"'
1341 . ($pma_switch_to_new ?
' checked="checked"' : '') . '/>';
1342 $html_output .= '<label for="checkbox_switch">'
1343 . __('Switch to copied table') . '</label>'
1346 $html_output .= '<fieldset class="tblFooters">'
1347 . '<input type="submit" name="submit_copy" value="' . __('Go') . '" />'
1352 return $html_output;
1356 * Get HTML snippet for table maintenance
1358 * @param Table $pma_table Table object
1359 * @param array $url_params array of URL parameters
1361 * @return string $html_output
1363 public function getHtmlForTableMaintenance($pma_table, array $url_params)
1365 $html_output = '<div>';
1366 $html_output .= '<fieldset>'
1367 . '<legend>' . __('Table maintenance') . '</legend>';
1368 $html_output .= '<ul id="tbl_maintenance">';
1370 // Note: BERKELEY (BDB) is no longer supported, starting with MySQL 5.1
1371 $html_output .= $this->getListofMaintainActionLink($pma_table, $url_params);
1373 $html_output .= '</ul>'
1377 return $html_output;
1381 * Get HTML 'li' having a link of maintain action
1383 * @param Table $pma_table Table object
1384 * @param array $url_params Array of URL parameters
1386 * @return string $html_output
1388 private function getListofMaintainActionLink($pma_table, array $url_params)
1393 if ($pma_table->isEngine(array('MYISAM', 'ARIA', 'INNODB', 'BERKELEYDB', 'TOKUDB'))) {
1395 'sql_query' => 'ANALYZE TABLE '
1396 . Util
::backquote($GLOBALS['table']),
1397 'table_maintenance' => 'Go',
1399 $html_output .= $this->getMaintainActionlink(
1400 __('Analyze table'),
1408 if ($pma_table->isEngine(array('MYISAM', 'ARIA', 'INNODB', 'TOKUDB'))) {
1410 'sql_query' => 'CHECK TABLE '
1411 . Util
::backquote($GLOBALS['table']),
1412 'table_maintenance' => 'Go',
1414 $html_output .= $this->getMaintainActionlink(
1424 'sql_query' => 'CHECKSUM TABLE '
1425 . Util
::backquote($GLOBALS['table']),
1426 'table_maintenance' => 'Go',
1428 $html_output .= $this->getMaintainActionlink(
1429 __('Checksum table'),
1436 if ($pma_table->isEngine(array('INNODB'))) {
1438 'sql_query' => 'ALTER TABLE '
1439 . Util
::backquote($GLOBALS['table'])
1440 . ' ENGINE = InnoDB;'
1442 $html_output .= $this->getMaintainActionlink(
1443 __('Defragment table'),
1446 'InnoDB_File_Defragmenting'
1452 'sql_query' => 'FLUSH TABLE '
1453 . Util
::backquote($GLOBALS['table']),
1454 'message_to_show' => sprintf(
1455 __('Table %s has been flushed.'),
1456 htmlspecialchars($GLOBALS['table'])
1460 $html_output .= $this->getMaintainActionlink(
1461 __('Flush the table (FLUSH)'),
1468 if ($pma_table->isEngine(array('MYISAM', 'ARIA', 'INNODB', 'BERKELEYDB', 'TOKUDB'))) {
1470 'sql_query' => 'OPTIMIZE TABLE '
1471 . Util
::backquote($GLOBALS['table']),
1472 'table_maintenance' => 'Go',
1474 $html_output .= $this->getMaintainActionlink(
1475 __('Optimize table'),
1483 if ($pma_table->isEngine(array('MYISAM', 'ARIA'))) {
1485 'sql_query' => 'REPAIR TABLE '
1486 . Util
::backquote($GLOBALS['table']),
1487 'table_maintenance' => 'Go',
1489 $html_output .= $this->getMaintainActionlink(
1497 return $html_output;
1501 * Get maintain action HTML link
1503 * @param string $action_message action message
1504 * @param array $params url parameters array
1505 * @param array $url_params additional url parameters
1506 * @param string $link contains name of page/anchor that is being linked
1508 * @return string $html_output
1510 private function getMaintainActionlink($action_message, array $params, array $url_params, $link)
1513 . Util
::linkOrButton(
1514 'sql.php' . Url
::getCommon(array_merge($url_params, $params)),
1516 ['class' => 'maintain_action ajax']
1518 . Util
::showMySQLDocu($link)
1523 * Get HTML for Delete data or table (truncate table, drop table)
1525 * @param array $truncate_table_url_params url parameter array for truncate table
1526 * @param array $dropTableUrlParams url parameter array for drop table
1528 * @return string $html_output
1530 public function getHtmlForDeleteDataOrTable(
1531 array $truncate_table_url_params,
1532 array $dropTableUrlParams
1534 $html_output = '<div>'
1535 . '<fieldset class="caution">'
1536 . '<legend>' . __('Delete data or table') . '</legend>';
1538 $html_output .= '<ul>';
1540 if (! empty($truncate_table_url_params)) {
1541 $html_output .= $this->getDeleteDataOrTablelink(
1542 $truncate_table_url_params,
1544 __('Empty the table (TRUNCATE)'),
1545 'truncate_tbl_anchor'
1548 if (!empty($dropTableUrlParams)) {
1549 $html_output .= $this->getDeleteDataOrTablelink(
1550 $dropTableUrlParams,
1552 __('Delete the table (DROP)'),
1556 $html_output .= '</ul></fieldset></div>';
1558 return $html_output;
1562 * Get the HTML link for Truncate table, Drop table and Drop db
1564 * @param array $url_params url parameter array for delete data or table
1565 * @param string $syntax TRUNCATE_TABLE or DROP_TABLE or DROP_DATABASE
1566 * @param string $link link to be shown
1567 * @param string $htmlId id of the link
1569 * @return string html output
1571 public function getDeleteDataOrTablelink(array $url_params, $syntax, $link, $htmlId)
1573 return '<li>' . Util
::linkOrButton(
1574 'sql.php' . Url
::getCommon($url_params),
1576 array('id' => $htmlId, 'class' => 'ajax')
1578 . Util
::showMySQLDocu($syntax)
1583 * Get HTML snippet for partition maintenance
1585 * @param array $partition_names array of partition names for a specific db/table
1586 * @param array $url_params url parameters
1588 * @return string $html_output
1590 public function getHtmlForPartitionMaintenance(array $partition_names, array $url_params)
1593 'ANALYZE' => __('Analyze'),
1594 'CHECK' => __('Check'),
1595 'OPTIMIZE' => __('Optimize'),
1596 'REBUILD' => __('Rebuild'),
1597 'REPAIR' => __('Repair'),
1598 'TRUNCATE' => __('Truncate')
1601 $partition_method = Partition
::getPartitionMethod(
1602 $GLOBALS['db'], $GLOBALS['table']
1604 // add COALESCE or DROP option to choices array depeding on Partition method
1605 if ($partition_method == 'RANGE'
1606 ||
$partition_method == 'RANGE COLUMNS'
1607 ||
$partition_method == 'LIST'
1608 ||
$partition_method == 'LIST COLUMNS'
1610 $choices['DROP'] = __('Drop');
1612 $choices['COALESCE'] = __('Coalesce');
1615 $html_output = '<div>'
1616 . '<form id="partitionsForm" class="ajax" '
1617 . 'method="post" action="tbl_operations.php" >'
1618 . Url
::getHiddenInputs($GLOBALS['db'], $GLOBALS['table'])
1621 . __('Partition maintenance')
1622 . Util
::showMySQLDocu('partitioning_maintenance')
1625 $html_select = '<select id="partition_name" name="partition_name[]"'
1626 . ' multiple="multiple" required="required">' . "\n";
1628 foreach ($partition_names as $one_partition) {
1629 $one_partition = htmlspecialchars($one_partition);
1630 $html_select .= '<option value="' . $one_partition . '"';
1632 $html_select .= ' selected="selected"';
1635 $html_select .= '>' . $one_partition . '</option>' . "\n";
1637 $html_select .= '</select>' . "\n";
1638 $html_output .= sprintf(__('Partition %s'), $html_select);
1640 $html_output .= '<div class="clearfloat" />';
1641 $html_output .= Util
::getRadioFields(
1642 'partition_operation', $choices, 'ANALYZE', false, true, 'floatleft'
1644 $this_url_params = array_merge(
1647 'sql_query' => 'ALTER TABLE '
1648 . Util
::backquote($GLOBALS['table'])
1649 . ' REMOVE PARTITIONING;'
1652 $html_output .= '<div class="clearfloat" /><br />';
1654 $html_output .= '<a href="sql.php'
1655 . Url
::getCommon($this_url_params) . '">'
1656 . __('Remove partitioning') . '</a>';
1658 $html_output .= '</fieldset>'
1659 . '<fieldset class="tblFooters">'
1660 . '<input type="hidden" name="submit_partition" value="1">'
1661 . '<input type="submit" value="' . __('Go') . '" />'
1666 return $html_output;
1670 * Get the HTML for Referential Integrity check
1672 * @param array $foreign all Relations to foreign tables for a given table
1673 * or optionally a given column in a table
1674 * @param array $url_params array of url parameters
1676 * @return string $html_output
1678 public function getHtmlForReferentialIntegrityCheck(array $foreign, array $url_params)
1680 $html_output = '<div>'
1682 . '<legend>' . __('Check referential integrity:') . '</legend>';
1684 $html_output .= '<ul>';
1686 foreach ($foreign as $master => $arr) {
1687 $join_query = 'SELECT '
1688 . Util
::backquote($GLOBALS['table']) . '.*'
1689 . ' FROM ' . Util
::backquote($GLOBALS['table'])
1691 . Util
::backquote($arr['foreign_db'])
1693 . Util
::backquote($arr['foreign_table']);
1694 if ($arr['foreign_table'] == $GLOBALS['table']) {
1695 $foreign_table = $GLOBALS['table'] . '1';
1696 $join_query .= ' AS ' . Util
::backquote($foreign_table);
1698 $foreign_table = $arr['foreign_table'];
1700 $join_query .= ' ON '
1701 . Util
::backquote($GLOBALS['table']) . '.'
1702 . Util
::backquote($master)
1704 . Util
::backquote($arr['foreign_db'])
1706 . Util
::backquote($foreign_table) . '.'
1707 . Util
::backquote($arr['foreign_field'])
1709 . Util
::backquote($arr['foreign_db'])
1711 . Util
::backquote($foreign_table) . '.'
1712 . Util
::backquote($arr['foreign_field'])
1714 . Util
::backquote($GLOBALS['table']) . '.'
1715 . Util
::backquote($master)
1717 $this_url_params = array_merge(
1720 'sql_query' => $join_query,
1721 'sql_signature' => Core
::signSqlQuery($join_query),
1725 $html_output .= '<li>'
1726 . '<a href="sql.php'
1727 . Url
::getCommon($this_url_params)
1729 . $master . ' -> ' . $arr['foreign_db'] . '.'
1730 . $arr['foreign_table'] . '.' . $arr['foreign_field']
1731 . '</a></li>' . "\n";
1732 } // foreach $foreign
1733 $html_output .= '</ul></fieldset></div>';
1735 return $html_output;
1739 * Reorder table based on request params
1741 * @return array SQL query and result
1743 public function getQueryAndResultForReorderingTable()
1745 $sql_query = 'ALTER TABLE '
1746 . Util
::backquote($GLOBALS['table'])
1748 . Util
::backquote(urldecode($_POST['order_field']));
1749 if (isset($_POST['order_order'])
1750 && $_POST['order_order'] === 'desc'
1752 $sql_query .= ' DESC';
1754 $sql_query .= ' ASC';
1757 $result = $GLOBALS['dbi']->query($sql_query);
1759 return array($sql_query, $result);
1763 * Get table alters array
1765 * @param Table $pma_table The Table object
1766 * @param string $pack_keys pack keys
1767 * @param string $checksum value of checksum
1768 * @param string $page_checksum value of page checksum
1769 * @param string $delay_key_write delay key write
1770 * @param string $row_format row format
1771 * @param string $newTblStorageEngine table storage engine
1772 * @param string $transactional value of transactional
1773 * @param string $tbl_collation collation of the table
1775 * @return array $table_alters
1777 public function getTableAltersArray($pma_table, $pack_keys,
1778 $checksum, $page_checksum, $delay_key_write,
1779 $row_format, $newTblStorageEngine, $transactional, $tbl_collation
1781 global $auto_increment;
1783 $table_alters = array();
1785 if (isset($_POST['comment'])
1786 && urldecode($_POST['prev_comment']) !== $_POST['comment']
1788 $table_alters[] = 'COMMENT = \''
1789 . $GLOBALS['dbi']->escapeString($_POST['comment']) . '\'';
1792 if (! empty($newTblStorageEngine)
1793 && mb_strtolower($newTblStorageEngine) !== mb_strtolower($GLOBALS['tbl_storage_engine'])
1795 $table_alters[] = 'ENGINE = ' . $newTblStorageEngine;
1797 if (! empty($_POST['tbl_collation'])
1798 && $_POST['tbl_collation'] !== $tbl_collation
1800 $table_alters[] = 'DEFAULT '
1801 . Util
::getCharsetQueryPart($_POST['tbl_collation']);
1804 if ($pma_table->isEngine(array('MYISAM', 'ARIA', 'ISAM'))
1805 && isset($_POST['new_pack_keys'])
1806 && $_POST['new_pack_keys'] != (string)$pack_keys
1808 $table_alters[] = 'pack_keys = ' . $_POST['new_pack_keys'];
1811 $_POST['new_checksum'] = empty($_POST['new_checksum']) ?
'0' : '1';
1812 if ($pma_table->isEngine(array('MYISAM', 'ARIA'))
1813 && $_POST['new_checksum'] !== $checksum
1815 $table_alters[] = 'checksum = ' . $_POST['new_checksum'];
1818 $_POST['new_transactional']
1819 = empty($_POST['new_transactional']) ?
'0' : '1';
1820 if ($pma_table->isEngine('ARIA')
1821 && $_POST['new_transactional'] !== $transactional
1823 $table_alters[] = 'TRANSACTIONAL = ' . $_POST['new_transactional'];
1826 $_POST['new_page_checksum']
1827 = empty($_POST['new_page_checksum']) ?
'0' : '1';
1828 if ($pma_table->isEngine('ARIA')
1829 && $_POST['new_page_checksum'] !== $page_checksum
1831 $table_alters[] = 'PAGE_CHECKSUM = ' . $_POST['new_page_checksum'];
1834 $_POST['new_delay_key_write']
1835 = empty($_POST['new_delay_key_write']) ?
'0' : '1';
1836 if ($pma_table->isEngine(array('MYISAM', 'ARIA'))
1837 && $_POST['new_delay_key_write'] !== $delay_key_write
1839 $table_alters[] = 'delay_key_write = ' . $_POST['new_delay_key_write'];
1842 if ($pma_table->isEngine(array('MYISAM', 'ARIA', 'INNODB', 'PBXT', 'ROCKSDB'))
1843 && ! empty($_POST['new_auto_increment'])
1844 && (! isset($auto_increment)
1845 ||
$_POST['new_auto_increment'] !== $auto_increment)
1847 $table_alters[] = 'auto_increment = '
1848 . $GLOBALS['dbi']->escapeString($_POST['new_auto_increment']);
1851 if (! empty($_POST['new_row_format'])) {
1852 $newRowFormat = $_POST['new_row_format'];
1853 $newRowFormatLower = mb_strtolower($newRowFormat);
1854 if ($pma_table->isEngine(array('MYISAM', 'ARIA', 'INNODB', 'PBXT'))
1855 && (strlen($row_format) === 0
1856 ||
$newRowFormatLower !== mb_strtolower($row_format))
1858 $table_alters[] = 'ROW_FORMAT = '
1859 . $GLOBALS['dbi']->escapeString($newRowFormat);
1863 return $table_alters;
1867 * Get warning messages array
1869 * @return array $warning_messages
1871 public function getWarningMessagesArray()
1873 $warning_messages = array();
1874 foreach ($GLOBALS['dbi']->getWarnings() as $warning) {
1875 // In MariaDB 5.1.44, when altering a table from Maria to MyISAM
1876 // and if TRANSACTIONAL was set, the system reports an error;
1877 // I discussed with a Maria developer and he agrees that this
1878 // should not be reported with a Level of Error, so here
1879 // I just ignore it. But there are other 1478 messages
1880 // that it's better to show.
1881 if (! (isset($_POST['new_tbl_storage_engine'])
1882 && $_POST['new_tbl_storage_engine'] == 'MyISAM'
1883 && $warning['Code'] == '1478'
1884 && $warning['Level'] == 'Error')
1886 $warning_messages[] = $warning['Level'] . ': #' . $warning['Code']
1887 . ' ' . $warning['Message'];
1890 return $warning_messages;
1894 * Get SQL query and result after ran this SQL query for a partition operation
1895 * has been requested by the user
1897 * @return array $sql_query, $result
1899 public function getQueryAndResultForPartition()
1901 $sql_query = 'ALTER TABLE '
1902 . Util
::backquote($GLOBALS['table']) . ' '
1903 . $_POST['partition_operation']
1906 if ($_POST['partition_operation'] == 'COALESCE') {
1907 $sql_query .= count($_POST['partition_name']);
1909 $sql_query .= implode(', ', $_POST['partition_name']) . ';';
1912 $result = $GLOBALS['dbi']->query($sql_query);
1914 return array($sql_query, $result);
1918 * Adjust the privileges after renaming/moving a table
1920 * @param string $oldDb Database name before table renaming/moving table
1921 * @param string $oldTable Table name before table renaming/moving table
1922 * @param string $newDb Database name after table renaming/ moving table
1923 * @param string $newTable Table name after table renaming/moving table
1927 public function adjustPrivilegesRenameOrMoveTable($oldDb, $oldTable, $newDb, $newTable)
1929 if ($GLOBALS['table_priv'] && $GLOBALS['col_priv']
1930 && $GLOBALS['is_reload_priv']
1932 $GLOBALS['dbi']->selectDb('mysql');
1934 // For table specific privileges
1935 $query_table_specific = 'UPDATE ' . Util
::backquote('tables_priv')
1936 . 'SET Db = \'' . $GLOBALS['dbi']->escapeString($newDb) . '\', Table_name = \'' . $GLOBALS['dbi']->escapeString($newTable)
1937 . '\' where Db = \'' . $GLOBALS['dbi']->escapeString($oldDb) . '\' AND Table_name = \'' . $GLOBALS['dbi']->escapeString($oldTable)
1939 $GLOBALS['dbi']->query($query_table_specific);
1941 // For column specific privileges
1942 $query_col_specific = 'UPDATE ' . Util
::backquote('columns_priv')
1943 . 'SET Db = \'' . $GLOBALS['dbi']->escapeString($newDb) . '\', Table_name = \'' . $GLOBALS['dbi']->escapeString($newTable)
1944 . '\' where Db = \'' . $GLOBALS['dbi']->escapeString($oldDb) . '\' AND Table_name = \'' . $GLOBALS['dbi']->escapeString($oldTable)
1946 $GLOBALS['dbi']->query($query_col_specific);
1948 // Finally FLUSH the new privileges
1949 $flush_query = "FLUSH PRIVILEGES;";
1950 $GLOBALS['dbi']->query($flush_query);
1955 * Adjust the privileges after copying a table
1957 * @param string $oldDb Database name before table copying
1958 * @param string $oldTable Table name before table copying
1959 * @param string $newDb Database name after table copying
1960 * @param string $newTable Table name after table copying
1964 public function adjustPrivilegesCopyTable($oldDb, $oldTable, $newDb, $newTable)
1966 if ($GLOBALS['table_priv'] && $GLOBALS['col_priv']
1967 && $GLOBALS['is_reload_priv']
1969 $GLOBALS['dbi']->selectDb('mysql');
1971 // For Table Specific privileges
1972 $query_table_specific_old = 'SELECT * FROM '
1973 . Util
::backquote('tables_priv') . ' where '
1974 . 'Db = "' . $oldDb . '" AND Table_name = "' . $oldTable . '";';
1976 $old_privs_table = $GLOBALS['dbi']->fetchResult(
1977 $query_table_specific_old,
1981 foreach ($old_privs_table as $old_priv) {
1982 $newDb_table_privs_query = 'INSERT INTO '
1983 . Util
::backquote('tables_priv') . ' VALUES("'
1984 . $old_priv[0] . '", "' . $newDb . '", "' . $old_priv[2] . '", "'
1985 . $newTable . '", "' . $old_priv[4] . '", "' . $old_priv[5]
1986 . '", "' . $old_priv[6] . '", "' . $old_priv[7] . '");';
1988 $GLOBALS['dbi']->query($newDb_table_privs_query);
1991 // For Column Specific privileges
1992 $query_col_specific_old = 'SELECT * FROM '
1993 . Util
::backquote('columns_priv') . ' WHERE '
1994 . 'Db = "' . $oldDb . '" AND Table_name = "' . $oldTable . '";';
1996 $old_privs_col = $GLOBALS['dbi']->fetchResult(
1997 $query_col_specific_old,
2001 foreach ($old_privs_col as $old_priv) {
2002 $newDb_col_privs_query = 'INSERT INTO '
2003 . Util
::backquote('columns_priv') . ' VALUES("'
2004 . $old_priv[0] . '", "' . $newDb . '", "' . $old_priv[2] . '", "'
2005 . $newTable . '", "' . $old_priv[4] . '", "' . $old_priv[5]
2006 . '", "' . $old_priv[6] . '");';
2008 $GLOBALS['dbi']->query($newDb_col_privs_query);
2011 // Finally FLUSH the new privileges
2012 $flush_query = "FLUSH PRIVILEGES;";
2013 $GLOBALS['dbi']->query($flush_query);
2018 * Change all collations and character sets of all columns in table
2020 * @param string $db Database name
2021 * @param string $table Table name
2022 * @param string $tbl_collation Collation Name
2026 public function changeAllColumnsCollation($db, $table, $tbl_collation)
2028 $GLOBALS['dbi']->selectDb($db);
2030 $change_all_collations_query = 'ALTER TABLE '
2031 . Util
::backquote($table)
2034 list($charset) = explode('_', $tbl_collation);
2036 $change_all_collations_query .= ' CHARACTER SET ' . $charset
2037 . ($charset == $tbl_collation ?
'' : ' COLLATE ' . $tbl_collation);
2039 $GLOBALS['dbi']->query($change_all_collations_query);
2043 * Move or copy a table
2045 * @param string $db current database name
2046 * @param string $table current table name
2050 public function moveOrCopyTable($db, $table)
2053 * Selects the database to work with
2055 $GLOBALS['dbi']->selectDb($db);
2058 * $_POST['target_db'] could be empty in case we came from an input field
2059 * (when there are many databases, no drop-down)
2061 if (empty($_POST['target_db'])) {
2062 $_POST['target_db'] = $db;
2066 * A target table name has been sent to this script -> do the work
2068 if (Core
::isValid($_POST['new_name'])) {
2069 if ($db == $_POST['target_db'] && $table == $_POST['new_name']) {
2070 if (isset($_POST['submit_move'])) {
2071 $message = Message
::error(__('Can\'t move table to same one!'));
2073 $message = Message
::error(__('Can\'t copy table to same one!'));
2077 $db, $table, $_POST['target_db'], $_POST['new_name'],
2078 $_POST['what'], isset($_POST['submit_move']), 'one_table'
2081 if (isset($_POST['adjust_privileges'])
2082 && ! empty($_POST['adjust_privileges'])
2084 if (isset($_POST['submit_move'])) {
2085 $this->adjustPrivilegesRenameOrMoveTable(
2086 $db, $table, $_POST['target_db'], $_POST['new_name']
2089 $this->adjustPrivilegesCopyTable(
2090 $db, $table, $_POST['target_db'], $_POST['new_name']
2094 if (isset($_POST['submit_move'])) {
2095 $message = Message
::success(
2097 'Table %s has been moved to %s. Privileges have been '
2102 $message = Message
::success(
2104 'Table %s has been copied to %s. Privileges have been '
2111 if (isset($_POST['submit_move'])) {
2112 $message = Message
::success(
2113 __('Table %s has been moved to %s.')
2116 $message = Message
::success(
2117 __('Table %s has been copied to %s.')
2122 $old = Util
::backquote($db) . '.'
2123 . Util
::backquote($table);
2124 $message->addParam($old);
2126 $new_name = $_POST['new_name'];
2127 if ($GLOBALS['dbi']->getLowerCaseNames() === '1') {
2128 $new_name = strtolower($new_name);
2131 $GLOBALS['table'] = $new_name;
2133 $new = Util
::backquote($_POST['target_db']) . '.'
2134 . Util
::backquote($new_name);
2135 $message->addParam($new);
2137 /* Check: Work on new table or on old table? */
2138 if (isset($_POST['submit_move'])
2139 || Core
::isValid($_POST['switch_to_new'])
2145 * No new name for the table!
2147 $message = Message
::error(__('The table name is empty!'));
2150 $response = Response
::getInstance();
2151 if ($response->isAjax()) {
2152 $response->addJSON('message', $message);
2153 if ($message->isSuccess()) {
2154 $response->addJSON('db', $GLOBALS['db']);
2156 $response->setRequestStatus(false);