tbl_columns_definition_form.inc.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  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. $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. $columnMeta['DefaultValue'] = $columnMeta['Default'];
  236. break;
  237. }
  238. }
  239. if (isset($columnMeta['Type'])) {
  240. $extracted_columnspec = Util::extractColumnSpec(
  241. $columnMeta['Type']
  242. );
  243. if ($extracted_columnspec['type'] == 'bit') {
  244. $columnMeta['Default']
  245. = Util::convertBitDefaultValue($columnMeta['Default']);
  246. }
  247. $type = $extracted_columnspec['type'];
  248. if ($length == '') {
  249. $length = $extracted_columnspec['spec_in_brackets'];
  250. }
  251. } else {
  252. // creating a column
  253. $columnMeta['Type'] = '';
  254. }
  255. // Variable tell if current column is bound in a foreign key constraint or not.
  256. // MySQL version from 5.6.6 allow renaming columns with foreign keys
  257. if (isset($columnMeta['Field'])
  258. && isset($form_params['table'])
  259. && $GLOBALS['dbi']->getVersion() < 50606
  260. ) {
  261. $columnMeta['column_status'] = $relation->checkChildForeignReferences(
  262. $form_params['db'],
  263. $form_params['table'],
  264. $columnMeta['Field'],
  265. $foreigners,
  266. $child_references
  267. );
  268. }
  269. // some types, for example longtext, are reported as
  270. // "longtext character set latin7" when their charset and / or collation
  271. // differs from the ones of the corresponding database.
  272. // rtrim the type, for cases like "float unsigned"
  273. $type = rtrim(
  274. preg_replace('/[\s]character set[\s][\S]+/', '', $type)
  275. );
  276. /**
  277. * old column attributes
  278. */
  279. if ($is_backup) {
  280. // old column name
  281. if (isset($columnMeta['Field'])) {
  282. $form_params['field_orig[' . $columnNumber . ']']
  283. = $columnMeta['Field'];
  284. if (isset($columnMeta['column_status'])
  285. && !$columnMeta['column_status']['isEditable']
  286. ) {
  287. $form_params['field_name[' . $columnNumber . ']']
  288. = $columnMeta['Field'];
  289. }
  290. } else {
  291. $form_params['field_orig[' . $columnNumber . ']'] = '';
  292. }
  293. // old column type
  294. if (isset($columnMeta['Type'])) {
  295. // keep in uppercase because the new type will be in uppercase
  296. $form_params['field_type_orig[' . $columnNumber . ']'] = mb_strtoupper($type);
  297. if (isset($columnMeta['column_status'])
  298. && !$columnMeta['column_status']['isEditable']
  299. ) {
  300. $form_params['field_type[' . $columnNumber . ']'] = mb_strtoupper($type);
  301. }
  302. } else {
  303. $form_params['field_type_orig[' . $columnNumber . ']'] = '';
  304. }
  305. // old column length
  306. $form_params['field_length_orig[' . $columnNumber . ']'] = $length;
  307. // old column default
  308. $form_params = array_merge(
  309. $form_params,
  310. array(
  311. "field_default_value_orig[${columnNumber}]" => Util::getValueByKey(
  312. $columnMeta, 'Default', ''
  313. ),
  314. "field_default_type_orig[${columnNumber}]" => Util::getValueByKey(
  315. $columnMeta, 'DefaultType', ''
  316. ),
  317. "field_collation_orig[${columnNumber}]" => Util::getValueByKey(
  318. $columnMeta, 'Collation', ''
  319. ),
  320. "field_attribute_orig[${columnNumber}]" => trim(
  321. Util::getValueByKey($extracted_columnspec, 'attribute', '')
  322. ),
  323. "field_null_orig[${columnNumber}]" => Util::getValueByKey(
  324. $columnMeta, 'Null', ''
  325. ),
  326. "field_extra_orig[${columnNumber}]" => Util::getValueByKey(
  327. $columnMeta, 'Extra', ''
  328. ),
  329. "field_comments_orig[${columnNumber}]" => Util::getValueByKey(
  330. $columnMeta, 'Comment', ''
  331. ),
  332. "field_virtuality_orig[${columnNumber}]" => Util::getValueByKey(
  333. $columnMeta, 'Virtuality', ''
  334. ),
  335. "field_expression_orig[${columnNumber}]" => Util::getValueByKey(
  336. $columnMeta, 'Expression', ''
  337. ),
  338. )
  339. );
  340. }
  341. $content_cells[$columnNumber] = array(
  342. 'column_number' => $columnNumber,
  343. 'column_meta' => $columnMeta,
  344. 'type_upper' => mb_strtoupper($type),
  345. 'length_values_input_size' => $length_values_input_size,
  346. 'length' => $length,
  347. 'extracted_columnspec' => $extracted_columnspec,
  348. 'submit_attribute' => $submit_attribute,
  349. 'comments_map' => $comments_map,
  350. 'fields_meta' => isset($fields_meta) ? $fields_meta : null,
  351. 'is_backup' => $is_backup,
  352. 'move_columns' => $move_columns,
  353. 'cfg_relation' => $cfgRelation,
  354. 'available_mime' => $available_mime,
  355. 'mime_map' => isset($mime_map) ? $mime_map : array()
  356. );
  357. } // end for
  358. include 'libraries/tbl_partition_definition.inc.php';
  359. $html = Template::get('columns_definitions/column_definitions_form')->render([
  360. 'is_backup' => $is_backup,
  361. 'fields_meta' => isset($fields_meta) ? $fields_meta : null,
  362. 'mimework' => $cfgRelation['mimework'],
  363. 'action' => $action,
  364. 'form_params' => $form_params,
  365. 'content_cells' => $content_cells,
  366. 'partition_details' => $partitionDetails,
  367. 'primary_indexes' => isset($_POST['primary_indexes']) ? $_POST['primary_indexes'] : null,
  368. 'unique_indexes' => isset($_POST['unique_indexes']) ? $_POST['unique_indexes'] : null,
  369. 'indexes' => isset($_POST['indexes']) ? $_POST['indexes'] : null,
  370. 'fulltext_indexes' => isset($_POST['fulltext_indexes']) ? $_POST['fulltext_indexes'] : null,
  371. 'spatial_indexes' => isset($_POST['spatial_indexes']) ? $_POST['spatial_indexes'] : null,
  372. 'table' => isset($_POST['table']) ? $_POST['table'] : null,
  373. 'comment' => isset($_POST['comment']) ? $_POST['comment'] : null,
  374. 'tbl_collation' => isset($_POST['tbl_collation']) ? $_POST['tbl_collation'] : null,
  375. 'tbl_storage_engine' => isset($_POST['tbl_storage_engine']) ? $_POST['tbl_storage_engine'] : null,
  376. 'connection' => isset($_POST['connection']) ? $_POST['connection'] : null,
  377. 'change_column' => isset($_POST['change_column']) ? $_POST['change_column'] : null,
  378. 'is_virtual_columns_supported' => Util::isVirtualColumnsSupported(),
  379. 'browse_mime' => isset($GLOBALS['cfg']['BrowseMIME']) ? $GLOBALS['cfg']['BrowseMIME'] : null,
  380. 'server_type' => Util::getServerType(),
  381. 'max_rows' => intval($GLOBALS['cfg']['MaxRows']),
  382. 'char_editing' => isset($GLOBALS['cfg']['CharEditing']) ? $GLOBALS['cfg']['CharEditing'] : null,
  383. 'attribute_types' => $GLOBALS['dbi']->types->getAttributes(),
  384. 'privs_available' => (isset($GLOBALS['col_priv']) ? $GLOBALS['col_priv'] : false
  385. && isset($GLOBALS['is_reload_priv']) ? $GLOBALS['is_reload_priv'] : false
  386. ),
  387. 'max_length' => $GLOBALS['dbi']->getVersion() >= 50503 ? 1024 : 255,
  388. 'have_partitioning' => Partition::havePartitioning(),
  389. 'dbi' => $GLOBALS['dbi'],
  390. 'disable_is' => $GLOBALS['cfg']['Server']['DisableIS'],
  391. ]);
  392. unset($form_params);
  393. $response = Response::getInstance();
  394. $response->getHeader()->getScripts()->addFiles(
  395. array(
  396. 'vendor/jquery/jquery.uitablefilter.js',
  397. 'indexes.js'
  398. )
  399. );
  400. $response->addHTML($html);