2 /* vim: set expandtab sw=4 ts=4 sts=4: */
4 * Common functions for Designer
6 * @package PhpMyAdmin-Designer
9 * Block attempts to directly run this script
11 if (! defined('PHPMYADMIN')) {
15 $GLOBALS['PMD']['STYLE'] = 'default';
17 $cfgRelation = PMA_getRelationsParam();
20 * Retrieves table info and stores it in $GLOBALS['PMD']
22 * @return array with table info
24 function PMA_getTablesInfo()
28 $GLOBALS['PMD']['TABLE_NAME'] = array();// that foreach no error
29 $GLOBALS['PMD']['OWNER'] = array();
30 $GLOBALS['PMD']['TABLE_NAME_SMALL'] = array();
32 $tables = $GLOBALS['dbi']->getTablesFull($GLOBALS['db']);
33 // seems to be needed later
34 $GLOBALS['dbi']->selectDb($GLOBALS['db']);
36 foreach ($tables as $one_table) {
37 $GLOBALS['PMD']['TABLE_NAME'][$i]
38 = $GLOBALS['db'] . "." . $one_table['TABLE_NAME'];
39 $GLOBALS['PMD']['OWNER'][$i] = $GLOBALS['db'];
40 $GLOBALS['PMD']['TABLE_NAME_SMALL'][$i] = $one_table['TABLE_NAME'];
42 $GLOBALS['PMD_URL']['TABLE_NAME'][$i]
43 = urlencode($GLOBALS['db'] . "." . $one_table['TABLE_NAME']);
44 $GLOBALS['PMD_URL']['OWNER'][$i] = urlencode($GLOBALS['db']);
45 $GLOBALS['PMD_URL']['TABLE_NAME_SMALL'][$i]
46 = urlencode($one_table['TABLE_NAME']);
48 $GLOBALS['PMD_OUT']['TABLE_NAME'][$i] = htmlspecialchars(
49 $GLOBALS['db'] . "." . $one_table['TABLE_NAME'], ENT_QUOTES
51 $GLOBALS['PMD_OUT']['OWNER'][$i] = htmlspecialchars(
52 $GLOBALS['db'], ENT_QUOTES
54 $GLOBALS['PMD_OUT']['TABLE_NAME_SMALL'][$i] = htmlspecialchars(
55 $one_table['TABLE_NAME'], ENT_QUOTES
58 $GLOBALS['PMD']['TABLE_TYPE'][$i] = /*overload*/mb_strtoupper(
62 $DF = PMA_getDisplayField($GLOBALS['db'], $one_table['TABLE_NAME']);
64 $retval[$GLOBALS['PMD_URL']["TABLE_NAME_SMALL"][$i]] = urlencode($DF);
74 * Retrieves table column info
76 * @return array table column nfo
78 function PMA_getColumnsInfo()
80 $GLOBALS['dbi']->selectDb($GLOBALS['db']);
81 $tab_column = array();
82 for ($i = 0, $cnt = count($GLOBALS['PMD']["TABLE_NAME"]); $i < $cnt; $i++
) {
83 $fields_rs = $GLOBALS['dbi']->query(
84 $GLOBALS['dbi']->getColumnsSql(
86 $GLOBALS['PMD']["TABLE_NAME_SMALL"][$i],
91 PMA_DatabaseInterface
::QUERY_STORE
93 $tbl_name_i = $GLOBALS['PMD']['TABLE_NAME'][$i];
95 while ($row = $GLOBALS['dbi']->fetchAssoc($fields_rs)) {
96 $tab_column[$tbl_name_i]['COLUMN_ID'][$j] = $j;
97 $tab_column[$tbl_name_i]['COLUMN_NAME'][$j] = $row['Field'];
98 $tab_column[$tbl_name_i]['TYPE'][$j] = $row['Type'];
99 $tab_column[$tbl_name_i]['NULLABLE'][$j] = $row['Null'];
107 * Returns JavaScript code for initializing vars
109 * @return string JavaScript code
111 function PMA_getScriptContr()
113 $GLOBALS['dbi']->selectDb($GLOBALS['db']);
115 $con["C_NAME"] = array();
117 $alltab_rs = $GLOBALS['dbi']->query(
118 'SHOW TABLES FROM ' . PMA_Util
::backquote($GLOBALS['db']),
120 PMA_DatabaseInterface
::QUERY_STORE
122 while ($val = @$GLOBALS['dbi']->fetchRow($alltab_rs)) {
123 $row = PMA_getForeigners($GLOBALS['db'], $val[0], '', 'internal');
124 //echo "<br> internal ".$GLOBALS['db']." - ".$val[0]." - ";
126 if ($row !== false) {
127 foreach ($row as $field => $value) {
128 $con['C_NAME'][$i] = '';
129 $con['DTN'][$i] = urlencode($GLOBALS['db'] . "." . $val[0]);
130 $con['DCN'][$i] = urlencode($field);
131 $con['STN'][$i] = urlencode(
132 $value['foreign_db'] . "." . $value['foreign_table']
134 $con['SCN'][$i] = urlencode($value['foreign_field']);
138 $row = PMA_getForeigners($GLOBALS['db'], $val[0], '', 'foreign');
141 if ($row !== false) {
142 foreach ($row['foreign_keys_data'] as $one_key) {
143 foreach ($one_key['index_list'] as $index => $one_field) {
144 $con['C_NAME'][$i] = '';
145 $con['DTN'][$i] = urlencode($GLOBALS['db'] . "." . $val[0]);
146 $con['DCN'][$i] = urlencode($one_field);
147 $con['STN'][$i] = urlencode(
148 (isset($one_key['ref_db_name']) ?
149 $one_key['ref_db_name'] : $GLOBALS['db'])
150 . "." . $one_key['ref_table_name']
152 $con['SCN'][$i] = urlencode($one_key['ref_index_list'][$index]);
161 for ($i = 0, $cnt = count($con["C_NAME"]); $i < $cnt; $i++
) {
162 $c_name_i = $con['C_NAME'][$i];
163 $dtn_i = $con['DTN'][$i];
164 $retval[$ti] = array();
165 $retval[$ti][$c_name_i] = array();
166 if (in_array($dtn_i, $GLOBALS['PMD_URL']["TABLE_NAME"])
167 && in_array($con['STN'][$i], $GLOBALS['PMD_URL']["TABLE_NAME"])
169 $retval[$ti][$c_name_i][$dtn_i] = array();
170 $retval[$ti][$c_name_i][$dtn_i][$con['DCN'][$i]] = array(
171 0 => $con['STN'][$i],
181 * Returns UNIQUE and PRIMARY indices
183 * @return array unique or primary indices
185 function PMA_getPKOrUniqueKeys()
187 return PMA_getAllKeys(true);
191 * Returns all indices
193 * @param bool $unique_only whether to include only unique ones
195 * @return array indices
197 function PMA_getAllKeys($unique_only = false)
199 include_once './libraries/Index.class.php';
203 foreach ($GLOBALS['PMD']['TABLE_NAME_SMALL'] as $I => $table) {
204 $schema = $GLOBALS['PMD']['OWNER'][$I];
205 // for now, take into account only the first index segment
206 foreach (PMA_Index
::getFromTable($table, $schema) as $index) {
207 if ($unique_only && ! $index->isUnique()) {
210 $columns = $index->getColumns();
211 foreach ($columns as $column_name => $dummy) {
212 $keys[$schema . '.' . $table . '.' . $column_name] = 1;
220 * Return script to create j_tab and h_tab arrays
224 function PMA_getScriptTabs()
231 for ($i = 0, $cnt = count($GLOBALS['PMD']['TABLE_NAME']); $i < $cnt; $i++
) {
233 if (PMA_Util
::isForeignKeySupported($GLOBALS['PMD']['TABLE_TYPE'][$i])) {
236 $retval['j_tabs'][$GLOBALS['PMD_URL']['TABLE_NAME'][$i]] = $j;
237 $retval['h_tabs'][$GLOBALS['PMD_URL']['TABLE_NAME'][$i]] = 1;
243 * Returns table positions of a given pdf page
245 * @param int $pg pdf page id
247 * @return array of table positions
249 function PMA_getTablePositions($pg)
251 $cfgRelation = PMA_getRelationsParam();
252 if (! $cfgRelation['pdfwork']) {
257 SELECT CONCAT_WS('.', `db_name`, `table_name`) AS `name`,
262 FROM " . PMA_Util
::backquote($cfgRelation['db'])
263 . "." . PMA_Util
::backquote($cfgRelation['table_coords']) . "
264 WHERE pdf_page_number = " . $pg;
266 $tab_pos = $GLOBALS['dbi']->fetchResult(
270 $GLOBALS['controllink'],
271 PMA_DatabaseInterface
::QUERY_STORE
277 * Returns page name of a given pdf page
279 * @param int $pg pdf page id
281 * @return String table name
283 function PMA_getPageName($pg)
285 $cfgRelation = PMA_getRelationsParam();
286 if (! $cfgRelation['pdfwork']) {
290 $query = "SELECT `page_descr`"
291 . " FROM " . PMA_Util
::backquote($cfgRelation['db'])
292 . "." . PMA_Util
::backquote($cfgRelation['pdf_pages'])
293 . " WHERE " . PMA_Util
::backquote('page_nr') . " = " . $pg;
294 $page_name = $GLOBALS['dbi']->fetchResult(
298 $GLOBALS['controllink'],
299 PMA_DatabaseInterface
::QUERY_STORE
301 return count($page_name) ?
$page_name[0] : null;
305 * Deletes a given pdf page and its corresponding coordinates
307 * @param int $pg page id
309 * @return boolean success/failure
311 function PMA_deletePage($pg)
313 $cfgRelation = PMA_getRelationsParam();
314 if (! $cfgRelation['pdfwork']) {
318 $query = "DELETE FROM " . PMA_Util
::backquote($cfgRelation['db'])
319 . "." . PMA_Util
::backquote($cfgRelation['table_coords'])
320 . " WHERE " . PMA_Util
::backquote('pdf_page_number') . " = " . $pg;
321 $success = PMA_queryAsControlUser(
322 $query, true, PMA_DatabaseInterface
::QUERY_STORE
326 $query = "DELETE FROM " . PMA_Util
::backquote($cfgRelation['db'])
327 . "." . PMA_Util
::backquote($cfgRelation['pdf_pages'])
328 . " WHERE " . PMA_Util
::backquote('page_nr') . " = " . $pg;
329 $success = PMA_queryAsControlUser(
330 $query, true, PMA_DatabaseInterface
::QUERY_STORE
334 return (boolean
) $success;
338 * Returns the id of the default pdf page of the database.
339 * Default page is the one which has the same name as the database.
341 * @param string $db database
343 * @return int id of the default pdf page for the database
345 function PMA_getDefaultPage($db)
347 $cfgRelation = PMA_getRelationsParam();
348 if (! $cfgRelation['pdfwork']) {
352 $query = "SELECT `page_nr`"
353 . " FROM " . PMA_Util
::backquote($cfgRelation['db'])
354 . "." . PMA_Util
::backquote($cfgRelation['pdf_pages'])
355 . " WHERE `db_name` = '" . PMA_Util
::sqlAddSlashes($db) . "'"
356 . " AND `page_descr` = '" . PMA_Util
::sqlAddSlashes($db) . "'";
358 $default_page_no = $GLOBALS['dbi']->fetchResult(
362 $GLOBALS['controllink'],
363 PMA_DatabaseInterface
::QUERY_STORE
366 if (count($default_page_no)) {
367 return $default_page_no[0];
373 * Get the id of the page to load. If a default page exists it will be returned.
374 * If no such exists, returns the id of the first page of the database.
376 * @param string $db database
378 * @return int id of the page to load
380 function PMA_getLoadingPage($db)
382 $cfgRelation = PMA_getRelationsParam();
383 if (! $cfgRelation['pdfwork']) {
389 $default_page_no = PMA_getDefaultPage($db);
390 if ($default_page_no != -1) {
391 $page_no = $default_page_no;
393 $query = "SELECT MIN(`page_nr`)"
394 . " FROM " . PMA_Util
::backquote($cfgRelation['db'])
395 . "." . PMA_Util
::backquote($cfgRelation['pdf_pages'])
396 . " WHERE `db_name` = '" . PMA_Util
::sqlAddSlashes($db) . "'";
398 $min_page_no = $GLOBALS['dbi']->fetchResult(
402 $GLOBALS['controllink'],
403 PMA_DatabaseInterface
::QUERY_STORE
405 if (count($min_page_no[0])) {
406 $page_no = $min_page_no[0];
413 * Creates a new page and returns its auto-incrementing id
415 * @param string $pageName name of the page
416 * @param string $db name of the database
420 function PMA_createNewPage($pageName, $db)
422 $cfgRelation = PMA_getRelationsParam();
423 if ($cfgRelation['pdfwork']) {
424 $pageNumber = PMA_REL_createPage(
435 * Saves positions of table(s) of a given pdf page
437 * @param int $pg pdf page id
439 * @return boolean success/failure
441 function PMA_saveTablePositions($pg)
443 $cfgRelation = PMA_getRelationsParam();
444 if (! $cfgRelation['pdfwork']) {
448 $query = "DELETE FROM " . PMA_Util
::backquote($GLOBALS['cfgRelation']['db'])
449 . "." . PMA_Util
::backquote($GLOBALS['cfgRelation']['table_coords'])
450 . " WHERE `db_name` = '" . PMA_Util
::sqlAddSlashes($_REQUEST['db']) . "'"
451 . " AND `pdf_page_number` = '" . PMA_Util
::sqlAddSlashes($pg) . "'";
453 $res = PMA_queryAsControlUser($query, true, PMA_DatabaseInterface
::QUERY_STORE
);
456 foreach ($_REQUEST['t_h'] as $key => $value) {
457 list($DB, $TAB) = explode(".", $key);
459 $query = "INSERT INTO "
460 . PMA_Util
::backquote($GLOBALS['cfgRelation']['db']) . "."
461 . PMA_Util
::backquote($GLOBALS['cfgRelation']['table_coords'])
462 . " (`db_name`, `table_name`, `pdf_page_number`, `x`, `y`)"
464 . "'" . PMA_Util
::sqlAddSlashes($DB) . "', "
465 . "'" . PMA_Util
::sqlAddSlashes($TAB) . "', "
466 . "'" . PMA_Util
::sqlAddSlashes($pg) . "', "
467 . "'" . PMA_Util
::sqlAddSlashes($_REQUEST['t_x'][$key]) . "', "
468 . "'" . PMA_Util
::sqlAddSlashes($_REQUEST['t_y'][$key]) . "')";
470 $res = PMA_queryAsControlUser(
471 $query, true, PMA_DatabaseInterface
::QUERY_STORE
477 return (boolean
) $res;
481 * Saves the display field for a table.
483 * @param string $db database name
484 * @param string $table table name
485 * @param string $field display field name
489 function PMA_saveDisplayField($db, $table, $field)
491 $cfgRelation = PMA_getRelationsParam();
492 if (!$cfgRelation['displaywork']) {
496 $disp = PMA_getDisplayField($db, $table);
497 if ($disp && $disp === $field) {
501 $upd_query = new PMA_Table($table, $db, $GLOBALS['dbi']);
502 $upd_query->updateDisplayField($disp, $field, $cfgRelation);
508 * Adds a new foreign relation
510 * @param string $db database name
511 * @param string $T1 foreign table
512 * @param string $F1 foreign field
513 * @param string $T2 master table
514 * @param string $F2 master field
515 * @param string $on_delete on delete action
516 * @param string $on_update on update action
518 * @return array array of success/failure and message
520 function PMA_addNewRelation($db, $T1, $F1, $T2, $F2, $on_delete, $on_update)
522 $tables = $GLOBALS['dbi']->getTablesFull($db, $T1);
523 $type_T1 = /*overload*/mb_strtoupper($tables[$T1]['ENGINE']);
524 $tables = $GLOBALS['dbi']->getTablesFull($db, $T2);
525 $type_T2 = /*overload*/mb_strtoupper($tables[$T2]['ENGINE']);
527 // native foreign key
528 if (PMA_Util
::isForeignKeySupported($type_T1)
529 && PMA_Util
::isForeignKeySupported($type_T2)
530 && $type_T1 == $type_T2
533 $existrel_foreign = PMA_getForeigners($db, $T2, '', 'foreign');
534 $foreigner = PMA_searchColumnInForeigners($existrel_foreign, $F2);
536 && isset($foreigner['constraint'])
538 return array(false, __('Error: relation already exists.'));
540 // note: in InnoDB, the index does not requires to be on a PRIMARY
542 // improve: check all other requirements for InnoDB relations
543 $result = $GLOBALS['dbi']->query(
544 'SHOW INDEX FROM ' . PMA_Util
::backquote($db)
545 . '.' . PMA_Util
::backquote($T1) . ';'
548 // will be use to emphasis prim. keys in the table view
549 $index_array1 = array();
550 while ($row = $GLOBALS['dbi']->fetchAssoc($result)) {
551 $index_array1[$row['Column_name']] = 1;
553 $GLOBALS['dbi']->freeResult($result);
555 $result = $GLOBALS['dbi']->query(
556 'SHOW INDEX FROM ' . PMA_Util
::backquote($db)
557 . '.' . PMA_Util
::backquote($T2) . ';'
559 // will be used to emphasis prim. keys in the table view
560 $index_array2 = array();
561 while ($row = $GLOBALS['dbi']->fetchAssoc($result)) {
562 $index_array2[$row['Column_name']] = 1;
564 $GLOBALS['dbi']->freeResult($result);
566 if (! empty($index_array1[$F1]) && ! empty($index_array2[$F2])) {
567 $upd_query = 'ALTER TABLE ' . PMA_Util
::backquote($db)
568 . '.' . PMA_Util
::backquote($T2)
569 . ' ADD FOREIGN KEY ('
570 . PMA_Util
::backquote($F2) . ')'
572 . PMA_Util
::backquote($db) . '.'
573 . PMA_Util
::backquote($T1) . '('
574 . PMA_Util
::backquote($F1) . ')';
576 if ($on_delete != 'nix') {
577 $upd_query .= ' ON DELETE ' . $on_delete;
579 if ($on_update != 'nix') {
580 $upd_query .= ' ON UPDATE ' . $on_update;
583 if ($GLOBALS['dbi']->tryQuery($upd_query)) {
584 return array(true, __('FOREIGN KEY relation has been added.'));
586 $error = $GLOBALS['dbi']->getError();
589 __('Error: FOREIGN KEY relation could not be added!')
594 return array(false, __('Error: Missing index on column(s).'));
596 } else { // internal (pmadb) relation
597 if ($GLOBALS['cfgRelation']['relwork'] == false) {
598 return array(false, __('Error: Relational features are disabled!'));
600 // no need to recheck if the keys are primary or unique at this point,
601 // this was checked on the interface part
604 . PMA_Util
::backquote($GLOBALS['cfgRelation']['db'])
605 . "." . PMA_Util
::backquote($GLOBALS['cfgRelation']['relation'])
606 . "(master_db, master_table, master_field, "
607 . "foreign_db, foreign_table, foreign_field)"
609 . "'" . PMA_Util
::sqlAddSlashes($db) . "', "
610 . "'" . PMA_Util
::sqlAddSlashes($T2) . "', "
611 . "'" . PMA_Util
::sqlAddSlashes($F2) . "', "
612 . "'" . PMA_Util
::sqlAddSlashes($db) . "', "
613 . "'" . PMA_Util
::sqlAddSlashes($T1) . "', "
614 . "'" . PMA_Util
::sqlAddSlashes($F1) . "')";
616 if (PMA_queryAsControlUser($q, false, PMA_DatabaseInterface
::QUERY_STORE
)
618 return array(true, __('Internal relation has been added.'));
620 $error = $GLOBALS['dbi']->getError($GLOBALS['controllink']);
623 __('Error: Internal relation could not be added!')
632 * Removes a foreign relation
634 * @param string $T1 foreign db.table
635 * @param string $F1 foreign field
636 * @param string $T2 master db.table
637 * @param string $F2 master field
639 * @return array array of success/failure and message
641 function PMA_removeRelation($T1, $F1, $T2, $F2)
643 list($DB1, $T1) = explode(".", $T1);
644 list($DB2, $T2) = explode(".", $T2);
646 $tables = $GLOBALS['dbi']->getTablesFull($DB1, $T1);
647 $type_T1 = /*overload*/mb_strtoupper($tables[$T1]['ENGINE']);
648 $tables = $GLOBALS['dbi']->getTablesFull($DB2, $T2);
649 $type_T2 = /*overload*/mb_strtoupper($tables[$T2]['ENGINE']);
651 if (PMA_Util
::isForeignKeySupported($type_T1)
652 && PMA_Util
::isForeignKeySupported($type_T2)
653 && $type_T1 == $type_T2
656 $existrel_foreign = PMA_getForeigners($DB2, $T2, '', 'foreign');
657 $foreigner = PMA_searchColumnInForeigners($existrel_foreign, $F2);
659 if (isset($foreigner['constraint'])) {
660 $upd_query = 'ALTER TABLE ' . PMA_Util
::backquote($DB2)
661 . '.' . PMA_Util
::backquote($T2) . ' DROP FOREIGN KEY '
662 . PMA_Util
::backquote($foreigner['constraint']) . ';';
663 if ($GLOBALS['dbi']->query($upd_query)) {
664 return array(true, __('FOREIGN KEY relation has been removed.'));
667 $error = $GLOBALS['dbi']->getError();
670 __('Error: FOREIGN KEY relation could not be removed!')
676 // internal relations
677 $delete_query = "DELETE FROM "
678 . PMA_Util
::backquote($GLOBALS['cfgRelation']['db']) . "."
679 . $GLOBALS['cfgRelation']['relation'] . " WHERE "
680 . "master_db = '" . PMA_Util
::sqlAddSlashes($DB2) . "'"
681 . " AND master_table = '" . PMA_Util
::sqlAddSlashes($T2) . "'"
682 . " AND master_field = '" . PMA_Util
::sqlAddSlashes($F2) . "'"
683 . " AND foreign_db = '" . PMA_Util
::sqlAddSlashes($DB1) . "'"
684 . " AND foreign_table = '" . PMA_Util
::sqlAddSlashes($T1) . "'"
685 . " AND foreign_field = '" . PMA_Util
::sqlAddSlashes($F1) . "'";
687 $result = PMA_queryAsControlUser(
690 PMA_DatabaseInterface
::QUERY_STORE
694 $error = $GLOBALS['dbi']->getError($GLOBALS['controllink']);
697 __('Error: Internal relation could not be removed!') . "<br/>" . $error
701 return array(true, __('Internal relation has been removed.'));
705 * Save value for a designer setting
707 * @param string $index setting
708 * @param string $value value
710 * @return bool whether the operation succeeded
712 function PMA_saveDesignerSetting($index, $value)
714 $cfgRelation = PMA_getRelationsParam();
715 $cfgDesigner = array(
716 'user' => $GLOBALS['cfg']['Server']['user'],
717 'db' => $cfgRelation['db'],
718 'table' => $cfgRelation['designer_settings']
722 if ($GLOBALS['cfgRelation']['designersettingswork']) {
724 $orig_data_query = "SELECT settings_data"
725 . " FROM " . PMA_Util
::backquote($cfgDesigner['db'])
726 . "." . PMA_Util
::backquote($cfgDesigner['table'])
727 . " WHERE username = '"
728 . PMA_Util
::sqlAddSlashes($cfgDesigner['user']) . "';";
730 $orig_data = $GLOBALS['dbi']->fetchSingleRow(
731 $orig_data_query, 'ASSOC', $GLOBALS['controllink']
734 if (! empty($orig_data)) {
735 $orig_data = json_decode($orig_data['settings_data'], true);
736 $orig_data[$index] = $value;
737 $orig_data = json_encode($orig_data);
739 $save_query = "UPDATE " . PMA_Util
::backquote($cfgDesigner['db'])
740 . "." . PMA_Util
::backquote($cfgDesigner['table'])
741 . " SET settings_data = '" . $orig_data . "'"
742 . " WHERE username = '"
743 . PMA_Util
::sqlAddSlashes($cfgDesigner['user']) . "';";
745 $success = PMA_queryAsControlUser($save_query);
747 $save_data = array($index => $value);
749 $query = "INSERT INTO " . PMA_Util
::backquote($cfgDesigner['db'])
750 . "." . PMA_Util
::backquote($cfgDesigner['table'])
751 . " (username, settings_data)"
752 . " VALUES('" . $cfgDesigner['user'] . "',"
753 . " '" . json_encode($save_data) . "');";
755 $success = PMA_queryAsControlUser($query);