display_structure.twig 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. {% extends 'table/page_with_secondary_tabs.twig' %}
  2. {% block content %}
  3. <h1 class="d-none d-print-block">{{table}}</h1>
  4. <form method="post" action="{{ url('/table/structure') }}" name="fieldsForm" id="fieldsForm"
  5. class="ajax{{ hide_structure_actions ? ' HideStructureActions' }}">
  6. {{ get_hidden_inputs(db, table) }}
  7. <input type="hidden" name="table_type" value=
  8. {%- if db_is_system_schema -%}
  9. "information_schema"
  10. {%- elseif tbl_is_view -%}
  11. "view"
  12. {%- else -%}
  13. "table"
  14. {%- endif %}>
  15. <div class="table-responsive-md">
  16. <table id="tablestructure" class="table table-light table-striped table-hover w-auto">
  17. {# Table header #}
  18. <thead class="thead-light">
  19. <tr>
  20. <th class="print_ignore"></th>
  21. <th>#</th>
  22. <th>{% trans 'Name' %}</th>
  23. <th>{% trans 'Type' %}</th>
  24. <th>{% trans 'Collation' %}</th>
  25. <th>{% trans 'Attributes' %}</th>
  26. <th>{% trans 'Null' %}</th>
  27. <th>{% trans 'Default' %}</th>
  28. {% if show_column_comments -%}
  29. <th>{% trans 'Comments' %}</th>
  30. {%- endif %}
  31. <th>{% trans 'Extra' %}</th>
  32. {# @see table/structure.js, function moreOptsMenuResize() #}
  33. {% if not db_is_system_schema and not tbl_is_view %}
  34. <th colspan="{{ show_icons('ActionLinksMode') ? '8' : '9' -}}
  35. " class="action print_ignore">{% trans 'Action' %}</th>
  36. {% endif %}
  37. </tr>
  38. </thead>
  39. <tbody>
  40. {# Table body #}
  41. {% set rownum = 0 %}
  42. {% for row in fields %}
  43. {% set rownum = rownum + 1 %}
  44. {% set extracted_columnspec = extracted_columnspecs[rownum] %}
  45. {% set field_name = row['Field']|e %}
  46. {# For column comments #}
  47. {% set comments = row_comments[rownum] %}
  48. {# Underline commented fields and display a hover-title (CSS only) #}
  49. <tr>
  50. <td class="text-center print_ignore">
  51. <input type="checkbox" class="checkall" name="selected_fld[]" value="{{ row['Field'] }}" id="checkbox_row_{{ rownum }}">
  52. </td>
  53. <td class="right">{{ rownum }}</td>
  54. <th class="nowrap">
  55. <label for="checkbox_row_{{ rownum }}">
  56. {% if displayed_fields[rownum].comment is defined %}
  57. <span class="commented_column" title="{{ displayed_fields[rownum].comment }}">{{ displayed_fields[rownum].text }}</span>
  58. {% else %}
  59. {{ displayed_fields[rownum].text }}
  60. {% endif %}
  61. {{ displayed_fields[rownum].icon|raw }}
  62. </label>
  63. </th>
  64. <td{{ 'set' != extracted_columnspec['type'] and 'enum' != extracted_columnspec['type'] ? ' class="nowrap"' }}>
  65. <bdo dir="ltr" lang="en">
  66. {{ extracted_columnspec['displayed_type']|raw }}
  67. {% if relation_commwork and relation_mimework and browse_mime
  68. and mime_map[row['Field']]['mimetype'] is defined %}
  69. <br>{% trans 'Media type:' %} {{ mime_map[row['Field']]['mimetype']|replace({'_': '/'})|lower }}
  70. {% endif %}
  71. </bdo>
  72. </td>
  73. <td>
  74. {% if row['Collation'] is not empty %}
  75. <dfn title="{{ collations[row['Collation']].description }}">{{ collations[row['Collation']].name }}</dfn>
  76. {% endif %}
  77. </td>
  78. <td class="column_attribute nowrap">{{ attributes[rownum] }}</td>
  79. <td>{{ row['Null'] == 'YES' ? 'Yes'|trans : 'No'|trans }}</td>
  80. <td class="nowrap">
  81. {% if row['Default'] is not null %}
  82. {% if extracted_columnspec['type'] == 'bit' %}
  83. {{ row['Default']|convert_bit_default_value }}
  84. {% else %}
  85. {{ row['Default'] }}
  86. {% endif %}
  87. {% elseif row['Null'] == 'YES' %}
  88. <em>NULL</em>
  89. {% else %}
  90. <em>{% trans %}None{% context %}None for default{% endtrans %}</em>
  91. {% endif %}
  92. </td>
  93. {% if show_column_comments %}
  94. <td>
  95. {{ comments }}
  96. </td>
  97. {% endif %}
  98. <td class="nowrap">{{ row['Extra']|upper }}</td>
  99. {% if not tbl_is_view and not db_is_system_schema %}
  100. <td class="edit text-center print_ignore">
  101. <a class="change_column_anchor ajax" href="{{ url('/table/structure/change', {
  102. 'db': db,
  103. 'table': table,
  104. 'field': row['Field'],
  105. 'change_column': 1
  106. }) }}">
  107. {{ get_icon('b_edit', 'Change'|trans) }}
  108. </a>
  109. </td>
  110. <td class="drop text-center print_ignore">
  111. <a class="drop_column_anchor ajax" href="{{ url('/sql') }}" data-post="{{ get_common({
  112. 'db': db,
  113. 'table': table,
  114. 'sql_query': 'ALTER TABLE ' ~ backquote(table) ~ ' DROP ' ~ backquote(row['Field']) ~ ';',
  115. 'dropped_column': row['Field'],
  116. 'purge': true,
  117. 'message_to_show': 'Column %s has been dropped.'|trans|format(row['Field']|e)
  118. }) }}">
  119. {{ get_icon('b_drop', 'Drop'|trans) }}
  120. </a>
  121. </td>
  122. {% endif %}
  123. {% if not tbl_is_view and not db_is_system_schema %}
  124. {% set type = extracted_columnspec['print_type'] is not empty ? extracted_columnspec['print_type'] %}
  125. <td class="print_ignore">
  126. <ul class="table-structure-actions resizable-menu">
  127. {% if hide_structure_actions %}
  128. <li class="submenu shown">
  129. <a href="#" class="tab nowrap">{{ get_icon('b_more', 'More'|trans) }}</a>
  130. <ul>
  131. {% endif %}
  132. <li class="primary nowrap">
  133. {% if type == 'text' or type == 'blob' or tbl_storage_engine == 'ARCHIVE' or (primary and primary.hasColumn(field_name)) %}
  134. {{ get_icon('bd_primary', 'Primary'|trans) }}
  135. {% else %}
  136. <a rel="samepage" class="ajax add_key print_ignore add_primary_key_anchor" href="{{ url('/table/structure/add-key') }}" data-post="{{ get_common({
  137. 'db': db,
  138. 'table': table,
  139. 'sql_query': 'ALTER TABLE ' ~ backquote(table) ~ (primary ? ' DROP PRIMARY KEY,') ~ ' ADD PRIMARY KEY(' ~ backquote(row['Field']) ~ ');',
  140. 'message_to_show': 'A primary key has been added on %s.'|trans|format(row['Field']|e)
  141. }) }}">
  142. {{ get_icon('b_primary', 'Primary'|trans) }}
  143. </a>
  144. {% endif %}
  145. </li>
  146. <li class="add_unique unique nowrap">
  147. {% if type == 'text' or type == 'blob' or tbl_storage_engine == 'ARCHIVE' or field_name in columns_with_unique_index %}
  148. {{ get_icon('bd_unique', 'Unique'|trans) }}
  149. {% else %}
  150. <a rel="samepage" class="ajax add_key print_ignore add_unique_anchor" href="{{ url('/table/structure/add-key') }}" data-post="{{ get_common({
  151. 'db': db,
  152. 'table': table,
  153. 'sql_query': 'ALTER TABLE ' ~ backquote(table) ~ ' ADD UNIQUE(' ~ backquote(row['Field']) ~ ');',
  154. 'message_to_show': 'An index has been added on %s.'|trans|format(row['Field']|e)
  155. }) }}">
  156. {{ get_icon('b_unique', 'Unique'|trans) }}
  157. </a>
  158. {% endif %}
  159. </li>
  160. <li class="add_index nowrap">
  161. {% if type == 'text' or type == 'blob' or tbl_storage_engine == 'ARCHIVE' %}
  162. {{ get_icon('bd_index', 'Index'|trans) }}
  163. {% else %}
  164. <a rel="samepage" class="ajax add_key print_ignore add_index_anchor" href="{{ url('/table/structure/add-key') }}" data-post="{{ get_common({
  165. 'db': db,
  166. 'table': table,
  167. 'sql_query': 'ALTER TABLE ' ~ backquote(table) ~ ' ADD INDEX(' ~ backquote(row['Field']) ~ ');',
  168. 'message_to_show': 'An index has been added on %s.'|trans|format(row['Field']|e)
  169. }) }}">
  170. {{ get_icon('b_index', 'Index'|trans) }}
  171. </a>
  172. {% endif %}
  173. </li>
  174. {% set spatial_types = [
  175. 'geometry',
  176. 'point',
  177. 'linestring',
  178. 'polygon',
  179. 'multipoint',
  180. 'multilinestring',
  181. 'multipolygon',
  182. 'geomtrycollection'
  183. ] %}
  184. <li class="spatial nowrap">
  185. {% if type == 'text' or type == 'blob' or tbl_storage_engine == 'ARCHIVE' or (type not in spatial_types and (tbl_storage_engine == 'MYISAM' or mysql_int_version >= 50705)) %}
  186. {{ get_icon('bd_spatial', 'Spatial'|trans) }}
  187. {% else %}
  188. <a rel="samepage" class="ajax add_key print_ignore add_spatial_anchor" href="{{ url('/table/structure/add-key') }}" data-post="{{ get_common({
  189. 'db': db,
  190. 'table': table,
  191. 'sql_query': 'ALTER TABLE ' ~ backquote(table) ~ ' ADD SPATIAL(' ~ backquote(row['Field']) ~ ');',
  192. 'message_to_show': 'An index has been added on %s.'|trans|format(row['Field']|e)
  193. }) }}">
  194. {{ get_icon('b_spatial', 'Spatial'|trans) }}
  195. </a>
  196. {% endif %}
  197. </li>
  198. {# FULLTEXT is possible on TEXT, CHAR and VARCHAR #}
  199. <li class="fulltext nowrap">
  200. {% if tbl_storage_engine is not empty and (
  201. tbl_storage_engine == 'MYISAM'
  202. or tbl_storage_engine == 'ARIA'
  203. or tbl_storage_engine == 'MARIA'
  204. or (tbl_storage_engine == 'INNODB' and mysql_int_version >= 50604)
  205. ) and ('text' in type or 'char' in type) %}
  206. <a rel="samepage" class="ajax add_key add_fulltext_anchor" href="{{ url('/table/structure/add-key') }}" data-post="{{ get_common({
  207. 'db': db,
  208. 'table': table,
  209. 'sql_query': 'ALTER TABLE ' ~ backquote(table) ~ ' ADD FULLTEXT(' ~ backquote(row['Field']) ~ ');',
  210. 'message_to_show': 'An index has been added on %s.'|trans|format(row['Field']|e)
  211. }) }}">
  212. {{ get_icon('b_ftext', 'Fulltext'|trans) }}
  213. </a>
  214. {% else %}
  215. {{ get_icon('bd_ftext', 'Fulltext'|trans) }}
  216. {% endif %}
  217. </li>
  218. {# Distinct value action #}
  219. <li class="browse nowrap">
  220. <a href="{{ url('/sql') }}" data-post="{{ get_common({
  221. 'db': db,
  222. 'table': table,
  223. 'sql_query': 'SELECT COUNT(*) AS ' ~ backquote('Rows'|trans)
  224. ~ ', ' ~ backquote(row['Field'])
  225. ~ ' FROM ' ~ backquote(table)
  226. ~ ' GROUP BY ' ~ backquote(row['Field'])
  227. ~ ' ORDER BY ' ~ backquote(row['Field']),
  228. 'is_browse_distinct': true
  229. }) }}">
  230. {{ get_icon('b_browse', 'Distinct values'|trans) }}
  231. </a>
  232. </li>
  233. {% if central_columns_work %}
  234. <li class="browse nowrap">
  235. {% if row['Field'] in central_list %}
  236. <a href="#" class="central_columns remove_button">
  237. {{ get_icon('centralColumns_delete', 'Remove from central columns'|trans) }}
  238. </a>
  239. {% else %}
  240. <a href="#" class="central_columns add_button">
  241. {{ get_icon('centralColumns_add', 'Add to central columns'|trans) }}
  242. </a>
  243. {% endif %}
  244. </li>
  245. {% endif %}
  246. {% if hide_structure_actions %}
  247. </ul>
  248. </li>
  249. {% endif %}
  250. </ul>
  251. </td>
  252. {% endif %}
  253. </tr>
  254. {% endfor %}
  255. </tbody>
  256. </table>
  257. </div>
  258. <div class="print_ignore">
  259. {% include 'select_all.twig' with {
  260. 'theme_image_path': theme_image_path,
  261. 'text_dir': text_dir,
  262. 'form_name': 'fieldsForm'
  263. } only %}
  264. <button class="btn btn-link mult_submit" type="submit" formaction="{{ url('/table/structure/browse') }}">
  265. {{ get_icon('b_browse', 'Browse'|trans) }}
  266. </button>
  267. {% if not tbl_is_view and not db_is_system_schema %}
  268. <button class="btn btn-link mult_submit" type="submit" formaction="{{ url('/table/structure/change') }}">
  269. {{ get_icon('b_edit', 'Change'|trans) }}
  270. </button>
  271. <button class="btn btn-link mult_submit" type="submit" formaction="{{ url('/table/structure/drop-confirm') }}">
  272. {{ get_icon('b_drop', 'Drop'|trans) }}
  273. </button>
  274. {% if tbl_storage_engine != 'ARCHIVE' %}
  275. <button class="btn btn-link mult_submit" type="submit" formaction="{{ url('/table/structure/primary') }}">
  276. {{ get_icon('b_primary', 'Primary'|trans) }}
  277. </button>
  278. <button class="btn btn-link mult_submit" type="submit" formaction="{{ url('/table/structure/unique') }}">
  279. {{ get_icon('b_unique', 'Unique'|trans) }}
  280. </button>
  281. <button class="btn btn-link mult_submit" type="submit" formaction="{{ url('/table/structure/index') }}">
  282. {{ get_icon('b_index', 'Index'|trans) }}
  283. </button>
  284. <button class="btn btn-link mult_submit" type="submit" formaction="{{ url('/table/structure/spatial') }}">
  285. {{ get_icon('b_spatial', 'Spatial'|trans) }}
  286. </button>
  287. <button class="btn btn-link mult_submit" type="submit" formaction="{{ url('/table/structure/fulltext') }}">
  288. {{ get_icon('b_ftext', 'Fulltext'|trans) }}
  289. </button>
  290. {% if central_columns_work %}
  291. <button class="btn btn-link mult_submit" type="submit" formaction="{{ url('/table/structure/central-columns-add') }}">
  292. {{ get_icon('centralColumns_add', 'Add to central columns'|trans) }}
  293. </button>
  294. <button class="btn btn-link mult_submit" type="submit" formaction="{{ url('/table/structure/central-columns-remove') }}">
  295. {{ get_icon('centralColumns_delete', 'Remove from central columns'|trans) }}
  296. </button>
  297. {% endif %}
  298. {% endif %}
  299. {% endif %}
  300. </div>
  301. </form>
  302. <hr class="print_ignore">
  303. <div id="move_columns_dialog" class="hide" title="{% trans 'Move columns' %}">
  304. <p>{% trans 'Move the columns by dragging them up and down.' %}</p>
  305. <form action="{{ url('/table/structure/move-columns') }}" name="move_column_form" id="move_column_form">
  306. <div>
  307. {{ get_hidden_inputs(db, table) }}
  308. <ul></ul>
  309. </div>
  310. </form>
  311. </div>
  312. {# Work on the table #}
  313. <div id="structure-action-links">
  314. {% if tbl_is_view and not db_is_system_schema %}
  315. {{ link_or_button(
  316. url('/view/create', {'db': db, 'table': table}),
  317. get_icon('b_edit', 'Edit view'|trans, true)
  318. ) }}
  319. {% endif %}
  320. <a href="#" id="printView">{{ get_icon('b_print', 'Print'|trans, true) }}</a>
  321. {% if not tbl_is_view and not db_is_system_schema %}
  322. {# Only display propose table structure for MySQL < 8.0 #}
  323. {% if mysql_int_version < 80000 or is_mariadb %}
  324. <a class="mr-0" href="{{ url('/sql') }}" data-post="{{ get_common({
  325. 'db': db,
  326. 'table': table,
  327. 'sql_query': 'SELECT * FROM ' ~ backquote(table) ~ ' PROCEDURE ANALYSE()',
  328. 'session_max_rows': 'all'
  329. }) }}">
  330. {{ get_icon(
  331. 'b_tblanalyse',
  332. 'Propose table structure'|trans,
  333. true
  334. ) }}
  335. </a>
  336. {{ show_mysql_docu('procedure_analyse') }}
  337. {% endif %}
  338. {% if is_active %}
  339. <a href="{{ url('/table/tracking', {'db': db, 'table': table}) }}">
  340. {{ get_icon('eye', 'Track table'|trans, true) }}
  341. </a>
  342. {% endif %}
  343. <a href="#" id="move_columns_anchor">
  344. {{ get_icon('b_move', 'Move columns'|trans, true) }}
  345. </a>
  346. <a href="{{ url('/normalization', {'db': db, 'table': table}) }}">
  347. {{ get_icon('normalize', 'Normalize'|trans, true) }}
  348. </a>
  349. {% endif %}
  350. {% if tbl_is_view and not db_is_system_schema %}
  351. {% if is_active %}
  352. <a href="{{ url('/table/tracking', {'db': db, 'table': table}) }}">
  353. {{ get_icon('eye', 'Track view'|trans, true) }}
  354. </a>
  355. {% endif %}
  356. {% endif %}
  357. </div>
  358. {% if not tbl_is_view and not db_is_system_schema %}
  359. <form method="post" action="{{ url('/table/add-field') }}" id="addColumns" name="addColumns">
  360. {{ get_hidden_inputs(db, table) }}
  361. {% if show_icons('ActionLinksMode') %}
  362. {{ get_image('b_insrow', 'Add column'|trans) }}&nbsp;
  363. {% endif %}
  364. {% set num_fields -%}
  365. <input type="number" name="num_fields" value="1" onfocus="this.select()" min="1" required>
  366. {%- endset %}
  367. {{ 'Add %s column(s)'|trans|format(num_fields)|raw }}
  368. <input type="hidden" name="field_where" value="after">&nbsp;
  369. {# I tried displaying the drop-down inside the label but with Firefox the drop-down was blinking #}
  370. <select name="after_field">
  371. <option value="first" data-pos="first">
  372. {% trans 'at beginning of table' %}
  373. </option>
  374. {% for one_column_name in columns_list %}
  375. <option value="{{ one_column_name }}"
  376. {{- loop.revindex0 == 0 ? ' selected="selected"' }}>
  377. {{ 'after %s'|trans|format(one_column_name) }}
  378. </option>
  379. {% endfor %}
  380. </select>
  381. <input class="btn btn-primary" type="submit" value="{% trans 'Go' %}">
  382. </form>
  383. {% endif %}
  384. {% if not tbl_is_view and not db_is_system_schema and tbl_storage_engine != 'ARCHIVE' %}
  385. <div id="index_div" class="w-100 ajax">
  386. <fieldset class="index_info">
  387. <legend id="index_header">
  388. {% trans 'Indexes' %}
  389. {{ show_mysql_docu('optimizing-database-structure') }}
  390. </legend>
  391. {% if indexes is not empty %}
  392. {{ indexes_duplicates|raw }}
  393. <div class="table-responsive jsresponsive">
  394. <table class="table table-light table-striped table-hover table-sm w-auto" id="table_index">
  395. <thead class="thead-light">
  396. <tr>
  397. <th colspan="3" class="print_ignore">{% trans 'Action' %}</th>
  398. <th>{% trans 'Keyname' %}</th>
  399. <th>{% trans 'Type' %}</th>
  400. <th>{% trans 'Unique' %}</th>
  401. <th>{% trans 'Packed' %}</th>
  402. <th>{% trans 'Column' %}</th>
  403. <th>{% trans 'Cardinality' %}</th>
  404. <th>{% trans 'Collation' %}</th>
  405. <th>{% trans 'Null' %}</th>
  406. <th>{% trans 'Comment' %}</th>
  407. </tr>
  408. </thead>
  409. {% for index in indexes %}
  410. <tbody class="row_span">
  411. {% set columns_count = index.getColumnCount() %}
  412. <tr class="noclick">
  413. <td rowspan="{{ columns_count }}" class="edit_index print_ignore ajax">
  414. <a class="ajax" href="{{ url('/table/indexes') }}" data-post="{{ get_common({
  415. 'db': db,
  416. 'table': table,
  417. 'index': index.getName()
  418. }, '') }}">
  419. {{ get_icon('b_edit', 'Edit'|trans) }}
  420. </a>
  421. </td>
  422. <td rowspan="{{ columns_count }}" class="rename_index print_ignore ajax" >
  423. <a class="ajax" href="{{ url('/table/indexes/rename') }}" data-post="{{ get_common({
  424. 'db': db,
  425. 'table': table,
  426. 'index': index.getName()
  427. }, '') }}">
  428. {{ get_icon('b_rename', 'Rename'|trans) }}
  429. </a>
  430. </td>
  431. <td rowspan="{{ columns_count }}" class="print_ignore">
  432. {% if index.getName() == 'PRIMARY' %}
  433. {% set index_params = {
  434. 'sql_query': 'ALTER TABLE ' ~ backquote(table) ~ ' DROP PRIMARY KEY;',
  435. 'message_to_show': 'The primary key has been dropped.'|trans
  436. } %}
  437. {% else %}
  438. {% set index_params = {
  439. 'sql_query': 'ALTER TABLE ' ~ backquote(table) ~ ' DROP INDEX ' ~ backquote(index.getName()) ~ ';',
  440. 'message_to_show': 'Index %s has been dropped.'|trans|format(index.getName())
  441. } %}
  442. {% endif %}
  443. <input type="hidden" class="drop_primary_key_index_msg" value="{{ index_params.sql_query|js_format(false) }}">
  444. {{ link_or_button(
  445. url('/sql', index_params|merge({'db': db, 'table': table})),
  446. get_icon('b_drop', 'Drop'|trans),
  447. {'class': 'drop_primary_key_index_anchor ajax'}
  448. ) }}
  449. </td>
  450. <th rowspan="{{ columns_count }}">{{ index.getName() }}</th>
  451. <td rowspan="{{ columns_count }}">{{ index.getType()|default(index.getChoice()) }}</td>
  452. <td rowspan="{{ columns_count }}">{{ index.isUnique() ? 'Yes'|trans : 'No'|trans }}</td>
  453. <td rowspan="{{ columns_count }}">{{ index.isPacked()|raw }}</td>
  454. {% for column in index.getColumns() %}
  455. {% if column.getSeqInIndex() > 1 %}
  456. <tr class="noclick">
  457. {% endif %}
  458. <td>
  459. {{ column.getName() }}
  460. {% if column.getSubPart() is not empty %}
  461. ({{ column.getSubPart() }})
  462. {% endif %}
  463. </td>
  464. <td>{{ column.getCardinality() }}</td>
  465. <td>{{ column.getCollation() }}</td>
  466. <td>{{ column.getNull(true) }}</td>
  467. {% if column.getSeqInIndex() == 1 %}
  468. <td rowspan="{{ columns_count }}">{{ index.getComments() }}</td>
  469. {% endif %}
  470. </tr>
  471. {% endfor %}
  472. </tbody>
  473. {% endfor %}
  474. </table>
  475. </div>
  476. {% else %}
  477. <div class="no_indexes_defined">{{ 'No index defined!'|trans|notice }}</div>
  478. {% endif %}
  479. </fieldset>
  480. <fieldset class="tblFooters print_ignore text-left">
  481. <form action="{{ url('/table/indexes') }}" method="post">
  482. {{ get_hidden_inputs(db, table) }}
  483. <input type="hidden" name="create_index" value="1">
  484. {% apply format('<input class="mx-2" type="number" name="added_fields" value="1" min="1" required>')|raw %}
  485. {% trans %}Create an index on %s columns{% endtrans %}
  486. {% endapply %}
  487. <input class="btn btn-primary add_index ajax" type="submit" value="{% trans 'Go' %}">
  488. </form>
  489. </fieldset>
  490. </div>
  491. {% endif %}
  492. {# Display partition details #}
  493. {% if have_partitioning %}
  494. {# Detect partitioning #}
  495. {% if partition_names is not empty and partition_names[0] is not null %}
  496. {% set first_partition = partitions[0] %}
  497. {% set range_or_list = first_partition.getMethod() == 'RANGE'
  498. or first_partition.getMethod() == 'RANGE COLUMNS'
  499. or first_partition.getMethod() == 'LIST'
  500. or first_partition.getMethod() == 'LIST COLUMNS' %}
  501. {% set sub_partitions = first_partition.getSubPartitions() %}
  502. {% set has_sub_partitions = first_partition.hasSubPartitions() %}
  503. {% if has_sub_partitions %}
  504. {% set first_sub_partition = sub_partitions[0] %}
  505. {% endif %}
  506. <div id="partitions-2"{% if default_sliders_state != 'disabled' -%}
  507. {{- default_sliders_state == 'closed' ? ' style="display: none; overflow:auto;"' }} class="pma_auto_slider" title="{% trans 'Partitions' %}"
  508. {%- endif %}>
  509. {% include 'table/structure/display_partitions.twig' with {
  510. 'db': db,
  511. 'table': table,
  512. 'partitions': partitions,
  513. 'partition_method': first_partition.getMethod(),
  514. 'partition_expression': first_partition.getExpression(),
  515. 'has_description': first_partition.getDescription() is not empty,
  516. 'has_sub_partitions': has_sub_partitions,
  517. 'sub_partition_method': has_sub_partitions ? first_sub_partition.getMethod(),
  518. 'sub_partition_expression': has_sub_partitions ? first_sub_partition.getExpression(),
  519. 'range_or_list': range_or_list
  520. } only %}
  521. {% else %}
  522. {% include 'table/structure/display_partitions.twig' with {
  523. 'db': db,
  524. 'table': table
  525. } only %}
  526. {% endif %}
  527. </div>
  528. {% endif %}
  529. {# Displays Space usage and row statistics #}
  530. {% if show_stats %}
  531. {{ table_stats|raw }}
  532. {% endif %}
  533. <div class="clearfloat"></div>
  534. {% endblock %}