tbl_relation.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Display table relations for viewing and editing
  5. *
  6. * includes phpMyAdmin relations and InnoDB relations
  7. *
  8. * @todo fix name handling: currently names with dots (.) are not properly handled
  9. * for internal relations (but foreign keys relations are correct)
  10. * @todo foreign key constraints require both fields being of equal type and size
  11. * @todo check foreign fields to be from same type and size, all other makes no sense
  12. * @todo add an link to create an index required for constraints,
  13. * or an option to do automatically
  14. * @todo if above todos are fullfilled we can add all fields meet requirements
  15. * in the select dropdown
  16. * @package PhpMyAdmin
  17. */
  18. /**
  19. * Gets some core libraries
  20. */
  21. require_once 'libraries/common.inc.php';
  22. require_once 'libraries/index.lib.php';
  23. $response = PMA_Response::getInstance();
  24. $header = $response->getHeader();
  25. $scripts = $header->getScripts();
  26. $scripts->addFile('tbl_relation.js');
  27. $scripts->addFile('indexes.js');
  28. /**
  29. * Sets globals from $_POST
  30. */
  31. $post_params = array(
  32. 'destination',
  33. 'destination_foreign',
  34. 'display_field',
  35. 'fields_name',
  36. 'on_delete',
  37. 'on_update'
  38. );
  39. foreach ($post_params as $one_post_param) {
  40. if (isset($_POST[$one_post_param])) {
  41. $GLOBALS[$one_post_param] = $_POST[$one_post_param];
  42. }
  43. }
  44. /**
  45. * Gets tables informations
  46. */
  47. require_once 'libraries/tbl_info.inc.php';
  48. $options_array = array(
  49. 'CASCADE' => 'CASCADE',
  50. 'SET_NULL' => 'SET NULL',
  51. 'NO_ACTION' => 'NO ACTION',
  52. 'RESTRICT' => 'RESTRICT',
  53. );
  54. /**
  55. * Gets the relation settings
  56. */
  57. $cfgRelation = PMA_getRelationsParam();
  58. /**
  59. * Updates
  60. */
  61. if ($cfgRelation['relwork']) {
  62. $existrel = PMA_getForeigners($db, $table, '', 'internal');
  63. }
  64. if (PMA_Util::isForeignKeySupported($tbl_storage_engine)) {
  65. $existrel_foreign = PMA_getForeigners($db, $table, '', 'foreign');
  66. }
  67. if ($cfgRelation['displaywork']) {
  68. $disp = PMA_getDisplayField($db, $table);
  69. }
  70. // will be used in the logic for internal relations and foreign keys:
  71. $multi_edit_columns_name = isset($_REQUEST['fields_name'])
  72. ? $_REQUEST['fields_name']
  73. : null;
  74. $html_output = '';
  75. // u p d a t e s f o r I n t e r n a l r e l a t i o n s
  76. if (isset($destination) && $cfgRelation['relwork']) {
  77. foreach ($destination as $master_field_md5 => $foreign_string) {
  78. $upd_query = false;
  79. // Map the fieldname's md5 back to its real name
  80. $master_field = $multi_edit_columns_name[$master_field_md5];
  81. if (! empty($foreign_string)) {
  82. $foreign_string = trim($foreign_string, '`');
  83. list($foreign_db, $foreign_table, $foreign_field)
  84. = explode('.', $foreign_string);
  85. if (! isset($existrel[$master_field])) {
  86. $upd_query = 'INSERT INTO '
  87. . PMA_Util::backquote($GLOBALS['cfgRelation']['db'])
  88. . '.' . PMA_Util::backquote($cfgRelation['relation'])
  89. . '(master_db, master_table, master_field, foreign_db,'
  90. . ' foreign_table, foreign_field)'
  91. . ' values('
  92. . '\'' . PMA_Util::sqlAddSlashes($db) . '\', '
  93. . '\'' . PMA_Util::sqlAddSlashes($table) . '\', '
  94. . '\'' . PMA_Util::sqlAddSlashes($master_field) . '\', '
  95. . '\'' . PMA_Util::sqlAddSlashes($foreign_db) . '\', '
  96. . '\'' . PMA_Util::sqlAddSlashes($foreign_table) . '\','
  97. . '\'' . PMA_Util::sqlAddSlashes($foreign_field) . '\')';
  98. } elseif ($existrel[$master_field]['foreign_db'] . '.' .$existrel[$master_field]['foreign_table'] . '.' . $existrel[$master_field]['foreign_field'] != $foreign_string) {
  99. $upd_query = 'UPDATE '
  100. . PMA_Util::backquote($GLOBALS['cfgRelation']['db'])
  101. . '.' . PMA_Util::backquote($cfgRelation['relation']) . ' SET'
  102. . ' foreign_db = \''
  103. . PMA_Util::sqlAddSlashes($foreign_db) . '\', '
  104. . ' foreign_table = \''
  105. . PMA_Util::sqlAddSlashes($foreign_table) . '\', '
  106. . ' foreign_field = \''
  107. . PMA_Util::sqlAddSlashes($foreign_field) . '\' '
  108. . ' WHERE master_db = \'' . PMA_Util::sqlAddSlashes($db) . '\''
  109. . ' AND master_table = \''
  110. . PMA_Util::sqlAddSlashes($table) . '\''
  111. . ' AND master_field = \''
  112. . PMA_Util::sqlAddSlashes($master_field) . '\'';
  113. } // end if... else....
  114. } elseif (isset($existrel[$master_field])) {
  115. $upd_query = 'DELETE FROM '
  116. . PMA_Util::backquote($GLOBALS['cfgRelation']['db'])
  117. . '.' . PMA_Util::backquote($cfgRelation['relation'])
  118. . ' WHERE master_db = \'' . PMA_Util::sqlAddSlashes($db) . '\''
  119. . ' AND master_table = \'' . PMA_Util::sqlAddSlashes($table) . '\''
  120. . ' AND master_field = \'' . PMA_Util::sqlAddSlashes($master_field)
  121. . '\'';
  122. } // end if... else....
  123. if ($upd_query) {
  124. PMA_queryAsControlUser($upd_query);
  125. }
  126. } // end while
  127. } // end if (updates for internal relations)
  128. // u p d a t e s f o r f o r e i g n k e y s
  129. // (for now, one index name only; we keep the definitions if the
  130. // foreign db is not the same)
  131. if (isset($_REQUEST['destination_foreign'])) {
  132. $display_query = '';
  133. $seen_error = false;
  134. foreach ($_REQUEST['destination_foreign'] as $master_field_md5 => $foreign_string) {
  135. $create = false;
  136. $drop = false;
  137. // Map the fieldname's md5 back to it's real name
  138. $master_field = $multi_edit_columns_name[$master_field_md5];
  139. if (! empty($foreign_string)) {
  140. list($foreign_db, $foreign_table, $foreign_field)
  141. = PMA_backquoteSplit($foreign_string);
  142. if (! isset($existrel_foreign[$master_field])) {
  143. // no key defined for this field
  144. $create = true;
  145. } elseif (PMA_Util::backquote($existrel_foreign[$master_field]['foreign_db']) != $foreign_db
  146. || PMA_Util::backquote($existrel_foreign[$master_field]['foreign_table']) != $foreign_table
  147. || PMA_Util::backquote($existrel_foreign[$master_field]['foreign_field']) != $foreign_field
  148. || $_REQUEST['constraint_name'][$master_field_md5] != $existrel_foreign[$master_field]['constraint']
  149. || ($_REQUEST['on_delete'][$master_field_md5] != (! empty($existrel_foreign[$master_field]['on_delete']) ? $existrel_foreign[$master_field]['on_delete'] : 'RESTRICT'))
  150. || ($_REQUEST['on_update'][$master_field_md5] != (! empty($existrel_foreign[$master_field]['on_update']) ? $existrel_foreign[$master_field]['on_update'] : 'RESTRICT'))
  151. ) {
  152. // another foreign key is already defined for this field
  153. // or an option has been changed for ON DELETE or ON UPDATE
  154. $drop = true;
  155. $create = true;
  156. } // end if... else....
  157. } elseif (isset($existrel_foreign[$master_field])) {
  158. $drop = true;
  159. } // end if... else....
  160. $tmp_error_drop = false;
  161. if ($drop) {
  162. $drop_query = PMA_getSQLToDropForeignKey(
  163. $table, $existrel_foreign[$master_field]['constraint']
  164. );
  165. $display_query .= $drop_query . "\n";
  166. PMA_DBI_try_query($drop_query);
  167. $tmp_error_drop = PMA_DBI_getError();
  168. if (! empty($tmp_error_drop)) {
  169. $seen_error = true;
  170. $html_output .= PMA_Util::mysqlDie(
  171. $tmp_error_drop, $drop_query, false, '', false
  172. );
  173. continue;
  174. }
  175. }
  176. $tmp_error_create = false;
  177. if ($create) {
  178. $create_query = PMA_getSQLToCreateForeignKey(
  179. $table, $master_field, $foreign_db, $foreign_table, $foreign_field,
  180. $_REQUEST['constraint_name'][$master_field_md5],
  181. $options_array[$_REQUEST['on_delete'][$master_field_md5]],
  182. $options_array[$_REQUEST['on_update'][$master_field_md5]]
  183. );
  184. $display_query .= $create_query . "\n";
  185. PMA_DBI_try_query($create_query);
  186. $tmp_error_create = PMA_DBI_getError();
  187. if (! empty($tmp_error_create)) {
  188. $seen_error = true;
  189. if (substr($tmp_error_create, 1, 4) == '1005') {
  190. $message = PMA_Message::error(
  191. __('Error creating foreign key on %1$s (check data types)')
  192. );
  193. $message->addParam($master_field);
  194. $message->display();
  195. } else {
  196. $html_output .= PMA_Util::mysqlDie(
  197. $tmp_error_create, $create_query, false, '', false
  198. );
  199. }
  200. $html_output .= PMA_Util::showMySQLDocu(
  201. 'manual_Table_types', 'InnoDB_foreign_key_constraints'
  202. ) . "\n";
  203. }
  204. // this is an alteration and the old constraint has been dropped
  205. // without creation of a new one
  206. if ($drop && $create && empty($tmp_error_drop)
  207. && ! empty($tmp_error_create)
  208. ) {
  209. // a rollback may be better here
  210. $sql_query_recreate = '# Restoring the dropped constraint...' . "\n";
  211. $sql_query_recreate .= PMA_getSQLToCreateForeignKey(
  212. $table, $master_field,
  213. PMA_Util::backquote($existrel_foreign[$master_field]['foreign_db']),
  214. PMA_Util::backquote($existrel_foreign[$master_field]['foreign_table']),
  215. PMA_Util::backquote($existrel_foreign[$master_field]['foreign_field']),
  216. $existrel_foreign[$master_field]['constraint'],
  217. $options_array[$existrel_foreign[$master_field]['on_delete']],
  218. $options_array[$existrel_foreign[$master_field]['on_update']]
  219. );
  220. $display_query .= $sql_query_recreate . "\n";
  221. PMA_DBI_try_query($sql_query_recreate);
  222. }
  223. }
  224. } // end foreach
  225. if (! empty($display_query) && ! $seen_error) {
  226. $html_output .= PMA_Util::getMessage(
  227. __('Your SQL query has been executed successfully'),
  228. null, 'success'
  229. );
  230. }
  231. } // end if isset($destination_foreign)
  232. // U p d a t e s f o r d i s p l a y f i e l d
  233. if ($cfgRelation['displaywork'] && isset($display_field)) {
  234. $upd_query = false;
  235. if ($disp) {
  236. if ($display_field != '') {
  237. $upd_query = 'UPDATE '
  238. . PMA_Util::backquote($GLOBALS['cfgRelation']['db'])
  239. . '.' . PMA_Util::backquote($cfgRelation['table_info'])
  240. . ' SET display_field = \''
  241. . PMA_Util::sqlAddSlashes($display_field) . '\''
  242. . ' WHERE db_name = \'' . PMA_Util::sqlAddSlashes($db) . '\''
  243. . ' AND table_name = \'' . PMA_Util::sqlAddSlashes($table) . '\'';
  244. } else {
  245. $upd_query = 'DELETE FROM '
  246. . PMA_Util::backquote($GLOBALS['cfgRelation']['db'])
  247. . '.' . PMA_Util::backquote($cfgRelation['table_info'])
  248. . ' WHERE db_name = \'' . PMA_Util::sqlAddSlashes($db) . '\''
  249. . ' AND table_name = \'' . PMA_Util::sqlAddSlashes($table) . '\'';
  250. }
  251. } elseif ($display_field != '') {
  252. $upd_query = 'INSERT INTO '
  253. . PMA_Util::backquote($GLOBALS['cfgRelation']['db'])
  254. . '.' . PMA_Util::backquote($cfgRelation['table_info'])
  255. . '(db_name, table_name, display_field) VALUES('
  256. . '\'' . PMA_Util::sqlAddSlashes($db) . '\','
  257. . '\'' . PMA_Util::sqlAddSlashes($table) . '\','
  258. . '\'' . PMA_Util::sqlAddSlashes($display_field) . '\')';
  259. }
  260. if ($upd_query) {
  261. PMA_queryAsControlUser($upd_query);
  262. }
  263. } // end if
  264. // If we did an update, refresh our data
  265. if (isset($destination) && $cfgRelation['relwork']) {
  266. $existrel = PMA_getForeigners($db, $table, '', 'internal');
  267. }
  268. if (isset($destination_foreign)
  269. && PMA_Util::isForeignKeySupported($tbl_storage_engine)
  270. ) {
  271. $existrel_foreign = PMA_getForeigners($db, $table, '', 'foreign');
  272. }
  273. if ($cfgRelation['displaywork']) {
  274. $disp = PMA_getDisplayField($db, $table);
  275. }
  276. /**
  277. * Dialog
  278. */
  279. // common form
  280. $html_output .= '<form method="post" action="tbl_relation.php">' . "\n"
  281. . PMA_generate_common_hidden_inputs($db, $table);
  282. // relations
  283. if ($cfgRelation['relwork']
  284. || PMA_Util::isForeignKeySupported($tbl_storage_engine)
  285. ) {
  286. // To choose relations we first need all tables names in current db
  287. // and if the main table supports foreign keys
  288. // we use SHOW TABLE STATUS because we need to find other tables of the
  289. // same engine.
  290. if (PMA_Util::isForeignKeySupported($tbl_storage_engine)) {
  291. $tab_query = 'SHOW TABLE STATUS FROM ' . PMA_Util::backquote($db);
  292. // [0] of the row is the name
  293. // [1] is the type
  294. } else {
  295. $tab_query = 'SHOW TABLES FROM ' . PMA_Util::backquote($db);
  296. // [0] of the row is the name
  297. }
  298. $tab_rs = PMA_DBI_query($tab_query, null, PMA_DBI_QUERY_STORE);
  299. $selectboxall[] = '';
  300. $selectboxall_foreign[] = '';
  301. while ($curr_table = PMA_DBI_fetch_row($tab_rs)) {
  302. $current_table = new PMA_Table($curr_table[0], $db);
  303. // explicitely ask for non-quoted list of indexed columns
  304. $selectboxall = array_merge(
  305. $selectboxall,
  306. $current_table->getUniqueColumns($backquoted = false)
  307. );
  308. // if foreign keys are supported, collect all keys from other
  309. // tables of the same engine
  310. if (PMA_Util::isForeignKeySupported($tbl_storage_engine)
  311. && isset($curr_table[1])
  312. && strtoupper($curr_table[1]) == $tbl_storage_engine
  313. ) {
  314. // explicitely ask for non-quoted list of indexed columns
  315. // need to obtain backquoted values to support dots inside values
  316. $selectboxall_foreign = array_merge(
  317. $selectboxall_foreign,
  318. $current_table->getIndexedColumns($backquoted = true)
  319. );
  320. }
  321. } // end while over tables
  322. } // end if
  323. // Now find out the columns of our $table
  324. // need to use PMA_DBI_QUERY_STORE with PMA_DBI_num_rows() in mysqli
  325. $columns = PMA_DBI_get_columns($db, $table);
  326. if (count($columns) > 0) {
  327. foreach ($columns as $row) {
  328. $save_row[] = $row;
  329. }
  330. $saved_row_cnt = count($save_row);
  331. $html_output .= '<fieldset>'
  332. . '<legend>' . __('Relations'). '</legend>'
  333. . '<table>'
  334. . '<tr><th>' . __('Column') . '</th>';
  335. if ($cfgRelation['relwork']) {
  336. $html_output .= '<th>' . __('Internal relation');
  337. if (PMA_Util::isForeignKeySupported($tbl_storage_engine)) {
  338. $html_output .= PMA_Util::showHint(
  339. __(
  340. 'An internal relation is not necessary when a corresponding'
  341. . ' FOREIGN KEY relation exists.'
  342. )
  343. );
  344. }
  345. $html_output .= '</th>';
  346. }
  347. if (PMA_Util::isForeignKeySupported($tbl_storage_engine)) {
  348. // this does not have to be translated, it's part of the MySQL syntax
  349. $html_output .= '<th colspan="2">' . __('Foreign key constraint')
  350. . ' (' . $tbl_storage_engine . ')';
  351. $html_output .= '</th>';
  352. }
  353. $html_output .= '</tr>';
  354. $odd_row = true;
  355. for ($i = 0; $i < $saved_row_cnt; $i++) {
  356. $myfield = $save_row[$i]['Field'];
  357. // Use an md5 as array index to avoid having special characters
  358. // in the name atttibure (see bug #1746964 )
  359. $myfield_md5 = md5($myfield);
  360. $myfield_html = htmlspecialchars($myfield);
  361. $html_output .= '<tr class="' . ($odd_row ? 'odd' : 'even') . '">'
  362. . '<td class="center">'
  363. . '<strong>' . $myfield_html . '</strong>'
  364. . '<input type="hidden" name="fields_name[' . $myfield_md5 . ']"'
  365. . ' value="' . $myfield_html . '"/>'
  366. . '</td>';
  367. $odd_row = ! $odd_row;
  368. if ($cfgRelation['relwork']) {
  369. $html_output .= '<td><select name="destination[' . $myfield_md5 . ']">';
  370. // PMA internal relations
  371. if (isset($existrel[$myfield])) {
  372. $foreign_field = $existrel[$myfield]['foreign_db'] . '.'
  373. . $existrel[$myfield]['foreign_table'] . '.'
  374. . $existrel[$myfield]['foreign_field'];
  375. } else {
  376. $foreign_field = false;
  377. }
  378. $seen_key = false;
  379. foreach ($selectboxall as $value) {
  380. $html_output .= '<option value="' . htmlspecialchars($value) . '"';
  381. if ($foreign_field && $value == $foreign_field) {
  382. $html_output .= ' selected="selected"';
  383. $seen_key = true;
  384. }
  385. $html_output .= '>' . htmlspecialchars($value) . '</option>'. "\n";
  386. } // end while
  387. // if the link defined in relationtable points to a foreign field
  388. // that is not a key in the foreign table, we show the link
  389. // (will not be shown with an arrow)
  390. if ($foreign_field && !$seen_key) {
  391. $html_output .= '<option value="' . htmlspecialchars($foreign_field)
  392. . '"'
  393. . ' selected="selected">' . $foreign_field . '</option>'. "\n";
  394. }
  395. $html_output .= '</select>'
  396. . '</td>';
  397. } // end if (internal relations)
  398. if (PMA_Util::isForeignKeySupported($tbl_storage_engine)) {
  399. $html_output .= '<td>';
  400. if (!empty($save_row[$i]['Key'])) {
  401. $html_output .= '<span class="formelement">'
  402. . '<select name="destination_foreign[' . $myfield_md5 . ']"'
  403. . ' class="referenced_column_dropdown">';
  404. if (isset($existrel_foreign[$myfield])) {
  405. // need to PMA_Util::backquote to support a dot character inside
  406. // an element
  407. $foreign_field = PMA_Util::backquote(
  408. $existrel_foreign[$myfield]['foreign_db']
  409. )
  410. . '.' . PMA_Util::backquote(
  411. $existrel_foreign[$myfield]['foreign_table']
  412. )
  413. . '.' . PMA_Util::backquote(
  414. $existrel_foreign[$myfield]['foreign_field']
  415. );
  416. } else {
  417. $foreign_field = false;
  418. }
  419. $found_foreign_field = false;
  420. foreach ($selectboxall_foreign as $value) {
  421. $html_output .= '<option value="'
  422. . htmlspecialchars($value) . '"';
  423. if ($foreign_field && $value == $foreign_field) {
  424. $html_output .= ' selected="selected"';
  425. $found_foreign_field = true;
  426. }
  427. $html_output .= '>' . htmlspecialchars($value)
  428. . '</option>'. "\n";
  429. } // end while
  430. // we did not find the foreign field in the tables of current db,
  431. // must be defined in another db so show it to avoid erasing it
  432. if (!$found_foreign_field && $foreign_field) {
  433. $html_output .= '<option value="'
  434. . htmlspecialchars($foreign_field) . '"'
  435. . ' selected="selected"'
  436. . '>' . $foreign_field . '</option>' . "\n";
  437. }
  438. $html_output .= '</select>'
  439. . '</span>';
  440. // For constraint name
  441. $html_output .= '<span class="formelement">';
  442. $constraint_name = isset($existrel_foreign[$myfield]['constraint'])
  443. ? $existrel_foreign[$myfield]['constraint'] : '';
  444. $html_output .= __('Constraint name');
  445. $html_output .= '<input type="text" name="constraint_name['
  446. . $myfield_md5 . ']"'
  447. . ' value="' . htmlspecialchars($constraint_name) . '"/>';
  448. $html_output .= '</span>' . "\n";
  449. $html_output .= '<span class="formelement">';
  450. // For ON DELETE and ON UPDATE, the default action
  451. // is RESTRICT as per MySQL doc; however, a SHOW CREATE TABLE
  452. // won't display the clause if it's set as RESTRICT.
  453. $on_delete = isset($existrel_foreign[$myfield]['on_delete'])
  454. ? $existrel_foreign[$myfield]['on_delete'] : 'RESTRICT';
  455. $html_output .= PMA_generateDropdown(
  456. 'ON DELETE',
  457. 'on_delete[' . $myfield_md5 . ']',
  458. $options_array,
  459. $on_delete
  460. );
  461. $html_output .= '</span>' . "\n";
  462. $html_output .= '<span class="formelement">' . "\n";
  463. $on_update = isset($existrel_foreign[$myfield]['on_update'])
  464. ? $existrel_foreign[$myfield]['on_update'] : 'RESTRICT';
  465. $html_output .= PMA_generateDropdown(
  466. 'ON UPDATE',
  467. 'on_update[' . $myfield_md5 . ']',
  468. $options_array,
  469. $on_update
  470. );
  471. $html_output .= '</span>' . "\n";
  472. } else {
  473. $html_output .= __('No index defined! Create one below');
  474. } // end if (a key exists)
  475. $html_output .= '</td>';
  476. } // end if (InnoDB)
  477. $html_output .= '</tr>';
  478. } // end for
  479. unset( $myfield, $myfield_md5, $myfield_html);
  480. $html_output .= '</table>' . "\n"
  481. . '</fieldset>' . "\n";
  482. if ($cfgRelation['displaywork']) {
  483. // Get "display_field" infos
  484. $disp = PMA_getDisplayField($db, $table);
  485. $html_output .= '<fieldset>'
  486. . '<label>' . __('Choose column to display') . ': </label>'
  487. . '<select name="display_field">'
  488. . '<option value="">---</option>';
  489. foreach ($save_row AS $row) {
  490. $html_output .= '<option value="'
  491. . htmlspecialchars($row['Field']) . '"';
  492. if (isset($disp) && $row['Field'] == $disp) {
  493. $html_output .= ' selected="selected"';
  494. }
  495. $html_output .= '>' . htmlspecialchars($row['Field'])
  496. . '</option>'. "\n";
  497. } // end while
  498. $html_output .= '</select>'
  499. . '</fieldset>';
  500. } // end if (displayworks)
  501. $html_output .= '<fieldset class="tblFooters">'
  502. . '<input type="submit" value="' . __('Save') . '" />'
  503. . '</fieldset>'
  504. . '</form>';
  505. } // end if (we have columns in this table)
  506. if (PMA_Util::isForeignKeySupported($tbl_storage_engine)) {
  507. $html_output .= '<div id="index_div" class="ajax" >'
  508. . PMA_getHtmlForDisplayIndexes();
  509. }
  510. // Render HTML output
  511. PMA_Response::getInstance()->addHTML($html_output);
  512. /**
  513. * Generate dropdown choices
  514. *
  515. * @param string $dropdown_question Message to display
  516. * @param string $select_name Name of the <select> field
  517. * @param array $choices Choices for dropdown
  518. * @param string $selected_value Selected value
  519. *
  520. * @return string The html code for existing value (for selected)
  521. *
  522. * @access public
  523. */
  524. function PMA_generateDropdown(
  525. $dropdown_question, $select_name, $choices, $selected_value
  526. ) {
  527. $html_output = htmlspecialchars($dropdown_question) . '&nbsp;&nbsp;'
  528. . '<select name="' . htmlspecialchars($select_name) . '">' . "\n";
  529. foreach ($choices as $one_value => $one_label) {
  530. $html_output .= '<option value="' . htmlspecialchars($one_value) . '"';
  531. if ($selected_value == $one_value) {
  532. $html_output .= ' selected="selected" ';
  533. }
  534. $html_output .= '>' . htmlspecialchars($one_label) . '</option>' . "\n";
  535. }
  536. $html_output .= '</select>' . "\n";
  537. return $html_output;
  538. }
  539. /**
  540. * Split a string on backquote pairs
  541. *
  542. * @param string $text original string
  543. *
  544. * @return array containing the elements (and their surrounding backquotes)
  545. *
  546. * @access public
  547. */
  548. function PMA_backquoteSplit($text)
  549. {
  550. $elements = array();
  551. $final_pos = strlen($text) - 1;
  552. $pos = 0;
  553. while ($pos <= $final_pos) {
  554. $first_backquote = strpos($text, '`', $pos);
  555. $second_backquote = strpos($text, '`', $first_backquote + 1);
  556. // after the second one, there might be another one which means
  557. // this is an escaped backquote
  558. if ($second_backquote < $final_pos && '`' == $text[$second_backquote + 1]) {
  559. $second_backquote = strpos($text, '`', $second_backquote + 2);
  560. }
  561. if (false === $first_backquote || false === $second_backquote) {
  562. break;
  563. }
  564. $elements[] = substr(
  565. $text, $first_backquote, $second_backquote - $first_backquote + 1
  566. );
  567. $pos = $second_backquote + 1;
  568. }
  569. return($elements);
  570. }
  571. /**
  572. * Returns the DROP query for a foreign key constraint
  573. *
  574. * @param string $table table of the foreign key
  575. * @param string $fk foreign key name
  576. *
  577. * @return string DROP query for the foreign key constraint
  578. */
  579. function PMA_getSQLToDropForeignKey($table, $fk)
  580. {
  581. return 'ALTER TABLE ' . PMA_Util::backquote($table)
  582. . ' DROP FOREIGN KEY ' . PMA_Util::backquote($fk) . ';';
  583. }
  584. /**
  585. * Returns the SQL query for foreign key constraint creation
  586. *
  587. * @param string $table table name
  588. * @param string $field field name
  589. * @param string $foreignDb back-quoted foreign database name
  590. * @param string $foreignTable back-quoted foreign table name
  591. * @param string $foreignField back-quoted foreign field name
  592. * @param string $name name of the constraint
  593. * @param string $onDelete on delete action
  594. * @param string $onUpdate on update action
  595. *
  596. * @return string SQL query for foreign key constraint creation
  597. */
  598. function PMA_getSQLToCreateForeignKey($table, $field, $foreignDb, $foreignTable,
  599. $foreignField, $name = null, $onDelete = null, $onUpdate = null
  600. ) {
  601. $sql_query = 'ALTER TABLE ' . PMA_Util::backquote($table) . ' ADD ';
  602. // if user entered a constraint name
  603. if (! empty($name)) {
  604. $sql_query .= ' CONSTRAINT ' . PMA_Util::backquote($name);
  605. }
  606. $sql_query .= ' FOREIGN KEY (' . PMA_Util::backquote($field) . ')'
  607. . ' REFERENCES ' . $foreignDb . '.' . $foreignTable
  608. . '(' . $foreignField . ')';
  609. if (! empty($onDelete)) {
  610. $sql_query .= ' ON DELETE ' . $onDelete;
  611. }
  612. if (! empty($onUpdate)) {
  613. $sql_query .= ' ON UPDATE ' . $onUpdate;
  614. }
  615. $sql_query .= ';';
  616. return $sql_query;
  617. }
  618. ?>