relation.lib.php 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Set of functions used with the relation and pdf feature
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. if (! defined('PHPMYADMIN')) {
  9. exit;
  10. }
  11. /**
  12. * Executes a query as controluser if possible, otherwise as normal user
  13. *
  14. * @param string $sql the query to execute
  15. * @param boolean $show_error whether to display SQL error messages or not
  16. * @param int $options query options
  17. *
  18. * @return integer the result set, or false if no result set
  19. *
  20. * @access public
  21. *
  22. */
  23. function PMA_queryAsControlUser($sql, $show_error = true, $options = 0)
  24. {
  25. // Avoid caching of the number of rows affected; for example, this function
  26. // is called for tracking purposes but we want to display the correct number
  27. // of rows affected by the original query, not by the query generated for
  28. // tracking.
  29. $cache_affected_rows = false;
  30. if ($show_error) {
  31. $result = PMA_DBI_query(
  32. $sql,
  33. $GLOBALS['controllink'],
  34. $options,
  35. $cache_affected_rows
  36. );
  37. } else {
  38. $result = @PMA_DBI_try_query(
  39. $sql,
  40. $GLOBALS['controllink'],
  41. $options,
  42. $cache_affected_rows
  43. );
  44. } // end if... else...
  45. if ($result) {
  46. return $result;
  47. } else {
  48. return false;
  49. }
  50. } // end of the "PMA_queryAsControlUser()" function
  51. /**
  52. * Returns current relation parameters
  53. *
  54. * @return array $cfgRelation
  55. */
  56. function PMA_getRelationsParam()
  57. {
  58. if (empty($_SESSION['relation'][$GLOBALS['server']])) {
  59. $_SESSION['relation'][$GLOBALS['server']] = PMA__getRelationsParam();
  60. }
  61. // just for BC but needs to be before PMA_getRelationsParamDiagnostic()
  62. // which uses it
  63. $GLOBALS['cfgRelation'] = $_SESSION['relation'][$GLOBALS['server']];
  64. return $_SESSION['relation'][$GLOBALS['server']];
  65. }
  66. /**
  67. * prints out diagnostic info for pma relation feature
  68. *
  69. * @param array $cfgRelation Relation configuration
  70. *
  71. * @return string
  72. */
  73. function PMA_getRelationsParamDiagnostic($cfgRelation)
  74. {
  75. $retval = '';
  76. $messages['error'] = '<font color="red"><strong>'
  77. . __('not OK')
  78. . '</strong></font>'
  79. . ' [ <a href="%s" target="documentation">'
  80. . __('Documentation')
  81. . '</a> ]';
  82. $messages['ok'] = '<font color="green"><strong>'
  83. . _pgettext('Correctly working', 'OK')
  84. . '</strong></font>';
  85. $messages['enabled'] = '<font color="green">' . __('Enabled') . '</font>';
  86. $messages['disabled'] = '<font color="red">' . __('Disabled') . '</font>';
  87. if (false === $GLOBALS['cfg']['Server']['pmadb']) {
  88. $retval .= 'PMA Database ... '
  89. . sprintf($messages['error'], 'pmadb')
  90. . '<br />' . "\n"
  91. . __('General relation features')
  92. . ' <font color="green">' . __('Disabled')
  93. . '</font>' . "\n";
  94. } else {
  95. $retval .= '<table>' . "\n";
  96. $retval .= PMA_getDiagMessageForParameter(
  97. 'pmadb',
  98. $GLOBALS['cfg']['Server']['pmadb'],
  99. $messages,
  100. 'pmadb'
  101. );
  102. $retval .= PMA_getDiagMessageForParameter(
  103. 'relation',
  104. isset($cfgRelation['relation']),
  105. $messages,
  106. 'relation'
  107. );
  108. $retval .= PMA_getDiagMessageForFeature(
  109. __('General relation features'),
  110. 'relwork',
  111. $messages
  112. );
  113. $retval .= PMA_getDiagMessageForParameter(
  114. 'table_info',
  115. isset($cfgRelation['table_info']),
  116. $messages,
  117. 'table_info'
  118. );
  119. $retval .= PMA_getDiagMessageForFeature(
  120. __('Display Features'),
  121. 'displaywork',
  122. $messages
  123. );
  124. $retval .= PMA_getDiagMessageForParameter(
  125. 'table_coords',
  126. isset($cfgRelation['table_coords']),
  127. $messages,
  128. 'table_coords'
  129. );
  130. $retval .= PMA_getDiagMessageForParameter(
  131. 'pdf_pages',
  132. isset($cfgRelation['pdf_pages']),
  133. $messages,
  134. 'pdf_pages'
  135. );
  136. $retval .= PMA_getDiagMessageForFeature(
  137. __('Creation of PDFs'),
  138. 'pdfwork',
  139. $messages
  140. );
  141. $retval .= PMA_getDiagMessageForParameter(
  142. 'column_info',
  143. isset($cfgRelation['column_info']),
  144. $messages,
  145. 'column_info'
  146. );
  147. $retval .= PMA_getDiagMessageForFeature(
  148. __('Displaying Column Comments'),
  149. 'commwork',
  150. $messages,
  151. false
  152. );
  153. $retval .= PMA_getDiagMessageForFeature(
  154. __('Browser transformation'),
  155. 'mimework',
  156. $messages
  157. );
  158. if ($cfgRelation['commwork'] && ! $cfgRelation['mimework']) {
  159. $retval .= '<tr><td colspan=2 class="left">';
  160. $retval .= __('Please see the documentation on how to update your column_comments table');
  161. $retval .= '</td></tr>';
  162. }
  163. $retval .= PMA_getDiagMessageForParameter(
  164. 'bookmarktable',
  165. isset($cfgRelation['bookmark']),
  166. $messages,
  167. 'bookmark'
  168. );
  169. $retval .= PMA_getDiagMessageForFeature(
  170. __('Bookmarked SQL query'),
  171. 'bookmarkwork',
  172. $messages
  173. );
  174. $retval .= PMA_getDiagMessageForParameter(
  175. 'history',
  176. isset($cfgRelation['history']),
  177. $messages,
  178. 'history'
  179. );
  180. $retval .= PMA_getDiagMessageForFeature(
  181. __('SQL history'),
  182. 'historywork',
  183. $messages
  184. );
  185. $retval .= PMA_getDiagMessageForParameter(
  186. 'designer_coords',
  187. isset($cfgRelation['designer_coords']),
  188. $messages,
  189. 'designer_coords'
  190. );
  191. $retval .= PMA_getDiagMessageForFeature(
  192. __('Designer'),
  193. 'designerwork',
  194. $messages
  195. );
  196. $retval .= PMA_getDiagMessageForParameter(
  197. 'recent',
  198. isset($cfgRelation['recent']),
  199. $messages,
  200. 'recent'
  201. );
  202. $retval .= PMA_getDiagMessageForFeature(
  203. __('Persistent recently used tables'),
  204. 'recentwork',
  205. $messages
  206. );
  207. $retval .= PMA_getDiagMessageForParameter(
  208. 'table_uiprefs',
  209. isset($cfgRelation['table_uiprefs']),
  210. $messages,
  211. 'table_uiprefs'
  212. );
  213. $retval .= PMA_getDiagMessageForFeature(
  214. __('Persistent tables\' UI preferences'),
  215. 'uiprefswork',
  216. $messages
  217. );
  218. $retval .= PMA_getDiagMessageForParameter(
  219. 'tracking',
  220. isset($cfgRelation['tracking']),
  221. $messages,
  222. 'tracking'
  223. );
  224. $retval .= PMA_getDiagMessageForFeature(
  225. __('Tracking'),
  226. 'trackingwork',
  227. $messages
  228. );
  229. $retval .= PMA_getDiagMessageForParameter(
  230. 'userconfig',
  231. isset($cfgRelation['userconfig']),
  232. $messages,
  233. 'userconfig'
  234. );
  235. $retval .= PMA_getDiagMessageForFeature(
  236. __('User preferences'),
  237. 'userconfigwork',
  238. $messages
  239. );
  240. $retval .= '</table>' . "\n";
  241. $retval .= '<p>' . __('Quick steps to setup advanced features:') . '</p>';
  242. $retval .= '<ul>';
  243. $retval .= '<li>';
  244. $retval .= __(
  245. 'Create the needed tables with the '
  246. . '<code>examples/create_tables.sql</code>.'
  247. );
  248. $retval .= ' ' . PMA_Util::showDocu('setup', 'linked-tables');
  249. $retval .= '</li>';
  250. $retval .= '<li>';
  251. $retval .= __('Create a pma user and give access to these tables.');
  252. $retval .= ' ' . PMA_Util::showDocu('config', 'cfg_Servers_controluser');
  253. $retval .= '</li>';
  254. $retval .= '<li>';
  255. $retval .= __(
  256. 'Enable advanced features in configuration file '
  257. . '(<code>config.inc.php</code>), for example by '
  258. . 'starting from <code>config.sample.inc.php</code>.'
  259. );
  260. $retval .= ' ' . PMA_Util::showDocu('setup', 'quick-install');
  261. $retval .= '</li>';
  262. $retval .= '<li>';
  263. $retval .= __(
  264. 'Re-login to phpMyAdmin to load the updated configuration file.'
  265. );
  266. $retval .= '</li>';
  267. $retval .= '</ul>';
  268. }
  269. return $retval;
  270. }
  271. /**
  272. * prints out one diagnostic message for a feature
  273. *
  274. * @param string $feature_name feature name in a message string
  275. * @param string $relation_parameter the $GLOBALS['cfgRelation'] parameter to check
  276. * @param array $messages utility messages
  277. * @param boolean $skip_line whether to skip a line after the message
  278. *
  279. * @return string
  280. */
  281. function PMA_getDiagMessageForFeature($feature_name,
  282. $relation_parameter, $messages, $skip_line = true
  283. ) {
  284. $retval = ' <tr><td colspan=2 class="right">' . $feature_name . ': ';
  285. if ($GLOBALS['cfgRelation'][$relation_parameter]) {
  286. $retval .= $messages['enabled'];
  287. } else {
  288. $retval .= $messages['disabled'];
  289. }
  290. $retval .= '</td></tr>';
  291. if ($skip_line) {
  292. $retval .= '<tr><td>&nbsp;</td></tr>';
  293. }
  294. return $retval;
  295. }
  296. /**
  297. * prints out one diagnostic message for a configuration parameter
  298. *
  299. * @param string $parameter config parameter name to display
  300. * @param boolean $relation_parameter_set whether this parameter is set
  301. * @param array $messages utility messages
  302. * @param string $doc_anchor anchor in documentation
  303. *
  304. * @return void
  305. */
  306. function PMA_getDiagMessageForParameter($parameter,
  307. $relation_parameter_set, $messages, $doc_anchor
  308. ) {
  309. $retval = '<tr><th class="left">';
  310. $retval .= '$cfg[\'Servers\'][$i][\'' . $parameter . '\'] ... ';
  311. $retval .= '</th><td class="right">';
  312. if ($relation_parameter_set) {
  313. $retval .= $messages['ok'];
  314. } else {
  315. $retval .= sprintf(
  316. $messages['error'],
  317. PMA_Util::getDocuLink('config', 'cfg_Servers_' . $doc_anchor)
  318. );
  319. }
  320. $retval .= '</td></tr>' . "\n";
  321. return $retval;
  322. }
  323. /**
  324. * Defines the relation parameters for the current user
  325. * just a copy of the functions used for relations ;-)
  326. * but added some stuff to check what will work
  327. *
  328. * @access protected
  329. * @return array the relation parameters for the current user
  330. */
  331. function PMA__getRelationsParam()
  332. {
  333. $cfgRelation = array();
  334. $cfgRelation['relwork'] = false;
  335. $cfgRelation['displaywork'] = false;
  336. $cfgRelation['bookmarkwork']= false;
  337. $cfgRelation['pdfwork'] = false;
  338. $cfgRelation['commwork'] = false;
  339. $cfgRelation['mimework'] = false;
  340. $cfgRelation['historywork'] = false;
  341. $cfgRelation['recentwork'] = false;
  342. $cfgRelation['uiprefswork'] = false;
  343. $cfgRelation['trackingwork'] = false;
  344. $cfgRelation['designerwork'] = false;
  345. $cfgRelation['userconfigwork'] = false;
  346. $cfgRelation['allworks'] = false;
  347. $cfgRelation['user'] = null;
  348. $cfgRelation['db'] = null;
  349. if ($GLOBALS['server'] == 0 || empty($GLOBALS['cfg']['Server']['pmadb'])
  350. || ! PMA_DBI_select_db($GLOBALS['cfg']['Server']['pmadb'], $GLOBALS['controllink'])
  351. ) {
  352. // No server selected -> no bookmark table
  353. // we return the array with the falses in it,
  354. // to avoid some 'Unitialized string offset' errors later
  355. $GLOBALS['cfg']['Server']['pmadb'] = false;
  356. return $cfgRelation;
  357. }
  358. $cfgRelation['user'] = $GLOBALS['cfg']['Server']['user'];
  359. $cfgRelation['db'] = $GLOBALS['cfg']['Server']['pmadb'];
  360. // Now I just check if all tables that i need are present so I can for
  361. // example enable relations but not pdf...
  362. // I was thinking of checking if they have all required columns but I
  363. // fear it might be too slow
  364. $tab_query = 'SHOW TABLES FROM '
  365. . PMA_Util::backquote(
  366. $GLOBALS['cfg']['Server']['pmadb']
  367. );
  368. $tab_rs = PMA_queryAsControlUser($tab_query, false, PMA_DBI_QUERY_STORE);
  369. if (! $tab_rs) {
  370. // query failed ... ?
  371. //$GLOBALS['cfg']['Server']['pmadb'] = false;
  372. return $cfgRelation;
  373. }
  374. while ($curr_table = @PMA_DBI_fetch_row($tab_rs)) {
  375. if ($curr_table[0] == $GLOBALS['cfg']['Server']['bookmarktable']) {
  376. $cfgRelation['bookmark'] = $curr_table[0];
  377. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['relation']) {
  378. $cfgRelation['relation'] = $curr_table[0];
  379. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['table_info']) {
  380. $cfgRelation['table_info'] = $curr_table[0];
  381. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['table_coords']) {
  382. $cfgRelation['table_coords'] = $curr_table[0];
  383. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['designer_coords']) {
  384. $cfgRelation['designer_coords'] = $curr_table[0];
  385. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['column_info']) {
  386. $cfgRelation['column_info'] = $curr_table[0];
  387. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['pdf_pages']) {
  388. $cfgRelation['pdf_pages'] = $curr_table[0];
  389. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['history']) {
  390. $cfgRelation['history'] = $curr_table[0];
  391. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['recent']) {
  392. $cfgRelation['recent'] = $curr_table[0];
  393. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['table_uiprefs']) {
  394. $cfgRelation['table_uiprefs'] = $curr_table[0];
  395. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['tracking']) {
  396. $cfgRelation['tracking'] = $curr_table[0];
  397. } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['userconfig']) {
  398. $cfgRelation['userconfig'] = $curr_table[0];
  399. }
  400. } // end while
  401. PMA_DBI_free_result($tab_rs);
  402. if (isset($cfgRelation['relation'])) {
  403. $cfgRelation['relwork'] = true;
  404. if (isset($cfgRelation['table_info'])) {
  405. $cfgRelation['displaywork'] = true;
  406. }
  407. }
  408. if (isset($cfgRelation['table_coords']) && isset($cfgRelation['pdf_pages'])) {
  409. $cfgRelation['pdfwork'] = true;
  410. }
  411. if (isset($cfgRelation['column_info'])) {
  412. $cfgRelation['commwork'] = true;
  413. $cfgRelation['mimework'] = true;
  414. }
  415. if (isset($cfgRelation['history'])) {
  416. $cfgRelation['historywork'] = true;
  417. }
  418. if (isset($cfgRelation['recent'])) {
  419. $cfgRelation['recentwork'] = true;
  420. }
  421. if (isset($cfgRelation['table_uiprefs'])) {
  422. $cfgRelation['uiprefswork'] = true;
  423. }
  424. if (isset($cfgRelation['tracking'])) {
  425. $cfgRelation['trackingwork'] = true;
  426. }
  427. if (isset($cfgRelation['userconfig'])) {
  428. $cfgRelation['userconfigwork'] = true;
  429. }
  430. // we do not absolutely need that the internal relations or the PDF
  431. // schema feature be activated
  432. if (isset($cfgRelation['designer_coords'])) {
  433. $cfgRelation['designerwork'] = true;
  434. }
  435. if (isset($cfgRelation['bookmark'])) {
  436. $cfgRelation['bookmarkwork'] = true;
  437. }
  438. if ($cfgRelation['relwork'] && $cfgRelation['displaywork']
  439. && $cfgRelation['pdfwork'] && $cfgRelation['commwork']
  440. && $cfgRelation['mimework'] && $cfgRelation['historywork']
  441. && $cfgRelation['recentwork'] && $cfgRelation['uiprefswork']
  442. && $cfgRelation['trackingwork'] && $cfgRelation['userconfigwork']
  443. && $cfgRelation['bookmarkwork'] && $cfgRelation['designerwork']
  444. ) {
  445. $cfgRelation['allworks'] = true;
  446. }
  447. return $cfgRelation;
  448. } // end of the 'PMA_getRelationsParam()' function
  449. /**
  450. * Gets all Relations to foreign tables for a given table or
  451. * optionally a given column in a table
  452. *
  453. * @param string $db the name of the db to check for
  454. * @param string $table the name of the table to check for
  455. * @param string $column the name of the column to check for
  456. * @param string $source the source for foreign key information
  457. *
  458. * @return array db,table,column
  459. *
  460. * @access public
  461. */
  462. function PMA_getForeigners($db, $table, $column = '', $source = 'both')
  463. {
  464. $cfgRelation = PMA_getRelationsParam();
  465. $foreign = array();
  466. if ($cfgRelation['relwork'] && ($source == 'both' || $source == 'internal')) {
  467. $rel_query = '
  468. SELECT `master_field`,
  469. `foreign_db`,
  470. `foreign_table`,
  471. `foreign_field`
  472. FROM ' . PMA_Util::backquote($cfgRelation['db']) . '.' . PMA_Util::backquote($cfgRelation['relation']) . '
  473. WHERE `master_db` = \'' . PMA_Util::sqlAddSlashes($db) . '\'
  474. AND `master_table` = \'' . PMA_Util::sqlAddSlashes($table) . '\' ';
  475. if (strlen($column)) {
  476. $rel_query .= ' AND `master_field` = \'' . PMA_Util::sqlAddSlashes($column) . '\'';
  477. }
  478. $foreign = PMA_DBI_fetch_result($rel_query, 'master_field', null, $GLOBALS['controllink']);
  479. }
  480. if (($source == 'both' || $source == 'foreign') && strlen($table)) {
  481. $show_create_table_query = 'SHOW CREATE TABLE '
  482. . PMA_Util::backquote($db) . '.' . PMA_Util::backquote($table);
  483. $show_create_table = PMA_DBI_fetch_value($show_create_table_query, 0, 1);
  484. $analyzed_sql = PMA_SQP_analyze(PMA_SQP_parse($show_create_table));
  485. foreach ($analyzed_sql[0]['foreign_keys'] as $one_key) {
  486. // The analyzer may return more than one column name in the
  487. // index list or the ref_index_list; if this happens,
  488. // the current logic just discards the whole index; having
  489. // more than one index field is currently unsupported (see FAQ 3.6)
  490. if (count($one_key['index_list']) == 1) {
  491. foreach ($one_key['index_list'] as $i => $field) {
  492. // If a foreign key is defined in the 'internal' source (pmadb)
  493. // and as a native foreign key, we won't get it twice
  494. // if $source='both' because we use $field as key
  495. // The parser looks for a CONSTRAINT clause just before
  496. // the FOREIGN KEY clause. It finds it (as output from
  497. // SHOW CREATE TABLE) in MySQL 4.0.13, but not in older
  498. // versions like 3.23.58.
  499. // In those cases, the FOREIGN KEY parsing will put numbers
  500. // like -1, 0, 1... instead of the constraint number.
  501. if (isset($one_key['constraint'])) {
  502. $foreign[$field]['constraint'] = $one_key['constraint'];
  503. }
  504. if (isset($one_key['ref_db_name'])) {
  505. $foreign[$field]['foreign_db'] = $one_key['ref_db_name'];
  506. } else {
  507. $foreign[$field]['foreign_db'] = $db;
  508. }
  509. $foreign[$field]['foreign_table'] = $one_key['ref_table_name'];
  510. $foreign[$field]['foreign_field'] = $one_key['ref_index_list'][$i];
  511. if (isset($one_key['on_delete'])) {
  512. $foreign[$field]['on_delete'] = $one_key['on_delete'];
  513. }
  514. if (isset($one_key['on_update'])) {
  515. $foreign[$field]['on_update'] = $one_key['on_update'];
  516. }
  517. }
  518. }
  519. }
  520. }
  521. /**
  522. * Emulating relations for some information_schema and data_dictionary tables
  523. */
  524. $is_information_schema = strtolower($db) == 'information_schema';
  525. $is_data_dictionary = PMA_DRIZZLE && strtolower($db) == 'data_dictionary';
  526. if (($is_information_schema || $is_data_dictionary) && ($source == 'internal' || $source == 'both')) {
  527. if ($is_information_schema) {
  528. $relations_key = 'information_schema_relations';
  529. include_once './libraries/information_schema_relations.lib.php';
  530. } else {
  531. $relations_key = 'data_dictionary_relations';
  532. include_once './libraries/data_dictionary_relations.lib.php';
  533. }
  534. if (isset($GLOBALS[$relations_key][$table])) {
  535. foreach ($GLOBALS[$relations_key][$table] as $field => $relations) {
  536. if ((! strlen($column) || $column == $field)
  537. && (! isset($foreign[$field]) || ! strlen($foreign[$field]))
  538. ) {
  539. $foreign[$field] = $relations;
  540. }
  541. }
  542. }
  543. }
  544. return $foreign;
  545. } // end of the 'PMA_getForeigners()' function
  546. /**
  547. * Gets the display field of a table
  548. *
  549. * @param string $db the name of the db to check for
  550. * @param string $table the name of the table to check for
  551. *
  552. * @return string field name
  553. *
  554. * @access public
  555. */
  556. function PMA_getDisplayField($db, $table)
  557. {
  558. $cfgRelation = PMA_getRelationsParam();
  559. /**
  560. * Try to fetch the display field from DB.
  561. */
  562. if ($cfgRelation['displaywork']) {
  563. $disp_query = '
  564. SELECT `display_field`
  565. FROM ' . PMA_Util::backquote($cfgRelation['db']) . '.' . PMA_Util::backquote($cfgRelation['table_info']) . '
  566. WHERE `db_name` = \'' . PMA_Util::sqlAddSlashes($db) . '\'
  567. AND `table_name` = \'' . PMA_Util::sqlAddSlashes($table) . '\'';
  568. $row = PMA_DBI_fetch_single_row($disp_query, 'ASSOC', $GLOBALS['controllink']);
  569. if (isset($row['display_field'])) {
  570. return $row['display_field'];
  571. }
  572. }
  573. /**
  574. * Emulating the display field for some information_schema tables.
  575. */
  576. if ($db == 'information_schema') {
  577. switch ($table) {
  578. case 'CHARACTER_SETS':
  579. return 'DESCRIPTION';
  580. case 'TABLES':
  581. return 'TABLE_COMMENT';
  582. }
  583. }
  584. /**
  585. * No Luck...
  586. */
  587. return false;
  588. } // end of the 'PMA_getDisplayField()' function
  589. /**
  590. * Gets the comments for all columns of a table or the db itself
  591. *
  592. * @param string $db the name of the db to check for
  593. * @param string $table the name of the table to check for
  594. *
  595. * @return array [column_name] = comment
  596. *
  597. * @access public
  598. */
  599. function PMA_getComments($db, $table = '')
  600. {
  601. $comments = array();
  602. if ($table != '') {
  603. // MySQL native column comments
  604. $columns = PMA_DBI_get_columns($db, $table, null, true);
  605. if ($columns) {
  606. foreach ($columns as $column) {
  607. if (! empty($column['Comment'])) {
  608. $comments[$column['Field']] = $column['Comment'];
  609. }
  610. }
  611. }
  612. } else {
  613. $comments[] = PMA_getDbComment($db);
  614. }
  615. return $comments;
  616. } // end of the 'PMA_getComments()' function
  617. /**
  618. * Gets the comment for a db
  619. *
  620. * @param string $db the name of the db to check for
  621. *
  622. * @return string comment
  623. *
  624. * @access public
  625. */
  626. function PMA_getDbComment($db)
  627. {
  628. $cfgRelation = PMA_getRelationsParam();
  629. $comment = '';
  630. if ($cfgRelation['commwork']) {
  631. // pmadb internal db comment
  632. $com_qry = "
  633. SELECT `comment`
  634. FROM " . PMA_Util::backquote($cfgRelation['db']) . "." . PMA_Util::backquote($cfgRelation['column_info']) . "
  635. WHERE db_name = '" . PMA_Util::sqlAddSlashes($db) . "'
  636. AND table_name = ''
  637. AND column_name = '(db_comment)'";
  638. $com_rs = PMA_queryAsControlUser($com_qry, true, PMA_DBI_QUERY_STORE);
  639. if ($com_rs && PMA_DBI_num_rows($com_rs) > 0) {
  640. $row = PMA_DBI_fetch_assoc($com_rs);
  641. $comment = $row['comment'];
  642. }
  643. PMA_DBI_free_result($com_rs);
  644. }
  645. return $comment;
  646. } // end of the 'PMA_getDbComment()' function
  647. /**
  648. * Gets the comment for a db
  649. *
  650. * @access public
  651. *
  652. * @return string comment
  653. */
  654. function PMA_getDbComments()
  655. {
  656. $cfgRelation = PMA_getRelationsParam();
  657. $comments = array();
  658. if ($cfgRelation['commwork']) {
  659. // pmadb internal db comment
  660. $com_qry = "
  661. SELECT `db_name`, `comment`
  662. FROM " . PMA_Util::backquote($cfgRelation['db']) . "." . PMA_Util::backquote($cfgRelation['column_info']) . "
  663. WHERE `column_name` = '(db_comment)'";
  664. $com_rs = PMA_queryAsControlUser($com_qry, true, PMA_DBI_QUERY_STORE);
  665. if ($com_rs && PMA_DBI_num_rows($com_rs) > 0) {
  666. while ($row = PMA_DBI_fetch_assoc($com_rs)) {
  667. $comments[$row['db_name']] = $row['comment'];
  668. }
  669. }
  670. PMA_DBI_free_result($com_rs);
  671. }
  672. return $comments;
  673. } // end of the 'PMA_getDbComments()' function
  674. /**
  675. * Set a database comment to a certain value.
  676. *
  677. * @param string $db the name of the db
  678. * @param string $comment the value of the column
  679. *
  680. * @return boolean true, if comment-query was made.
  681. *
  682. * @access public
  683. */
  684. function PMA_setDbComment($db, $comment = '')
  685. {
  686. $cfgRelation = PMA_getRelationsParam();
  687. if (! $cfgRelation['commwork']) {
  688. return false;
  689. }
  690. if (strlen($comment)) {
  691. $upd_query = "
  692. INSERT INTO
  693. " . PMA_Util::backquote($cfgRelation['db']) . "." . PMA_Util::backquote($cfgRelation['column_info']) . "
  694. (`db_name`, `table_name`, `column_name`, `comment`)
  695. VALUES (
  696. '" . PMA_Util::sqlAddSlashes($db) . "',
  697. '',
  698. '(db_comment)',
  699. '" . PMA_Util::sqlAddSlashes($comment) . "')
  700. ON DUPLICATE KEY UPDATE
  701. `comment` = '" . PMA_Util::sqlAddSlashes($comment) . "'";
  702. } else {
  703. $upd_query = '
  704. DELETE FROM
  705. ' . PMA_Util::backquote($cfgRelation['db']) . '.' . PMA_Util::backquote($cfgRelation['column_info']) . '
  706. WHERE `db_name` = \'' . PMA_Util::sqlAddSlashes($db) . '\'
  707. AND `table_name` = \'\'
  708. AND `column_name` = \'(db_comment)\'';
  709. }
  710. if (isset($upd_query)) {
  711. return PMA_queryAsControlUser($upd_query);
  712. }
  713. return false;
  714. } // end of 'PMA_setDbComment()' function
  715. /**
  716. * Set a SQL history entry
  717. *
  718. * @param string $db the name of the db
  719. * @param string $table the name of the table
  720. * @param string $username the username
  721. * @param string $sqlquery the sql query
  722. *
  723. * @return void
  724. *
  725. * @access public
  726. */
  727. function PMA_setHistory($db, $table, $username, $sqlquery)
  728. {
  729. // Prevent to run this automatically on Footer class destroying in testsuite
  730. if (defined('TESTSUITE') || strlen($sqlquery) > $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) {
  731. return;
  732. }
  733. $cfgRelation = PMA_getRelationsParam();
  734. if (! isset($_SESSION['sql_history'])) {
  735. $_SESSION['sql_history'] = array();
  736. }
  737. $key = md5($sqlquery . $db . $table);
  738. if (isset($_SESSION['sql_history'][$key])) {
  739. unset($_SESSION['sql_history'][$key]);
  740. }
  741. $_SESSION['sql_history'][$key] = array(
  742. 'db' => $db,
  743. 'table' => $table,
  744. 'sqlquery' => $sqlquery,
  745. );
  746. if (count($_SESSION['sql_history']) > $GLOBALS['cfg']['QueryHistoryMax']) {
  747. // history should not exceed a maximum count
  748. array_shift($_SESSION['sql_history']);
  749. }
  750. if (! $cfgRelation['historywork'] || ! $GLOBALS['cfg']['QueryHistoryDB']) {
  751. return;
  752. }
  753. PMA_queryAsControlUser(
  754. 'INSERT INTO
  755. ' . PMA_Util::backquote($cfgRelation['db']) . '.' . PMA_Util::backquote($cfgRelation['history']) . '
  756. (`username`,
  757. `db`,
  758. `table`,
  759. `timevalue`,
  760. `sqlquery`)
  761. VALUES
  762. (\'' . PMA_Util::sqlAddSlashes($username) . '\',
  763. \'' . PMA_Util::sqlAddSlashes($db) . '\',
  764. \'' . PMA_Util::sqlAddSlashes($table) . '\',
  765. NOW(),
  766. \'' . PMA_Util::sqlAddSlashes($sqlquery) . '\')'
  767. );
  768. } // end of 'PMA_setHistory()' function
  769. /**
  770. * Gets a SQL history entry
  771. *
  772. * @param string $username the username
  773. *
  774. * @return array list of history items
  775. *
  776. * @access public
  777. */
  778. function PMA_getHistory($username)
  779. {
  780. $cfgRelation = PMA_getRelationsParam();
  781. /**
  782. * if db-based history is disabled but there exists a session-based
  783. * history, use it
  784. */
  785. if (! $GLOBALS['cfg']['QueryHistoryDB'] && isset($_SESSION['sql_history'])) {
  786. return array_reverse($_SESSION['sql_history']);
  787. }
  788. if (! $cfgRelation['historywork']) {
  789. return false;
  790. }
  791. $hist_query = '
  792. SELECT `db`,
  793. `table`,
  794. `sqlquery`
  795. FROM ' . PMA_Util::backquote($cfgRelation['db']) . '.' . PMA_Util::backquote($cfgRelation['history']) . '
  796. WHERE `username` = \'' . PMA_Util::sqlAddSlashes($username) . '\'
  797. ORDER BY `id` DESC';
  798. return PMA_DBI_fetch_result($hist_query, null, null, $GLOBALS['controllink']);
  799. } // end of 'PMA_getHistory()' function
  800. /**
  801. * purges SQL history
  802. *
  803. * deletes entries that exceeds $cfg['QueryHistoryMax'], oldest first, for the
  804. * given user
  805. *
  806. * @param string $username the username
  807. *
  808. * @return void
  809. *
  810. * @access public
  811. */
  812. function PMA_purgeHistory($username)
  813. {
  814. $cfgRelation = PMA_getRelationsParam();
  815. if (! $GLOBALS['cfg']['QueryHistoryDB'] || ! $cfgRelation['historywork']) {
  816. return;
  817. }
  818. if (! $cfgRelation['historywork']) {
  819. return;
  820. }
  821. $search_query = '
  822. SELECT `timevalue`
  823. FROM ' . PMA_Util::backquote($cfgRelation['db']) . '.' . PMA_Util::backquote($cfgRelation['history']) . '
  824. WHERE `username` = \'' . PMA_Util::sqlAddSlashes($username) . '\'
  825. ORDER BY `timevalue` DESC
  826. LIMIT ' . $GLOBALS['cfg']['QueryHistoryMax'] . ', 1';
  827. if ($max_time = PMA_DBI_fetch_value($search_query, 0, 0, $GLOBALS['controllink'])) {
  828. PMA_queryAsControlUser(
  829. 'DELETE FROM
  830. ' . PMA_Util::backquote($cfgRelation['db']) . '.' . PMA_Util::backquote($cfgRelation['history']) . '
  831. WHERE `username` = \'' . PMA_Util::sqlAddSlashes($username) . '\'
  832. AND `timevalue` <= \'' . $max_time . '\''
  833. );
  834. }
  835. } // end of 'PMA_purgeHistory()' function
  836. /**
  837. * Prepares the dropdown for one mode
  838. *
  839. * @param array $foreign the keys and values for foreigns
  840. * @param string $data the current data of the dropdown
  841. * @param string $mode the needed mode
  842. *
  843. * @return array the <option value=""><option>s
  844. *
  845. * @access protected
  846. */
  847. function PMA__foreignDropdownBuild($foreign, $data, $mode)
  848. {
  849. $reloptions = array();
  850. // id-only is a special mode used when no foreign display column
  851. // is available
  852. if ($mode == 'id-content' || $mode == 'id-only') {
  853. // sort for id-content
  854. if ($GLOBALS['cfg']['NaturalOrder']) {
  855. uksort($foreign, 'strnatcasecmp');
  856. } else {
  857. ksort($foreign);
  858. }
  859. } elseif ($mode == 'content-id') {
  860. // sort for content-id
  861. if ($GLOBALS['cfg']['NaturalOrder']) {
  862. natcasesort($foreign);
  863. } else {
  864. asort($foreign);
  865. }
  866. }
  867. foreach ($foreign as $key => $value) {
  868. if (PMA_strlen($value) <= $GLOBALS['cfg']['LimitChars']) {
  869. $vtitle = '';
  870. $value = htmlspecialchars($value);
  871. } else {
  872. $vtitle = htmlspecialchars($value);
  873. $value = htmlspecialchars(substr($value, 0, $GLOBALS['cfg']['LimitChars']) . '...');
  874. }
  875. $reloption = '<option value="' . htmlspecialchars($key) . '"';
  876. if ($vtitle != '') {
  877. $reloption .= ' title="' . $vtitle . '"';
  878. }
  879. if ((string) $key == (string) $data) {
  880. $reloption .= ' selected="selected"';
  881. }
  882. if ($mode == 'content-id') {
  883. $reloptions[] = $reloption . '>' . $value . '&nbsp;-&nbsp;' . htmlspecialchars($key) . '</option>';
  884. } elseif ($mode == 'id-content') {
  885. $reloptions[] = $reloption . '>' . htmlspecialchars($key) . '&nbsp;-&nbsp;' . $value . '</option>';
  886. } elseif ($mode == 'id-only') {
  887. $reloptions[] = $reloption . '>' . htmlspecialchars($key) . '</option>';
  888. }
  889. } // end foreach
  890. return $reloptions;
  891. } // end of 'PMA__foreignDropdownBuild' function
  892. /**
  893. * Outputs dropdown with values of foreign fields
  894. *
  895. * @param array $disp_row array of the displayed row
  896. * @param string $foreign_field the foreign field
  897. * @param string $foreign_display the foreign field to display
  898. * @param string $data the current data of the dropdown (field in row)
  899. * @param int $max maximum number of items in the dropdown
  900. *
  901. * @return string the <option value=""><option>s
  902. *
  903. * @access public
  904. */
  905. function PMA_foreignDropdown($disp_row, $foreign_field, $foreign_display, $data,
  906. $max = null
  907. ) {
  908. if (null === $max) {
  909. $max = $GLOBALS['cfg']['ForeignKeyMaxLimit'];
  910. }
  911. $foreign = array();
  912. // collect the data
  913. foreach ($disp_row as $relrow) {
  914. $key = $relrow[$foreign_field];
  915. // if the display field has been defined for this foreign table
  916. if ($foreign_display) {
  917. $value = $relrow[$foreign_display];
  918. } else {
  919. $value = '';
  920. } // end if ($foreign_display)
  921. $foreign[$key] = $value;
  922. } // end foreach
  923. // put the dropdown sections in correct order
  924. $top = array();
  925. $bottom = array();
  926. if ($foreign_display) {
  927. if (PMA_isValid($GLOBALS['cfg']['ForeignKeyDropdownOrder'], 'array')) {
  928. if (PMA_isValid($GLOBALS['cfg']['ForeignKeyDropdownOrder'][0])) {
  929. $top = PMA__foreignDropdownBuild(
  930. $foreign,
  931. $data,
  932. $GLOBALS['cfg']['ForeignKeyDropdownOrder'][0]
  933. );
  934. }
  935. if (PMA_isValid($GLOBALS['cfg']['ForeignKeyDropdownOrder'][1])) {
  936. $bottom = PMA__foreignDropdownBuild(
  937. $foreign,
  938. $data,
  939. $GLOBALS['cfg']['ForeignKeyDropdownOrder'][1]
  940. );
  941. }
  942. } else {
  943. $top = PMA__foreignDropdownBuild($foreign, $data, 'id-content');
  944. $bottom = PMA__foreignDropdownBuild($foreign, $data, 'content-id');
  945. }
  946. } else {
  947. $top = PMA__foreignDropdownBuild($foreign, $data, 'id-only');
  948. }
  949. // beginning of dropdown
  950. $ret = '<option value="">&nbsp;</option>';
  951. $top_count = count($top);
  952. if ($max == -1 || $top_count < $max) {
  953. $ret .= implode('', $top);
  954. if ($foreign_display && $top_count > 0) {
  955. // this empty option is to visually mark the beginning of the
  956. // second series of values (bottom)
  957. $ret .= '<option value="">&nbsp;</option>';
  958. }
  959. }
  960. if ($foreign_display) {
  961. $ret .= implode('', $bottom);
  962. }
  963. return $ret;
  964. } // end of 'PMA_foreignDropdown()' function
  965. /**
  966. * Gets foreign keys in preparation for a drop-down selector
  967. *
  968. * @param array $foreigners array of the foreign keys
  969. * @param string $field the foreign field name
  970. * @param bool $override_total whether to override the total
  971. * @param string $foreign_filter a possible filter
  972. * @param string $foreign_limit a possible LIMIT clause
  973. *
  974. * @return array data about the foreign keys
  975. *
  976. * @access public
  977. */
  978. function PMA_getForeignData($foreigners, $field, $override_total, $foreign_filter, $foreign_limit)
  979. {
  980. // we always show the foreign field in the drop-down; if a display
  981. // field is defined, we show it besides the foreign field
  982. $foreign_link = false;
  983. if ($foreigners && isset($foreigners[$field])) {
  984. $foreigner = $foreigners[$field];
  985. $foreign_db = $foreigner['foreign_db'];
  986. $foreign_table = $foreigner['foreign_table'];
  987. $foreign_field = $foreigner['foreign_field'];
  988. // Count number of rows in the foreign table. Currently we do
  989. // not use a drop-down if more than ForeignKeyMaxLimit rows in the
  990. // foreign table,
  991. // for speed reasons and because we need a better interface for this.
  992. //
  993. // We could also do the SELECT anyway, with a LIMIT, and ensure that
  994. // the current value of the field is one of the choices.
  995. $the_total = PMA_Table::countRecords($foreign_db, $foreign_table, true);
  996. if ($override_total == true || $the_total < $GLOBALS['cfg']['ForeignKeyMaxLimit']) {
  997. // foreign_display can be false if no display field defined:
  998. $foreign_display = PMA_getDisplayField($foreign_db, $foreign_table);
  999. $f_query_main = 'SELECT ' . PMA_Util::backquote($foreign_field)
  1000. . (($foreign_display == false) ? '' : ', ' . PMA_Util::backquote($foreign_display));
  1001. $f_query_from = ' FROM ' . PMA_Util::backquote($foreign_db) . '.' . PMA_Util::backquote($foreign_table);
  1002. $f_query_filter = empty($foreign_filter) ? '' : ' WHERE ' . PMA_Util::backquote($foreign_field)
  1003. . ' LIKE "%' . PMA_Util::sqlAddSlashes($foreign_filter, true) . '%"'
  1004. . (($foreign_display == false) ? '' : ' OR ' . PMA_Util::backquote($foreign_display)
  1005. . ' LIKE "%' . PMA_Util::sqlAddSlashes($foreign_filter, true) . '%"'
  1006. );
  1007. $f_query_order = ($foreign_display == false) ? '' :' ORDER BY ' . PMA_Util::backquote($foreign_table) . '.' . PMA_Util::backquote($foreign_display);
  1008. $f_query_limit = isset($foreign_limit) ? $foreign_limit : '';
  1009. if (!empty($foreign_filter)) {
  1010. $res = PMA_DBI_query('SELECT COUNT(*)' . $f_query_from . $f_query_filter);
  1011. if ($res) {
  1012. $the_total = PMA_DBI_fetch_value($res);
  1013. @PMA_DBI_free_result($res);
  1014. } else {
  1015. $the_total = 0;
  1016. }
  1017. }
  1018. $disp = PMA_DBI_query($f_query_main . $f_query_from . $f_query_filter . $f_query_order . $f_query_limit);
  1019. if ($disp && PMA_DBI_num_rows($disp) > 0) {
  1020. // If a resultset has been created, pre-cache it in the $disp_row array
  1021. // This helps us from not needing to use mysql_data_seek by accessing a pre-cached
  1022. // PHP array. Usually those resultsets are not that big, so a performance hit should
  1023. // not be expected.
  1024. $disp_row = array();
  1025. while ($single_disp_row = @PMA_DBI_fetch_assoc($disp)) {
  1026. $disp_row[] = $single_disp_row;
  1027. }
  1028. @PMA_DBI_free_result($disp);
  1029. }
  1030. } else {
  1031. $disp_row = null;
  1032. $foreign_link = true;
  1033. }
  1034. } // end if $foreigners
  1035. $foreignData['foreign_link'] = $foreign_link;
  1036. $foreignData['the_total'] = isset($the_total) ? $the_total : null;
  1037. $foreignData['foreign_display'] = isset($foreign_display) ? $foreign_display : null;
  1038. $foreignData['disp_row'] = isset($disp_row) ? $disp_row : null;
  1039. $foreignData['foreign_field'] = isset($foreign_field) ? $foreign_field : null;
  1040. return $foreignData;
  1041. } // end of 'PMA_getForeignData()' function
  1042. /**
  1043. * Finds all related tables
  1044. *
  1045. * @param array $all_tables All the involved tables
  1046. * @param string $master The master table to form the LEFT JOIN clause
  1047. *
  1048. * @return string LEFT JOIN
  1049. * @access private
  1050. */
  1051. function PMA_getRelatives($all_tables, $master)
  1052. {
  1053. $fromclause = '';
  1054. $emerg = '';
  1055. // The list of tables that we still couldn't connect
  1056. $remaining_tables = $all_tables;
  1057. unset($remaining_tables[$master]);
  1058. // The list of allready connected tables
  1059. $known_tables[$master] = $master;
  1060. $run = 0;
  1061. while (count($remaining_tables) > 0) {
  1062. // Whether to go from master to foreign or vice versa
  1063. if ($run % 2 == 0) {
  1064. $from = 'master';
  1065. $to = 'foreign';
  1066. } else {
  1067. $from = 'foreign';
  1068. $to = 'master';
  1069. }
  1070. $in_know = '(\'' . implode('\', \'', $known_tables) . '\')';
  1071. $in_left = '(\'' . implode('\', \'', $remaining_tables) . '\')';
  1072. $rel_query = 'SELECT *'
  1073. . ' FROM ' . PMA_Util::backquote($GLOBALS['cfgRelation']['db'])
  1074. . '.' . PMA_Util::backquote($GLOBALS['cfgRelation']['relation'])
  1075. . ' WHERE ' . $from . '_db = \'' . PMA_Util::sqlAddSlashes($GLOBALS['db']) . '\''
  1076. . ' AND ' . $to . '_db = \'' . PMA_Util::sqlAddSlashes($GLOBALS['db']) . '\''
  1077. . ' AND ' . $from . '_table IN ' . $in_know
  1078. . ' AND ' . $to . '_table IN ' . $in_left;
  1079. $relations = @PMA_DBI_query($rel_query, $GLOBALS['controllink']);
  1080. while ($row = PMA_DBI_fetch_assoc($relations)) {
  1081. $found_table = $row[$to . '_table'];
  1082. if (isset($remaining_tables[$found_table])) {
  1083. $fromclause
  1084. .= "\n" . ' LEFT JOIN '
  1085. . PMA_Util::backquote($GLOBALS['db']) . '.' . PMA_Util::backquote($row[$to . '_table']) . ' ON '
  1086. . PMA_Util::backquote($row[$from . '_table']) . '.'
  1087. . PMA_Util::backquote($row[$from . '_field']) . ' = '
  1088. . PMA_Util::backquote($row[$to . '_table']) . '.'
  1089. . PMA_Util::backquote($row[$to . '_field']) . ' ';
  1090. $known_tables[$found_table] = $found_table;
  1091. unset($remaining_tables[$found_table]);
  1092. }
  1093. } // end while
  1094. $run++;
  1095. if ($run > 5) {
  1096. foreach ($remaining_tables as $table) {
  1097. $emerg .= ', ' . PMA_Util::backquote($table);
  1098. unset($remaining_tables[$table]);
  1099. }
  1100. }
  1101. } // end while
  1102. $fromclause = $emerg . $fromclause;
  1103. return $fromclause;
  1104. } // end of the "PMA_getRelatives()" function
  1105. /**
  1106. * Rename a field in relation tables
  1107. *
  1108. * usually called after a column in a table was renamed
  1109. *
  1110. * @param string $db databse name
  1111. * @param string $table table name
  1112. * @param string $field old field name
  1113. * @param string $new_name new field name
  1114. *
  1115. * @return void
  1116. */
  1117. function PMA_REL_renameField($db, $table, $field, $new_name)
  1118. {
  1119. $cfgRelation = PMA_getRelationsParam();
  1120. if ($cfgRelation['displaywork']) {
  1121. $table_query = 'UPDATE '
  1122. . PMA_Util::backquote($cfgRelation['db']) . '.'
  1123. . PMA_Util::backquote($cfgRelation['table_info'])
  1124. . ' SET display_field = \'' . PMA_Util::sqlAddSlashes($new_name) . '\''
  1125. . ' WHERE db_name = \'' . PMA_Util::sqlAddSlashes($db) . '\''
  1126. . ' AND table_name = \'' . PMA_Util::sqlAddSlashes($table) . '\''
  1127. . ' AND display_field = \'' . PMA_Util::sqlAddSlashes($field) . '\'';
  1128. PMA_queryAsControlUser($table_query);
  1129. }
  1130. if ($cfgRelation['relwork']) {
  1131. $table_query = 'UPDATE '
  1132. . PMA_Util::backquote($cfgRelation['db']) . '.'
  1133. . PMA_Util::backquote($cfgRelation['relation'])
  1134. . ' SET master_field = \'' . PMA_Util::sqlAddSlashes($new_name) . '\''
  1135. . ' WHERE master_db = \'' . PMA_Util::sqlAddSlashes($db) . '\''
  1136. . ' AND master_table = \'' . PMA_Util::sqlAddSlashes($table) . '\''
  1137. . ' AND master_field = \'' . PMA_Util::sqlAddSlashes($field) . '\'';
  1138. PMA_queryAsControlUser($table_query);
  1139. $table_query = 'UPDATE '
  1140. . PMA_Util::backquote($cfgRelation['db']) . '.'
  1141. . PMA_Util::backquote($cfgRelation['relation'])
  1142. . ' SET foreign_field = \'' . PMA_Util::sqlAddSlashes($new_name) . '\''
  1143. . ' WHERE foreign_db = \'' . PMA_Util::sqlAddSlashes($db) . '\''
  1144. . ' AND foreign_table = \'' . PMA_Util::sqlAddSlashes($table) . '\''
  1145. . ' AND foreign_field = \'' . PMA_Util::sqlAddSlashes($field) . '\'';
  1146. PMA_queryAsControlUser($table_query);
  1147. } // end if relwork
  1148. }
  1149. /**
  1150. * Performs SQL query used for renaming table.
  1151. *
  1152. * @param string $table Relation table to use
  1153. * @param string $source_db Source database name
  1154. * @param string $target_db Target database name
  1155. * @param string $source_table Source table name
  1156. * @param string $target_table Target table name
  1157. * @param string $db_field Name of database field
  1158. * @param string $table_field Name of table field
  1159. *
  1160. * @return nothing.
  1161. */
  1162. function PMA_REL_renameSingleTable($table,
  1163. $source_db, $target_db,
  1164. $source_table, $target_table,
  1165. $db_field, $table_field
  1166. ) {
  1167. $query = 'UPDATE '
  1168. . PMA_Util::backquote($GLOBALS['cfgRelation']['db']) . '.'
  1169. . PMA_Util::backquote($GLOBALS['cfgRelation'][$table])
  1170. . ' SET ' . $db_field . ' = \'' . PMA_Util::sqlAddSlashes($target_db) . '\', '
  1171. . ' ' . $table_field . ' = \'' . PMA_Util::sqlAddSlashes($target_table) . '\''
  1172. . ' WHERE '
  1173. . $db_field . ' = \'' . PMA_Util::sqlAddSlashes($source_db) . '\''
  1174. . ' AND '
  1175. . $table_field . ' = \'' . PMA_Util::sqlAddSlashes($source_table) . '\'';
  1176. PMA_queryAsControlUser($query);
  1177. }
  1178. /**
  1179. * Rename a table in relation tables
  1180. *
  1181. * usually called after table has been moved
  1182. *
  1183. * @param string $source_db Source database name
  1184. * @param string $target_db Target database name
  1185. * @param string $source_table Source table name
  1186. * @param string $target_table Target table name
  1187. *
  1188. * @return nothing
  1189. */
  1190. function PMA_REL_renameTable($source_db, $target_db, $source_table, $target_table)
  1191. {
  1192. // Move old entries from PMA-DBs to new table
  1193. if ($GLOBALS['cfgRelation']['commwork']) {
  1194. PMA_REL_renameSingleTable(
  1195. 'column_info',
  1196. $source_db, $target_db,
  1197. $source_table, $target_table,
  1198. 'db_name', 'table_name'
  1199. );
  1200. }
  1201. // updating bookmarks is not possible since only a single table is
  1202. // moved, and not the whole DB.
  1203. if ($GLOBALS['cfgRelation']['displaywork']) {
  1204. PMA_REL_renameSingleTable(
  1205. 'table_info',
  1206. $source_db, $target_db,
  1207. $source_table, $target_table,
  1208. 'db_name', 'table_name'
  1209. );
  1210. }
  1211. if ($GLOBALS['cfgRelation']['relwork']) {
  1212. PMA_REL_renameSingleTable(
  1213. 'relation',
  1214. $source_db, $target_db,
  1215. $source_table, $target_table,
  1216. 'foreign_db', 'foreign_table'
  1217. );
  1218. PMA_REL_renameSingleTable(
  1219. 'relation',
  1220. $source_db, $target_db,
  1221. $source_table, $target_table,
  1222. 'master_db', 'master_table'
  1223. );
  1224. }
  1225. /**
  1226. * @todo Can't get moving PDFs the right way. The page numbers
  1227. * always get screwed up independently from duplication because the
  1228. * numbers do not seem to be stored on a per-database basis. Would
  1229. * the author of pdf support please have a look at it?
  1230. */
  1231. if ($GLOBALS['cfgRelation']['pdfwork']) {
  1232. PMA_REL_renameSingleTable(
  1233. 'table_coords',
  1234. $source_db, $target_db,
  1235. $source_table, $target_table,
  1236. 'db_name', 'table_name'
  1237. );
  1238. }
  1239. if ($GLOBALS['cfgRelation']['designerwork']) {
  1240. PMA_REL_renameSingleTable(
  1241. 'designer_coords',
  1242. $source_db, $target_db,
  1243. $source_table, $target_table,
  1244. 'db_name', 'table_name'
  1245. );
  1246. }
  1247. }
  1248. /**
  1249. * Create a PDF page
  1250. *
  1251. * @param string $newpage name of the new PDF page
  1252. * @param array $cfgRelation Relation configuration
  1253. * @param string $db database name
  1254. *
  1255. * @return string $pdf_page_number
  1256. */
  1257. function PMA_REL_createPage($newpage, $cfgRelation, $db)
  1258. {
  1259. if (! isset($newpage) || $newpage == '') {
  1260. $newpage = __('no description');
  1261. }
  1262. $ins_query = 'INSERT INTO '
  1263. . PMA_Util::backquote($GLOBALS['cfgRelation']['db']) . '.'
  1264. . PMA_Util::backquote($cfgRelation['pdf_pages'])
  1265. . ' (db_name, page_descr)'
  1266. . ' VALUES (\''
  1267. . PMA_Util::sqlAddSlashes($db) . '\', \''
  1268. . PMA_Util::sqlAddSlashes($newpage) . '\')';
  1269. PMA_queryAsControlUser($ins_query, false);
  1270. return PMA_DBI_insert_id(
  1271. isset($GLOBALS['controllink']) ? $GLOBALS['controllink'] : ''
  1272. );
  1273. }
  1274. ?>