tbl_operations.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Various table operations
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. use PhpMyAdmin\Index;
  9. use PhpMyAdmin\Message;
  10. use PhpMyAdmin\Partition;
  11. use PhpMyAdmin\Operations;
  12. use PhpMyAdmin\Relation;
  13. use PhpMyAdmin\Response;
  14. use PhpMyAdmin\Table;
  15. use PhpMyAdmin\Util;
  16. /**
  17. *
  18. */
  19. require_once 'libraries/common.inc.php';
  20. /**
  21. * functions implementation for this script
  22. */
  23. require_once 'libraries/check_user_privileges.inc.php';
  24. $pma_table = new Table($GLOBALS['table'], $GLOBALS['db']);
  25. /**
  26. * Load JavaScript files
  27. */
  28. $response = Response::getInstance();
  29. $header = $response->getHeader();
  30. $scripts = $header->getScripts();
  31. $scripts->addFile('tbl_operations.js');
  32. /**
  33. * Runs common work
  34. */
  35. require 'libraries/tbl_common.inc.php';
  36. $url_query .= '&amp;goto=tbl_operations.php&amp;back=tbl_operations.php';
  37. $url_params['goto'] = $url_params['back'] = 'tbl_operations.php';
  38. /**
  39. * Gets relation settings
  40. */
  41. $relation = new Relation();
  42. $cfgRelation = $relation->getRelationsParam();
  43. // reselect current db (needed in some cases probably due to
  44. // the calling of PhpMyAdmin\Relation)
  45. $GLOBALS['dbi']->selectDb($GLOBALS['db']);
  46. /**
  47. * Gets tables information
  48. */
  49. $pma_table = $GLOBALS['dbi']->getTable(
  50. $GLOBALS['db'],
  51. $GLOBALS['table']
  52. );
  53. $reread_info = $pma_table->getStatusInfo(null, false);
  54. $GLOBALS['showtable'] = $pma_table->getStatusInfo(null, (isset($reread_info) && $reread_info ? true : false));
  55. if ($pma_table->isView()) {
  56. $tbl_is_view = true;
  57. $tbl_storage_engine = __('View');
  58. $show_comment = null;
  59. } else {
  60. $tbl_is_view = false;
  61. $tbl_storage_engine = $pma_table->getStorageEngine();
  62. $show_comment = $pma_table->getComment();
  63. }
  64. $tbl_collation = $pma_table->getCollation();
  65. $table_info_num_rows = $pma_table->getNumRows();
  66. $row_format = $pma_table->getRowFormat();
  67. $auto_increment = $pma_table->getAutoIncrement();
  68. $create_options = $pma_table->getCreateOptions();
  69. // set initial value of these variables, based on the current table engine
  70. if ($pma_table->isEngine('ARIA')) {
  71. // the value for transactional can be implicit
  72. // (no create option found, in this case it means 1)
  73. // or explicit (option found with a value of 0 or 1)
  74. // ($create_options['transactional'] may have been set by Table class,
  75. // from the $create_options)
  76. $create_options['transactional'] = (isset($create_options['transactional']) && $create_options['transactional'] == '0')
  77. ? '0'
  78. : '1';
  79. $create_options['page_checksum'] = (isset($create_options['page_checksum'])) ? $create_options['page_checksum'] : '';
  80. }
  81. $pma_table = $GLOBALS['dbi']->getTable(
  82. $GLOBALS['db'],
  83. $GLOBALS['table']
  84. );
  85. $reread_info = false;
  86. $table_alters = array();
  87. $operations = new Operations();
  88. /**
  89. * If the table has to be moved to some other database
  90. */
  91. if (isset($_POST['submit_move']) || isset($_POST['submit_copy'])) {
  92. //$_message = '';
  93. $operations->moveOrCopyTable($db, $table);
  94. // This was ended in an Ajax call
  95. exit;
  96. }
  97. /**
  98. * If the table has to be maintained
  99. */
  100. if (isset($_POST['table_maintenance'])) {
  101. include_once 'sql.php';
  102. unset($result);
  103. }
  104. /**
  105. * Updates table comment, type and options if required
  106. */
  107. if (isset($_POST['submitoptions'])) {
  108. $_message = '';
  109. $warning_messages = array();
  110. if (isset($_POST['new_name'])) {
  111. // Get original names before rename operation
  112. $oldTable = $pma_table->getName();
  113. $oldDb = $pma_table->getDbName();
  114. if ($pma_table->rename($_POST['new_name'])) {
  115. if (isset($_POST['adjust_privileges'])
  116. && ! empty($_POST['adjust_privileges'])
  117. ) {
  118. $operations->adjustPrivilegesRenameOrMoveTable(
  119. $oldDb, $oldTable, $_POST['db'], $_POST['new_name']
  120. );
  121. }
  122. // Reselect the original DB
  123. $GLOBALS['db'] = $oldDb;
  124. $GLOBALS['dbi']->selectDb($oldDb);
  125. $_message .= $pma_table->getLastMessage();
  126. $result = true;
  127. $GLOBALS['table'] = $pma_table->getName();
  128. $reread_info = true;
  129. $reload = true;
  130. } else {
  131. $_message .= $pma_table->getLastError();
  132. $result = false;
  133. }
  134. }
  135. if (! empty($_POST['new_tbl_storage_engine'])
  136. && mb_strtoupper($_POST['new_tbl_storage_engine']) !== $tbl_storage_engine
  137. ) {
  138. $new_tbl_storage_engine = mb_strtoupper($_POST['new_tbl_storage_engine']);
  139. if ($pma_table->isEngine('ARIA')) {
  140. $create_options['transactional'] = (isset($create_options['transactional']) && $create_options['transactional'] == '0')
  141. ? '0'
  142. : '1';
  143. $create_options['page_checksum'] = (isset($create_options['page_checksum'])) ? $create_options['page_checksum'] : '';
  144. }
  145. } else {
  146. $new_tbl_storage_engine = '';
  147. }
  148. $row_format = (isset($create_options['row_format']))
  149. ? $create_options['row_format']
  150. : $pma_table->getRowFormat();
  151. $table_alters = $operations->getTableAltersArray(
  152. $pma_table,
  153. $create_options['pack_keys'],
  154. (empty($create_options['checksum']) ? '0' : '1'),
  155. ((isset($create_options['page_checksum'])) ? $create_options['page_checksum'] : ''),
  156. (empty($create_options['delay_key_write']) ? '0' : '1'),
  157. $row_format,
  158. $new_tbl_storage_engine,
  159. ((isset($create_options['transactional']) && $create_options['transactional'] == '0') ? '0' : '1'),
  160. $tbl_collation
  161. );
  162. if (count($table_alters) > 0) {
  163. $sql_query = 'ALTER TABLE '
  164. . Util::backquote($GLOBALS['table']);
  165. $sql_query .= "\r\n" . implode("\r\n", $table_alters);
  166. $sql_query .= ';';
  167. $result .= $GLOBALS['dbi']->query($sql_query) ? true : false;
  168. $reread_info = true;
  169. unset($table_alters);
  170. $warning_messages = $operations->getWarningMessagesArray();
  171. }
  172. if (isset($_POST['tbl_collation'])
  173. && ! empty($_POST['tbl_collation'])
  174. && isset($_POST['change_all_collations'])
  175. && ! empty($_POST['change_all_collations'])
  176. ) {
  177. $operations->changeAllColumnsCollation(
  178. $GLOBALS['db'], $GLOBALS['table'], $_POST['tbl_collation']
  179. );
  180. }
  181. }
  182. /**
  183. * Reordering the table has been requested by the user
  184. */
  185. if (isset($_POST['submitorderby']) && ! empty($_POST['order_field'])) {
  186. list($sql_query, $result) = $operations->getQueryAndResultForReorderingTable();
  187. } // end if
  188. /**
  189. * A partition operation has been requested by the user
  190. */
  191. if (isset($_POST['submit_partition'])
  192. && ! empty($_POST['partition_operation'])
  193. ) {
  194. list($sql_query, $result) = $operations->getQueryAndResultForPartition();
  195. } // end if
  196. if ($reread_info) {
  197. // to avoid showing the old value (for example the AUTO_INCREMENT) after
  198. // a change, clear the cache
  199. $GLOBALS['dbi']->clearTableCache();
  200. $GLOBALS['dbi']->selectDb($GLOBALS['db']);
  201. $GLOBALS['showtable'] = $pma_table->getStatusInfo(null, true);
  202. if ($pma_table->isView()) {
  203. $tbl_is_view = true;
  204. $tbl_storage_engine = __('View');
  205. $show_comment = null;
  206. } else {
  207. $tbl_is_view = false;
  208. $tbl_storage_engine = $pma_table->getStorageEngine();
  209. $show_comment = $pma_table->getComment();
  210. }
  211. $tbl_collation = $pma_table->getCollation();
  212. $table_info_num_rows = $pma_table->getNumRows();
  213. $row_format = $pma_table->getRowFormat();
  214. $auto_increment = $pma_table->getAutoIncrement();
  215. $create_options = $pma_table->getCreateOptions();
  216. }
  217. unset($reread_info);
  218. if (isset($result) && empty($message_to_show)) {
  219. if (empty($_message)) {
  220. if (empty($sql_query)) {
  221. $_message = Message::success(__('No change'));
  222. } else {
  223. $_message = $result
  224. ? Message::success()
  225. : Message::error();
  226. }
  227. if ($response->isAjax()) {
  228. $response->setRequestStatus($_message->isSuccess());
  229. $response->addJSON('message', $_message);
  230. if (!empty($sql_query)) {
  231. $response->addJSON(
  232. 'sql_query', Util::getMessage(null, $sql_query)
  233. );
  234. }
  235. exit;
  236. }
  237. } else {
  238. $_message = $result
  239. ? Message::success($_message)
  240. : Message::error($_message);
  241. }
  242. if (! empty($warning_messages)) {
  243. $_message = new Message;
  244. $_message->addMessagesString($warning_messages);
  245. $_message->isError(true);
  246. if ($response->isAjax()) {
  247. $response->setRequestStatus(false);
  248. $response->addJSON('message', $_message);
  249. if (!empty($sql_query)) {
  250. $response->addJSON(
  251. 'sql_query', Util::getMessage(null, $sql_query)
  252. );
  253. }
  254. exit;
  255. }
  256. unset($warning_messages);
  257. }
  258. if (empty($sql_query)) {
  259. $response->addHTML(
  260. $_message->getDisplay()
  261. );
  262. } else {
  263. $response->addHTML(
  264. Util::getMessage($_message, $sql_query)
  265. );
  266. }
  267. unset($_message);
  268. }
  269. $url_params['goto']
  270. = $url_params['back']
  271. = 'tbl_operations.php';
  272. /**
  273. * Get columns names
  274. */
  275. $columns = $GLOBALS['dbi']->getColumns($GLOBALS['db'], $GLOBALS['table']);
  276. /**
  277. * Displays the page
  278. */
  279. /**
  280. * Order the table
  281. */
  282. $hideOrderTable = false;
  283. // `ALTER TABLE ORDER BY` does not make sense for InnoDB tables that contain
  284. // a user-defined clustered index (PRIMARY KEY or NOT NULL UNIQUE index).
  285. // InnoDB always orders table rows according to such an index if one is present.
  286. if ($tbl_storage_engine == 'INNODB') {
  287. $indexes = Index::getFromTable($GLOBALS['table'], $GLOBALS['db']);
  288. foreach ($indexes as $name => $idx) {
  289. if ($name == 'PRIMARY') {
  290. $hideOrderTable = true;
  291. break;
  292. } elseif (! $idx->getNonUnique()) {
  293. $notNull = true;
  294. foreach ($idx->getColumns() as $column) {
  295. if ($column->getNull()) {
  296. $notNull = false;
  297. break;
  298. }
  299. }
  300. if ($notNull) {
  301. $hideOrderTable = true;
  302. break;
  303. }
  304. }
  305. }
  306. }
  307. if (! $hideOrderTable) {
  308. $response->addHTML($operations->getHtmlForOrderTheTable($columns));
  309. }
  310. /**
  311. * Move table
  312. */
  313. $response->addHTML($operations->getHtmlForMoveTable());
  314. if (mb_strstr($show_comment, '; InnoDB free') === false) {
  315. if (mb_strstr($show_comment, 'InnoDB free') === false) {
  316. // only user entered comment
  317. $comment = $show_comment;
  318. } else {
  319. // here we have just InnoDB generated part
  320. $comment = '';
  321. }
  322. } else {
  323. // remove InnoDB comment from end, just the minimal part (*? is non greedy)
  324. $comment = preg_replace('@; InnoDB free:.*?$@', '', $show_comment);
  325. }
  326. // PACK_KEYS: MyISAM or ISAM
  327. // DELAY_KEY_WRITE, CHECKSUM, : MyISAM only
  328. // AUTO_INCREMENT: MyISAM and InnoDB since 5.0.3, PBXT
  329. // Here should be version check for InnoDB, however it is supported
  330. // in >5.0.4, >4.1.12 and >4.0.11, so I decided not to
  331. // check for version
  332. $response->addHTML(
  333. $operations->getTableOptionDiv(
  334. $pma_table, $comment, $tbl_collation, $tbl_storage_engine,
  335. $create_options['pack_keys'],
  336. $auto_increment,
  337. (empty($create_options['delay_key_write']) ? '0' : '1'),
  338. ((isset($create_options['transactional']) && $create_options['transactional'] == '0') ? '0' : '1'),
  339. ((isset($create_options['page_checksum'])) ? $create_options['page_checksum'] : ''),
  340. (empty($create_options['checksum']) ? '0' : '1')
  341. )
  342. );
  343. /**
  344. * Copy table
  345. */
  346. $response->addHTML($operations->getHtmlForCopytable());
  347. /**
  348. * Table maintenance
  349. */
  350. $response->addHTML(
  351. $operations->getHtmlForTableMaintenance($pma_table, $url_params)
  352. );
  353. if (! (isset($db_is_system_schema) && $db_is_system_schema)) {
  354. $truncate_table_url_params = array();
  355. $drop_table_url_params = array();
  356. if (! $tbl_is_view
  357. && ! (isset($db_is_system_schema) && $db_is_system_schema)
  358. ) {
  359. $this_sql_query = 'TRUNCATE TABLE '
  360. . Util::backquote($GLOBALS['table']);
  361. $truncate_table_url_params = array_merge(
  362. $url_params,
  363. array(
  364. 'sql_query' => $this_sql_query,
  365. 'goto' => 'tbl_structure.php',
  366. 'reload' => '1',
  367. 'message_to_show' => sprintf(
  368. __('Table %s has been emptied.'),
  369. htmlspecialchars($table)
  370. ),
  371. )
  372. );
  373. }
  374. if (! (isset($db_is_system_schema) && $db_is_system_schema)) {
  375. $this_sql_query = 'DROP TABLE '
  376. . Util::backquote($GLOBALS['table']);
  377. $drop_table_url_params = array_merge(
  378. $url_params,
  379. array(
  380. 'sql_query' => $this_sql_query,
  381. 'goto' => 'db_operations.php',
  382. 'reload' => '1',
  383. 'purge' => '1',
  384. 'message_to_show' => sprintf(
  385. ($tbl_is_view
  386. ? __('View %s has been dropped.')
  387. : __('Table %s has been dropped.')
  388. ),
  389. htmlspecialchars($table)
  390. ),
  391. // table name is needed to avoid running
  392. // PhpMyAdmin\RelationCleanup::database() on the whole db later
  393. 'table' => $GLOBALS['table'],
  394. )
  395. );
  396. }
  397. $response->addHTML(
  398. $operations->getHtmlForDeleteDataOrTable(
  399. $truncate_table_url_params,
  400. $drop_table_url_params
  401. )
  402. );
  403. }
  404. if (Partition::havePartitioning()) {
  405. $partition_names = Partition::getPartitionNames($db, $table);
  406. // show the Partition maintenance section only if we detect a partition
  407. if (! is_null($partition_names[0])) {
  408. $response->addHTML(
  409. $operations->getHtmlForPartitionMaintenance($partition_names, $url_params)
  410. );
  411. } // end if
  412. } // end if
  413. unset($partition_names);
  414. // Referential integrity check
  415. // The Referential integrity check was intended for the non-InnoDB
  416. // tables for which the relations are defined in pmadb
  417. // so I assume that if the current table is InnoDB, I don't display
  418. // this choice (InnoDB maintains integrity by itself)
  419. if ($cfgRelation['relwork'] && ! $pma_table->isEngine("INNODB")) {
  420. $GLOBALS['dbi']->selectDb($GLOBALS['db']);
  421. $foreign = $relation->getForeigners($GLOBALS['db'], $GLOBALS['table'], '', 'internal');
  422. if (! empty($foreign)) {
  423. $response->addHTML(
  424. $operations->getHtmlForReferentialIntegrityCheck($foreign, $url_params)
  425. );
  426. } // end if ($foreign)
  427. } // end if (!empty($cfg['Server']['relation']))