tbl_operations.php 15 KB

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