tbl_columns_definition_form.inc.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Display form for changing/adding table fields/columns.
  5. * Included by tbl_addfield.php and tbl_create.php
  6. *
  7. * @package PhpMyAdmin
  8. */
  9. use PhpMyAdmin\Di\Container;
  10. use PhpMyAdmin\Partition;
  11. use PhpMyAdmin\Relation;
  12. use PhpMyAdmin\Response;
  13. use PhpMyAdmin\Table;
  14. use PhpMyAdmin\Template;
  15. use PhpMyAdmin\Transformations;
  16. use PhpMyAdmin\Util;
  17. if (!defined('PHPMYADMIN')) {
  18. exit;
  19. }
  20. /**
  21. * Check parameters
  22. */
  23. Util::checkParameters(
  24. array('server', 'db', 'table', 'action', 'num_fields')
  25. );
  26. global $db, $table;
  27. $relation = new Relation();
  28. /**
  29. * Initialize to avoid code execution path warnings
  30. */
  31. if (!isset($num_fields)) {
  32. $num_fields = 0;
  33. }
  34. if (!isset($mime_map)) {
  35. $mime_map = null;
  36. }
  37. if (!isset($columnMeta)) {
  38. $columnMeta = array();
  39. }
  40. $length_values_input_size = 8;
  41. $content_cells = array();
  42. /** @var string $db */
  43. $form_params = array(
  44. 'db' => $db
  45. );
  46. if ($action == 'tbl_create.php') {
  47. $form_params['reload'] = 1;
  48. } else {
  49. if ($action == 'tbl_addfield.php') {
  50. $form_params = array_merge(
  51. $form_params, array(
  52. 'field_where' => Util::getValueByKey($_POST, 'field_where'))
  53. );
  54. if (isset($_POST['field_where'])) {
  55. $form_params['after_field'] = $_POST['after_field'];
  56. }
  57. }
  58. $form_params['table'] = $table;
  59. }
  60. if (isset($num_fields)) {
  61. $form_params['orig_num_fields'] = $num_fields;
  62. }
  63. $form_params = array_merge(
  64. $form_params,
  65. array(
  66. 'orig_field_where' => Util::getValueByKey($_POST, 'field_where'),
  67. 'orig_after_field' => Util::getValueByKey($_POST, 'after_field'),
  68. )
  69. );
  70. if (isset($selected) && is_array($selected)) {
  71. foreach ($selected as $o_fld_nr => $o_fld_val) {
  72. $form_params['selected[' . $o_fld_nr . ']'] = $o_fld_val;
  73. }
  74. }
  75. $is_backup = ($action != 'tbl_create.php' && $action != 'tbl_addfield.php');
  76. $cfgRelation = $relation->getRelationsParam();
  77. $comments_map = $relation->getComments($db, $table);
  78. $move_columns = array();
  79. if (isset($fields_meta)) {
  80. /** @var PhpMyAdmin\DatabaseInterface $dbi */
  81. $dbi = Container::getDefaultContainer()->get('dbi');
  82. $move_columns = $dbi->getTable($db, $table)->getColumnsMeta();
  83. }
  84. $available_mime = array();
  85. if ($cfgRelation['mimework'] && $GLOBALS['cfg']['BrowseMIME']) {
  86. $mime_map = Transformations::getMIME($db, $table);
  87. $available_mime = Transformations::getAvailableMIMEtypes();
  88. }
  89. // workaround for field_fulltext, because its submitted indices contain
  90. // the index as a value, not a key. Inserted here for easier maintenance
  91. // and less code to change in existing files.
  92. if (isset($field_fulltext) && is_array($field_fulltext)) {
  93. foreach ($field_fulltext as $fulltext_nr => $fulltext_indexkey) {
  94. $submit_fulltext[$fulltext_indexkey] = $fulltext_indexkey;
  95. }
  96. }
  97. if (isset($_POST['submit_num_fields'])
  98. || isset($_POST['submit_partition_change'])
  99. ) {
  100. //if adding new fields, set regenerate to keep the original values
  101. $regenerate = 1;
  102. }
  103. $foreigners = $relation->getForeigners($db, $table, '', 'foreign');
  104. $child_references = null;
  105. // From MySQL 5.6.6 onwards columns with foreign keys can be renamed.
  106. // Hence, no need to get child references
  107. if ($GLOBALS['dbi']->getVersion() < 50606) {
  108. $child_references = $relation->getChildReferences($db, $table);
  109. }
  110. for ($columnNumber = 0; $columnNumber < $num_fields; $columnNumber++) {
  111. $type = '';
  112. $length = '';
  113. $columnMeta = array();
  114. $submit_attribute = null;
  115. $extracted_columnspec = array();
  116. if (!empty($regenerate)) {
  117. $columnMeta = array_merge(
  118. $columnMeta,
  119. array(
  120. 'Field' => Util::getValueByKey(
  121. $_POST, "field_name.${columnNumber}", false
  122. ),
  123. 'Type' => Util::getValueByKey(
  124. $_POST, "field_type.${columnNumber}", false
  125. ),
  126. 'Collation' => Util::getValueByKey(
  127. $_POST, "field_collation.${columnNumber}", ''
  128. ),
  129. 'Null' => Util::getValueByKey(
  130. $_POST, "field_null.${columnNumber}", ''
  131. ),
  132. 'DefaultType' => Util::getValueByKey(
  133. $_POST, "field_default_type.${columnNumber}", 'NONE'
  134. ),
  135. 'DefaultValue' => Util::getValueByKey(
  136. $_POST, "field_default_value.${columnNumber}", ''
  137. ),
  138. 'Extra' => Util::getValueByKey(
  139. $_POST, "field_extra.${columnNumber}", false
  140. ),
  141. 'Virtuality' => Util::getValueByKey(
  142. $_POST, "field_virtuality.${columnNumber}", ''
  143. ),
  144. 'Expression' => Util::getValueByKey(
  145. $_POST, "field_expression.${columnNumber}", ''
  146. ),
  147. )
  148. );
  149. $columnMeta['Key'] = '';
  150. $parts = explode(
  151. '_', Util::getValueByKey($_POST, "field_key.${columnNumber}", ''), 2
  152. );
  153. if (count($parts) == 2 && $parts[1] == $columnNumber) {
  154. $columnMeta['Key'] = Util::getValueByKey(
  155. array(
  156. 'primary' => 'PRI',
  157. 'index' => 'MUL',
  158. 'unique' => 'UNI',
  159. 'fulltext' => 'FULLTEXT',
  160. 'spatial' => 'SPATIAL'
  161. ),
  162. $parts[0], ''
  163. );
  164. }
  165. $columnMeta['Comment']
  166. = isset($submit_fulltext[$columnNumber])
  167. && ($submit_fulltext[$columnNumber] == $columnNumber)
  168. ? 'FULLTEXT' : false;
  169. switch ($columnMeta['DefaultType']) {
  170. case 'NONE':
  171. $columnMeta['Default'] = null;
  172. break;
  173. case 'USER_DEFINED':
  174. $columnMeta['Default'] = $columnMeta['DefaultValue'];
  175. break;
  176. case 'NULL':
  177. case 'CURRENT_TIMESTAMP':
  178. case 'current_timestamp()':
  179. $columnMeta['Default'] = $columnMeta['DefaultType'];
  180. break;
  181. }
  182. $length = Util::getValueByKey($_POST, "field_length.${columnNumber}", $length);
  183. $submit_attribute = Util::getValueByKey(
  184. $_POST, "field_attribute.${columnNumber}", false
  185. );
  186. $comments_map[$columnMeta['Field']] = Util::getValueByKey(
  187. $_POST, "field_comments.${columnNumber}"
  188. );
  189. $mime_map[$columnMeta['Field']] = array_merge(
  190. isset($mime_map[$columnMeta['Field']]) ? $mime_map[$columnMeta['Field']] : [],
  191. array(
  192. 'mimetype' => Util::getValueByKey($_POST, "field_mimetype.${$columnNumber}"),
  193. 'transformation' => Util::getValueByKey(
  194. $_POST, "field_transformation.${$columnNumber}"
  195. ),
  196. 'transformation_options' => Util::getValueByKey(
  197. $_POST, "field_transformation_options.${$columnNumber}"
  198. ),
  199. )
  200. );
  201. } elseif (isset($fields_meta[$columnNumber])) {
  202. $columnMeta = $fields_meta[$columnNumber];
  203. $virtual = array(
  204. 'VIRTUAL', 'PERSISTENT', 'VIRTUAL GENERATED', 'STORED GENERATED'
  205. );
  206. if (in_array($columnMeta['Extra'], $virtual)) {
  207. $tableObj = new Table($GLOBALS['table'], $GLOBALS['db']);
  208. $expressions = $tableObj->getColumnGenerationExpression(
  209. $columnMeta['Field']
  210. );
  211. $columnMeta['Expression'] = $expressions[$columnMeta['Field']];
  212. }
  213. switch ($columnMeta['Default']) {
  214. case null:
  215. if (is_null($columnMeta['Default'])) { // null
  216. if ($columnMeta['Null'] == 'YES') {
  217. $columnMeta['DefaultType'] = 'NULL';
  218. $columnMeta['DefaultValue'] = '';
  219. } else {
  220. $columnMeta['DefaultType'] = 'NONE';
  221. $columnMeta['DefaultValue'] = '';
  222. }
  223. } else { // empty
  224. $columnMeta['DefaultType'] = 'USER_DEFINED';
  225. $columnMeta['DefaultValue'] = $columnMeta['Default'];
  226. }
  227. break;
  228. case 'CURRENT_TIMESTAMP':
  229. case 'current_timestamp()':
  230. $columnMeta['DefaultType'] = 'CURRENT_TIMESTAMP';
  231. $columnMeta['DefaultValue'] = '';
  232. break;
  233. default:
  234. $columnMeta['DefaultType'] = 'USER_DEFINED';
  235. if ('text' === substr($columnMeta['Type'], -4)) {
  236. $textDefault = substr($columnMeta['Default'], 1, -1);
  237. $columnMeta['Default'] = stripcslashes($textDefault !== false ? $textDefault : $columnMeta['Default']);
  238. }
  239. $columnMeta['DefaultValue'] = $columnMeta['Default'];
  240. break;
  241. }
  242. }
  243. if (isset($columnMeta['Type'])) {
  244. $extracted_columnspec = Util::extractColumnSpec(
  245. $columnMeta['Type']
  246. );
  247. if ($extracted_columnspec['type'] == 'bit') {
  248. $columnMeta['Default']
  249. = Util::convertBitDefaultValue($columnMeta['Default']);
  250. }
  251. $type = $extracted_columnspec['type'];
  252. if ($length == '') {
  253. $length = $extracted_columnspec['spec_in_brackets'];
  254. }
  255. } else {
  256. // creating a column
  257. $columnMeta['Type'] = '';
  258. }
  259. // Variable tell if current column is bound in a foreign key constraint or not.
  260. // MySQL version from 5.6.6 allow renaming columns with foreign keys
  261. if (isset($columnMeta['Field'])
  262. && isset($form_params['table'])
  263. && $GLOBALS['dbi']->getVersion() < 50606
  264. ) {
  265. $columnMeta['column_status'] = $relation->checkChildForeignReferences(
  266. $form_params['db'],
  267. $form_params['table'],
  268. $columnMeta['Field'],
  269. $foreigners,
  270. $child_references
  271. );
  272. }
  273. // some types, for example longtext, are reported as
  274. // "longtext character set latin7" when their charset and / or collation
  275. // differs from the ones of the corresponding database.
  276. // rtrim the type, for cases like "float unsigned"
  277. $type = rtrim(
  278. preg_replace('/[\s]character set[\s][\S]+/', '', $type)
  279. );
  280. /**
  281. * old column attributes
  282. */
  283. if ($is_backup) {
  284. // old column name
  285. if (isset($columnMeta['Field'])) {
  286. $form_params['field_orig[' . $columnNumber . ']']
  287. = $columnMeta['Field'];
  288. if (isset($columnMeta['column_status'])
  289. && !$columnMeta['column_status']['isEditable']
  290. ) {
  291. $form_params['field_name[' . $columnNumber . ']']
  292. = $columnMeta['Field'];
  293. }
  294. } else {
  295. $form_params['field_orig[' . $columnNumber . ']'] = '';
  296. }
  297. // old column type
  298. if (isset($columnMeta['Type'])) {
  299. // keep in uppercase because the new type will be in uppercase
  300. $form_params['field_type_orig[' . $columnNumber . ']'] = mb_strtoupper($type);
  301. if (isset($columnMeta['column_status'])
  302. && !$columnMeta['column_status']['isEditable']
  303. ) {
  304. $form_params['field_type[' . $columnNumber . ']'] = mb_strtoupper($type);
  305. }
  306. } else {
  307. $form_params['field_type_orig[' . $columnNumber . ']'] = '';
  308. }
  309. // old column length
  310. $form_params['field_length_orig[' . $columnNumber . ']'] = $length;
  311. // old column default
  312. $form_params = array_merge(
  313. $form_params,
  314. array(
  315. "field_default_value_orig[${columnNumber}]" => Util::getValueByKey(
  316. $columnMeta, 'Default', ''
  317. ),
  318. "field_default_type_orig[${columnNumber}]" => Util::getValueByKey(
  319. $columnMeta, 'DefaultType', ''
  320. ),
  321. "field_collation_orig[${columnNumber}]" => Util::getValueByKey(
  322. $columnMeta, 'Collation', ''
  323. ),
  324. "field_attribute_orig[${columnNumber}]" => trim(
  325. Util::getValueByKey($extracted_columnspec, 'attribute', '')
  326. ),
  327. "field_null_orig[${columnNumber}]" => Util::getValueByKey(
  328. $columnMeta, 'Null', ''
  329. ),
  330. "field_extra_orig[${columnNumber}]" => Util::getValueByKey(
  331. $columnMeta, 'Extra', ''
  332. ),
  333. "field_comments_orig[${columnNumber}]" => Util::getValueByKey(
  334. $columnMeta, 'Comment', ''
  335. ),
  336. "field_virtuality_orig[${columnNumber}]" => Util::getValueByKey(
  337. $columnMeta, 'Virtuality', ''
  338. ),
  339. "field_expression_orig[${columnNumber}]" => Util::getValueByKey(
  340. $columnMeta, 'Expression', ''
  341. ),
  342. )
  343. );
  344. }
  345. $content_cells[$columnNumber] = array(
  346. 'column_number' => $columnNumber,
  347. 'column_meta' => $columnMeta,
  348. 'type_upper' => mb_strtoupper($type),
  349. 'length_values_input_size' => $length_values_input_size,
  350. 'length' => $length,
  351. 'extracted_columnspec' => $extracted_columnspec,
  352. 'submit_attribute' => $submit_attribute,
  353. 'comments_map' => $comments_map,
  354. 'fields_meta' => isset($fields_meta) ? $fields_meta : null,
  355. 'is_backup' => $is_backup,
  356. 'move_columns' => $move_columns,
  357. 'cfg_relation' => $cfgRelation,
  358. 'available_mime' => $available_mime,
  359. 'mime_map' => isset($mime_map) ? $mime_map : array()
  360. );
  361. } // end for
  362. include 'libraries/tbl_partition_definition.inc.php';
  363. $html = Template::get('columns_definitions/column_definitions_form')->render([
  364. 'is_backup' => $is_backup,
  365. 'fields_meta' => isset($fields_meta) ? $fields_meta : null,
  366. 'mimework' => $cfgRelation['mimework'],
  367. 'action' => $action,
  368. 'form_params' => $form_params,
  369. 'content_cells' => $content_cells,
  370. 'partition_details' => $partitionDetails,
  371. 'primary_indexes' => isset($_POST['primary_indexes']) ? $_POST['primary_indexes'] : null,
  372. 'unique_indexes' => isset($_POST['unique_indexes']) ? $_POST['unique_indexes'] : null,
  373. 'indexes' => isset($_POST['indexes']) ? $_POST['indexes'] : null,
  374. 'fulltext_indexes' => isset($_POST['fulltext_indexes']) ? $_POST['fulltext_indexes'] : null,
  375. 'spatial_indexes' => isset($_POST['spatial_indexes']) ? $_POST['spatial_indexes'] : null,
  376. 'table' => isset($_POST['table']) ? $_POST['table'] : null,
  377. 'comment' => isset($_POST['comment']) ? $_POST['comment'] : null,
  378. 'tbl_collation' => isset($_POST['tbl_collation']) ? $_POST['tbl_collation'] : null,
  379. 'tbl_storage_engine' => isset($_POST['tbl_storage_engine']) ? $_POST['tbl_storage_engine'] : null,
  380. 'connection' => isset($_POST['connection']) ? $_POST['connection'] : null,
  381. 'change_column' => isset($_POST['change_column']) ? $_POST['change_column'] : null,
  382. 'is_virtual_columns_supported' => Util::isVirtualColumnsSupported(),
  383. 'browse_mime' => isset($GLOBALS['cfg']['BrowseMIME']) ? $GLOBALS['cfg']['BrowseMIME'] : null,
  384. 'server_type' => Util::getServerType(),
  385. 'max_rows' => intval($GLOBALS['cfg']['MaxRows']),
  386. 'char_editing' => isset($GLOBALS['cfg']['CharEditing']) ? $GLOBALS['cfg']['CharEditing'] : null,
  387. 'attribute_types' => $GLOBALS['dbi']->types->getAttributes(),
  388. 'privs_available' => ((isset($GLOBALS['col_priv']) ? $GLOBALS['col_priv'] : false)
  389. && (isset($GLOBALS['is_reload_priv']) ? $GLOBALS['is_reload_priv'] : false)
  390. ),
  391. 'max_length' => $GLOBALS['dbi']->getVersion() >= 50503 ? 1024 : 255,
  392. 'have_partitioning' => Partition::havePartitioning(),
  393. 'dbi' => $GLOBALS['dbi'],
  394. 'disable_is' => $GLOBALS['cfg']['Server']['DisableIS'],
  395. ]);
  396. unset($form_params);
  397. $response = Response::getInstance();
  398. $response->getHeader()->getScripts()->addFiles(
  399. array(
  400. 'vendor/jquery/jquery.uitablefilter.js',
  401. 'indexes.js'
  402. )
  403. );
  404. $response->addHTML($html);