PageRenderTime 71ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 1ms

/phpmyadmin/libraries/DisplayResults.class.php

https://bitbucket.org/openemr/openemr
PHP | 5769 lines | 3321 code | 858 blank | 1590 comment | 601 complexity | 7abde8c08b12edb0e43917c75c4d827e MD5 | raw file
Possible License(s): Apache-2.0, AGPL-1.0, GPL-2.0, LGPL-3.0, BSD-3-Clause, Unlicense, MPL-2.0, GPL-3.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Hold the PMA_DisplayResults class
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. if (! defined('PHPMYADMIN')) {
  9. exit;
  10. }
  11. require_once './libraries/transformations.lib.php';
  12. /**
  13. * Handle all the functionalities related to displaying results
  14. * of sql queries, stored procedure, browsing sql processes or
  15. * displaying binary log.
  16. *
  17. * @package PhpMyAdmin
  18. */
  19. class PMA_DisplayResults
  20. {
  21. // Define constants
  22. const NO_EDIT_OR_DELETE = 'nn';
  23. const UPDATE_ROW = 'ur';
  24. const DELETE_ROW = 'dr';
  25. const KILL_PROCESS = 'kp';
  26. const POSITION_LEFT = 'left';
  27. const POSITION_RIGHT = 'right';
  28. const POSITION_BOTH = 'both';
  29. const POSITION_NONE = 'none';
  30. const PLACE_TOP_DIRECTION_DROPDOWN = 'top_direction_dropdown';
  31. const PLACE_BOTTOM_DIRECTION_DROPDOWN = 'bottom_direction_dropdown';
  32. const DISPLAY_FULL_TEXT = 'F';
  33. const DISPLAY_PARTIAL_TEXT = 'P';
  34. const HEADER_FLIP_TYPE_AUTO = 'auto';
  35. const HEADER_FLIP_TYPE_CSS = 'css';
  36. const HEADER_FLIP_TYPE_FAKE = 'fake';
  37. const DATE_FIELD = 'date';
  38. const DATETIME_FIELD = 'datetime';
  39. const TIMESTAMP_FIELD = 'timestamp';
  40. const TIME_FIELD = 'time';
  41. const STRING_FIELD = 'string';
  42. const GEOMETRY_FIELD = 'geometry';
  43. const BLOB_FIELD = 'BLOB';
  44. const BINARY_FIELD = 'BINARY';
  45. const RELATIONAL_KEY = 'K';
  46. const RELATIONAL_DISPLAY_COLUMN = 'D';
  47. const GEOMETRY_DISP_GEOM = 'GEOM';
  48. const GEOMETRY_DISP_WKT = 'WKT';
  49. const GEOMETRY_DISP_WKB = 'WKB';
  50. const SMART_SORT_ORDER = 'SMART';
  51. const ASCENDING_SORT_DIR = 'ASC';
  52. const DESCENDING_SORT_DIR = 'DESC';
  53. const TABLE_TYPE_INNO_DB = 'InnoDB';
  54. const ALL_ROWS = 'all';
  55. const QUERY_TYPE_SELECT = 'SELECT';
  56. const ROUTINE_PROCEDURE = 'procedure';
  57. const ROUTINE_FUNCTION = 'function';
  58. const ACTION_LINK_CONTENT_ICONS = 'icons';
  59. const ACTION_LINK_CONTENT_TEXT = 'text';
  60. // Declare global fields
  61. /** array with properties of the class */
  62. private $_property_array = array(
  63. /** string Database name */
  64. 'db' => null,
  65. /** string Table name */
  66. 'table' => null,
  67. /** string the URL to go back in case of errors */
  68. 'goto' => null,
  69. /** string the SQL query */
  70. 'sql_query' => null,
  71. /**
  72. * integer the total number of rows returned by the SQL query without any
  73. * appended "LIMIT" clause programmatically
  74. */
  75. 'unlim_num_rows' => null,
  76. /** array meta information about fields */
  77. 'fields_meta' => null,
  78. /** boolean */
  79. 'is_count' => null,
  80. /** integer */
  81. 'is_export' => null,
  82. /** boolean */
  83. 'is_func' => null,
  84. /** integer */
  85. 'is_analyse' => null,
  86. /** integer the total number of rows returned by the SQL query */
  87. 'num_rows' => null,
  88. /** integer the total number of fields returned by the SQL query */
  89. 'fields_cnt' => null,
  90. /** double time taken for execute the SQL query */
  91. 'querytime' => null,
  92. /** string path for theme images directory */
  93. 'pma_theme_image' => null,
  94. /** string */
  95. 'text_dir' => null,
  96. /** boolean */
  97. 'is_maint' => null,
  98. /** boolean */
  99. 'is_explain' => null,
  100. /** boolean */
  101. 'is_show' => null,
  102. /** boolean */
  103. 'is_browse_distinct' => null,
  104. /** array table definitions */
  105. 'showtable' => null,
  106. /** string */
  107. 'printview' => null,
  108. /** string URL query */
  109. 'url_query' => null,
  110. /** array column names to highlight */
  111. 'highlight_columns' => null,
  112. /** array holding various display information */
  113. 'display_params' => null,
  114. /** array mime types information of fields */
  115. 'mime_map' => null,
  116. /** boolean */
  117. 'editable' => null,
  118. /** random unique ID to distinguish result set */
  119. 'unique_id' => null,
  120. /** where clauses for each row, each table in the row */
  121. 'whereClauseMap' => array(),
  122. );
  123. /**
  124. * This variable contains the column transformation information
  125. * for some of the system databases.
  126. * One element of this array represent all relevant columns in all tables in
  127. * one specific database
  128. */
  129. public $transformation_info;
  130. /**
  131. * Get any property of this class
  132. *
  133. * @param string $property name of the property
  134. *
  135. * @return mixed|void if property exist, value of the relevant property
  136. */
  137. public function __get($property)
  138. {
  139. if (array_key_exists($property, $this->_property_array)) {
  140. return $this->_property_array[$property];
  141. }
  142. }
  143. /**
  144. * Set values for any property of this class
  145. *
  146. * @param string $property name of the property
  147. * @param mixed $value value to set
  148. *
  149. * @return void
  150. */
  151. public function __set($property, $value)
  152. {
  153. if (array_key_exists($property, $this->_property_array)) {
  154. $this->_property_array[$property] = $value;
  155. }
  156. }
  157. /**
  158. * Constructor for PMA_DisplayResults class
  159. *
  160. * @param string $db the database name
  161. * @param string $table the table name
  162. * @param string $goto the URL to go back in case of errors
  163. * @param string $sql_query the SQL query
  164. *
  165. * @access public
  166. */
  167. public function __construct($db, $table, $goto, $sql_query)
  168. {
  169. $this->_setDefaultTransformations();
  170. $this->__set('db', $db);
  171. $this->__set('table', $table);
  172. $this->__set('goto', $goto);
  173. $this->__set('sql_query', $sql_query);
  174. $this->__set('unique_id', rand());
  175. }
  176. /**
  177. * Sets default transformations for some columns
  178. *
  179. * @return void
  180. */
  181. private function _setDefaultTransformations()
  182. {
  183. $json_highlighting_data = array(
  184. 'libraries/plugins/transformations/output/Text_Plain_Json.class.php',
  185. 'Text_Plain_Json',
  186. 'Text_Plain'
  187. );
  188. $sql_highlighting_data = array(
  189. 'libraries/plugins/transformations/output/Text_Plain_Sql.class.php',
  190. 'Text_Plain_Sql',
  191. 'Text_Plain'
  192. );
  193. $blob_sql_highlighting_data = array(
  194. 'libraries/plugins/transformations/output/Text_Octetstream_Sql.class.php',
  195. 'Text_Octetstream_Sql',
  196. 'Text_Octetstream'
  197. );
  198. $link_data = array(
  199. 'libraries/plugins/transformations/Text_Plain_Link.class.php',
  200. 'Text_Plain_Link',
  201. 'Text_Plain'
  202. );
  203. $this->transformation_info = array(
  204. 'information_schema' => array(
  205. 'events' => array(
  206. 'event_definition' => $sql_highlighting_data
  207. ),
  208. 'processlist' => array(
  209. 'info' => $sql_highlighting_data
  210. ),
  211. 'routines' => array(
  212. 'routine_definition' => $sql_highlighting_data
  213. ),
  214. 'triggers' => array(
  215. 'action_statement' => $sql_highlighting_data
  216. ),
  217. 'views' => array(
  218. 'view_definition' => $sql_highlighting_data
  219. )
  220. ),
  221. 'mysql' => array(
  222. 'event' => array(
  223. 'body' => $blob_sql_highlighting_data,
  224. 'body_utf8' => $blob_sql_highlighting_data
  225. ),
  226. 'general_log' => array(
  227. 'argument' => $sql_highlighting_data
  228. ),
  229. 'help_category' => array(
  230. 'url' => $link_data
  231. ),
  232. 'help_topic' => array(
  233. 'example' => $sql_highlighting_data,
  234. 'url' => $link_data
  235. ),
  236. 'proc' => array(
  237. 'param_list' => $blob_sql_highlighting_data,
  238. 'returns' => $blob_sql_highlighting_data,
  239. 'body' => $blob_sql_highlighting_data,
  240. 'body_utf8' => $blob_sql_highlighting_data
  241. ),
  242. 'slow_log' => array(
  243. 'sql_text' => $sql_highlighting_data
  244. )
  245. )
  246. );
  247. $cfgRelation = PMA_getRelationsParam();
  248. if ($cfgRelation['db']) {
  249. $this->transformation_info[$cfgRelation['db']] = array();
  250. $relDb = &$this->transformation_info[$cfgRelation['db']];
  251. if (! empty($cfgRelation['history'])) {
  252. $relDb[$cfgRelation['history']] = array(
  253. 'sqlquery' => $sql_highlighting_data
  254. );
  255. }
  256. if (! empty($cfgRelation['bookmark'])) {
  257. $relDb[$cfgRelation['bookmark']] = array(
  258. 'query' => $sql_highlighting_data
  259. );
  260. }
  261. if (! empty($cfgRelation['tracking'])) {
  262. $relDb[$cfgRelation['tracking']] = array(
  263. 'schema_sql' => $sql_highlighting_data,
  264. 'data_sql' => $sql_highlighting_data
  265. );
  266. }
  267. if (! empty($cfgRelation['favorite'])) {
  268. $relDb[$cfgRelation['favorite']] = array(
  269. 'tables' => $json_highlighting_data
  270. );
  271. }
  272. if (! empty($cfgRelation['recent'])) {
  273. $relDb[$cfgRelation['recent']] = array(
  274. 'tables' => $json_highlighting_data
  275. );
  276. }
  277. if (! empty($cfgRelation['savedsearches'])) {
  278. $relDb[$cfgRelation['savedsearches']] = array(
  279. 'search_data' => $json_highlighting_data
  280. );
  281. }
  282. if (! empty($cfgRelation['designer_settings'])) {
  283. $relDb[$cfgRelation['designer_settings']] = array(
  284. 'settings_data' => $json_highlighting_data
  285. );
  286. }
  287. if (! empty($cfgRelation['table_uiprefs'])) {
  288. $relDb[$cfgRelation['table_uiprefs']] = array(
  289. 'prefs' => $json_highlighting_data
  290. );
  291. }
  292. if (! empty($cfgRelation['userconfig'])) {
  293. $relDb[$cfgRelation['userconfig']] = array(
  294. 'config_data' => $json_highlighting_data
  295. );
  296. }
  297. if (! empty($cfgRelation['export_templates'])) {
  298. $relDb[$cfgRelation['export_templates']] = array(
  299. 'template_data' => $json_highlighting_data
  300. );
  301. }
  302. }
  303. }
  304. /**
  305. * Set properties which were not initialized at the constructor
  306. *
  307. * @param integer $unlim_num_rows the total number of rows returned by
  308. * the SQL query without any appended
  309. * "LIMIT" clause programmatically
  310. * @param array $fields_meta meta information about fields
  311. * @param boolean $is_count statement is SELECT COUNT
  312. * @param integer $is_export statement contains INTO OUTFILE
  313. * @param boolean $is_func statement contains a function like SUM()
  314. * @param integer $is_analyse statement contains PROCEDURE ANALYSE
  315. * @param integer $num_rows total no. of rows returned by SQL query
  316. * @param integer $fields_cnt total no.of fields returned by SQL query
  317. * @param double $querytime time taken for execute the SQL query
  318. * @param string $pmaThemeImage path for theme images directory
  319. * @param string $text_dir text direction
  320. * @param boolean $is_maint statement contains a maintenance command
  321. * @param boolean $is_explain statement contains EXPLAIN
  322. * @param boolean $is_show statement contains SHOW
  323. * @param array $showtable table definitions
  324. * @param string $printview print view was requested
  325. * @param string $url_query URL query
  326. * @param boolean $editable whether the results set is editable
  327. * @param boolean $is_browse_dist whether browsing distinct values
  328. *
  329. * @return void
  330. *
  331. * @see sql.php
  332. */
  333. public function setProperties(
  334. $unlim_num_rows, $fields_meta, $is_count, $is_export, $is_func,
  335. $is_analyse, $num_rows, $fields_cnt, $querytime, $pmaThemeImage, $text_dir,
  336. $is_maint, $is_explain, $is_show, $showtable, $printview, $url_query,
  337. $editable, $is_browse_dist
  338. ) {
  339. $this->__set('unlim_num_rows', $unlim_num_rows);
  340. $this->__set('fields_meta', $fields_meta);
  341. $this->__set('is_count', $is_count);
  342. $this->__set('is_export', $is_export);
  343. $this->__set('is_func', $is_func);
  344. $this->__set('is_analyse', $is_analyse);
  345. $this->__set('num_rows', $num_rows);
  346. $this->__set('fields_cnt', $fields_cnt);
  347. $this->__set('querytime', $querytime);
  348. $this->__set('pma_theme_image', $pmaThemeImage);
  349. $this->__set('text_dir', $text_dir);
  350. $this->__set('is_maint', $is_maint);
  351. $this->__set('is_explain', $is_explain);
  352. $this->__set('is_show', $is_show);
  353. $this->__set('showtable', $showtable);
  354. $this->__set('printview', $printview);
  355. $this->__set('url_query', $url_query);
  356. $this->__set('editable', $editable);
  357. $this->__set('is_browse_distinct', $is_browse_dist);
  358. } // end of the 'setProperties()' function
  359. /**
  360. * Defines the parts to display for a print view
  361. *
  362. * @param array $displayParts the parts to display
  363. *
  364. * @return array $displayParts the modified display parts
  365. *
  366. * @access private
  367. *
  368. */
  369. private function _setDisplayPartsForPrintView($displayParts)
  370. {
  371. // set all elements to false!
  372. $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link
  373. $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link
  374. $displayParts['sort_lnk'] = (string) '0';
  375. $displayParts['nav_bar'] = (string) '0';
  376. $displayParts['bkm_form'] = (string) '0';
  377. $displayParts['text_btn'] = (string) '0';
  378. $displayParts['pview_lnk'] = (string) '0';
  379. return $displayParts;
  380. }
  381. /**
  382. * Defines the parts to display for a SHOW statement
  383. *
  384. * @param array $displayParts the parts to display
  385. *
  386. * @return array $displayParts the modified display parts
  387. *
  388. * @access private
  389. *
  390. */
  391. private function _setDisplayPartsForShow($displayParts)
  392. {
  393. preg_match(
  394. '@^SHOW[[:space:]]+(VARIABLES|(FULL[[:space:]]+)?'
  395. . 'PROCESSLIST|STATUS|TABLE|GRANTS|CREATE|LOGS|DATABASES|FIELDS'
  396. . ')@i',
  397. $this->__get('sql_query'), $which
  398. );
  399. $bIsProcessList = isset($which[1]);
  400. if ($bIsProcessList) {
  401. $str = ' ' . strtoupper($which[1]);
  402. $bIsProcessList = $bIsProcessList
  403. && strpos($str, 'PROCESSLIST') > 0;
  404. }
  405. if ($bIsProcessList) {
  406. // no edit link
  407. $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE;
  408. // "kill process" type edit link
  409. $displayParts['del_lnk'] = self::KILL_PROCESS;
  410. } else {
  411. // Default case -> no links
  412. // no edit link
  413. $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE;
  414. // no delete link
  415. $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE;
  416. }
  417. // Other settings
  418. $displayParts['sort_lnk'] = (string) '0';
  419. $displayParts['nav_bar'] = (string) '0';
  420. $displayParts['bkm_form'] = (string) '1';
  421. $displayParts['text_btn'] = (string) '1';
  422. $displayParts['pview_lnk'] = (string) '1';
  423. return $displayParts;
  424. }
  425. /**
  426. * Defines the parts to display for statements not related to data
  427. *
  428. * @param array $displayParts the parts to display
  429. *
  430. * @return array $displayParts the modified display parts
  431. *
  432. * @access private
  433. *
  434. */
  435. private function _setDisplayPartsForNonData($displayParts)
  436. {
  437. // Statement is a "SELECT COUNT", a
  438. // "CHECK/ANALYZE/REPAIR/OPTIMIZE/CHECKSUM", an "EXPLAIN" one or
  439. // contains a "PROC ANALYSE" part
  440. $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE; // no edit link
  441. $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE; // no delete link
  442. $displayParts['sort_lnk'] = (string) '0';
  443. $displayParts['nav_bar'] = (string) '0';
  444. $displayParts['bkm_form'] = (string) '1';
  445. if ($this->__get('is_maint')) {
  446. $displayParts['text_btn'] = (string) '1';
  447. } else {
  448. $displayParts['text_btn'] = (string) '0';
  449. }
  450. $displayParts['pview_lnk'] = (string) '1';
  451. return $displayParts;
  452. }
  453. /**
  454. * Defines the parts to display for other statements (probably SELECT)
  455. *
  456. * @param array $displayParts the parts to display
  457. *
  458. * @return array $displayParts the modified display parts
  459. *
  460. * @access private
  461. *
  462. */
  463. private function _setDisplayPartsForSelect($displayParts)
  464. {
  465. // Other statements (ie "SELECT" ones) -> updates
  466. // $displayParts['edit_lnk'], $displayParts['del_lnk'] and
  467. // $displayParts['text_btn'] (keeps other default values)
  468. $fields_meta = $this->__get('fields_meta');
  469. $prev_table = '';
  470. $displayParts['text_btn'] = (string) '1';
  471. $number_of_columns = $this->__get('fields_cnt');
  472. for ($i = 0; $i < $number_of_columns; $i++) {
  473. $is_link = ($displayParts['edit_lnk'] != self::NO_EDIT_OR_DELETE)
  474. || ($displayParts['del_lnk'] != self::NO_EDIT_OR_DELETE)
  475. || ($displayParts['sort_lnk'] != '0');
  476. // Displays edit/delete/sort/insert links?
  477. if ($is_link
  478. && $prev_table != ''
  479. && $fields_meta[$i]->table != ''
  480. && $fields_meta[$i]->table != $prev_table
  481. ) {
  482. // don't display links
  483. $displayParts['edit_lnk'] = self::NO_EDIT_OR_DELETE;
  484. $displayParts['del_lnk'] = self::NO_EDIT_OR_DELETE;
  485. /**
  486. * @todo May be problematic with same field names
  487. * in two joined table.
  488. */
  489. // $displayParts['sort_lnk'] = (string) '0';
  490. if ($displayParts['text_btn'] == '1') {
  491. break;
  492. }
  493. } // end if
  494. // Always display print view link
  495. $displayParts['pview_lnk'] = (string) '1';
  496. if ($fields_meta[$i]->table != '') {
  497. $prev_table = $fields_meta[$i]->table;
  498. }
  499. } // end for
  500. return $displayParts;
  501. }
  502. /**
  503. * Defines the parts to display for the results of a SQL query
  504. *
  505. * @param array $displayParts the parts to display (see a few
  506. * lines above for explanations)
  507. * @param integer &$the_total the total number of rows returned by the SQL
  508. * query without any programmatically appended
  509. * LIMIT clause
  510. * (just a copy of $unlim_num_rows if it exists,
  511. * elsecomputed inside this function)
  512. *
  513. * @return array an array with explicit indexes for all the display
  514. * elements
  515. *
  516. * @access private
  517. *
  518. * @see getTable()
  519. */
  520. private function _setDisplayParts($displayParts, &$the_total)
  521. {
  522. // 1. Following variables are needed for use in isset/empty or
  523. // use with array indexes or safe use in foreach
  524. $db = $this->__get('db');
  525. $table = $this->__get('table');
  526. $unlim_num_rows = $this->__get('unlim_num_rows');
  527. $num_rows = $this->__get('num_rows');
  528. $printview = $this->__get('printview');
  529. // 2. Updates the display parts
  530. if ($printview == '1') {
  531. $displayParts = $this->_setDisplayPartsForPrintView($displayParts);
  532. } elseif ($this->__get('is_count') || $this->__get('is_analyse')
  533. || $this->__get('is_maint') || $this->__get('is_explain')
  534. ) {
  535. $displayParts = $this->_setDisplayPartsForNonData($displayParts);
  536. } elseif ($this->__get('is_show')) {
  537. $displayParts = $this->_setDisplayPartsForShow($displayParts);
  538. } else {
  539. $displayParts = $this->_setDisplayPartsForSelect($displayParts);
  540. } // end if..elseif...else
  541. // 3. Gets the total number of rows if it is unknown
  542. if (isset($unlim_num_rows) && $unlim_num_rows != '') {
  543. $the_total = $unlim_num_rows;
  544. } elseif ((($displayParts['nav_bar'] == '1')
  545. || ($displayParts['sort_lnk'] == '1'))
  546. && (/*overload*/mb_strlen($db) && !empty($table))
  547. ) {
  548. $the_total = $GLOBALS['dbi']->getTable($db, $table)->countRecords();
  549. }
  550. // if for COUNT query, number of rows returned more than 1
  551. // (may be being used GROUP BY)
  552. if ($this->__get('is_count') && isset($num_rows) && $num_rows > 1) {
  553. $displayParts['nav_bar'] = (string) '1';
  554. $displayParts['sort_lnk'] = (string) '1';
  555. }
  556. // 4. If navigation bar or sorting fields names URLs should be
  557. // displayed but there is only one row, change these settings to
  558. // false
  559. if ($displayParts['nav_bar'] == '1' || $displayParts['sort_lnk'] == '1') {
  560. // - Do not display sort links if less than 2 rows.
  561. // - For a VIEW we (probably) did not count the number of rows
  562. // so don't test this number here, it would remove the possibility
  563. // of sorting VIEW results.
  564. $_table = new PMA_Table($table, $db);
  565. if (isset($unlim_num_rows)
  566. && ($unlim_num_rows < 2)
  567. && ! $_table->isView()
  568. ) {
  569. $displayParts['sort_lnk'] = (string) '0';
  570. }
  571. } // end if (3)
  572. return $displayParts;
  573. } // end of the 'setDisplayParts()' function
  574. /**
  575. * Return true if we are executing a query in the form of
  576. * "SELECT * FROM <a table> ..."
  577. *
  578. * @param array $analyzed_sql_results analyzed sql results
  579. *
  580. * @return boolean
  581. *
  582. * @access private
  583. *
  584. * @see _getTableHeaders(), _getColumnParams()
  585. */
  586. private function _isSelect($analyzed_sql_results)
  587. {
  588. return ! ($this->__get('is_count')
  589. || $this->__get('is_export')
  590. || $this->__get('is_func')
  591. || $this->__get('is_analyse'))
  592. && !empty($analyzed_sql_results['select_from'])
  593. && !empty($analyzed_sql_results['statement']->from)
  594. && (count($analyzed_sql_results['statement']->from) == 1)
  595. && !empty($analyzed_sql_results['statement']->from[0]->table);
  596. }
  597. /**
  598. * Get a navigation button
  599. *
  600. * @param string $caption iconic caption for button
  601. * @param string $title text for button
  602. * @param integer $pos position for next query
  603. * @param string $html_sql_query query ready for display
  604. * @param boolean $back whether 'begin' or 'previous'
  605. * @param string $onsubmit optional onsubmit clause
  606. * @param string $input_for_real_end optional hidden field for special treatment
  607. * @param string $onclick optional onclick clause
  608. *
  609. * @return string html content
  610. *
  611. * @access private
  612. *
  613. * @see _getMoveBackwardButtonsForTableNavigation(),
  614. * _getMoveForwardButtonsForTableNavigation()
  615. */
  616. private function _getTableNavigationButton(
  617. $caption, $title, $pos, $html_sql_query, $back, $onsubmit = '',
  618. $input_for_real_end = '', $onclick = ''
  619. ) {
  620. $caption_output = '';
  621. if ($back) {
  622. if (PMA_Util::showIcons('TableNavigationLinksMode')) {
  623. $caption_output .= $caption;
  624. }
  625. if (PMA_Util::showText('TableNavigationLinksMode')) {
  626. $caption_output .= '&nbsp;' . $title;
  627. }
  628. } else {
  629. if (PMA_Util::showText('TableNavigationLinksMode')) {
  630. $caption_output .= $title;
  631. }
  632. if (PMA_Util::showIcons('TableNavigationLinksMode')) {
  633. $caption_output .= '&nbsp;' . $caption;
  634. }
  635. }
  636. $title_output = ' title="' . $title . '"';
  637. return '<td>'
  638. . '<form action="sql.php" method="post" ' . $onsubmit . '>'
  639. . PMA_URL_getHiddenInputs(
  640. $this->__get('db'), $this->__get('table')
  641. )
  642. . '<input type="hidden" name="sql_query" value="'
  643. . $html_sql_query . '" />'
  644. . '<input type="hidden" name="pos" value="' . $pos . '" />'
  645. . '<input type="hidden" name="is_browse_distinct" value="'
  646. . $this->__get('is_browse_distinct') . '" />'
  647. . '<input type="hidden" name="goto" value="' . $this->__get('goto')
  648. . '" />'
  649. . $input_for_real_end
  650. . '<input type="submit" name="navig"'
  651. . ' class="ajax" '
  652. . 'value="' . $caption_output . '" ' . $title_output . $onclick . ' />'
  653. . '</form>'
  654. . '</td>';
  655. } // end function _getTableNavigationButton()
  656. /**
  657. * Possibly return a page selector for table navigation
  658. *
  659. * @param string $table_navigation_html the current navigation HTML
  660. *
  661. * @return array ($table_navigation_html, $nbTotalPage)
  662. *
  663. * @access private
  664. *
  665. */
  666. private function _getHtmlPageSelector($table_navigation_html)
  667. {
  668. $pageNow = @floor(
  669. $_SESSION['tmpval']['pos']
  670. / $_SESSION['tmpval']['max_rows']
  671. ) + 1;
  672. $nbTotalPage = @ceil(
  673. $this->__get('unlim_num_rows')
  674. / $_SESSION['tmpval']['max_rows']
  675. );
  676. if ($nbTotalPage > 1) {
  677. $table_navigation_html .= '<td>';
  678. $_url_params = array(
  679. 'db' => $this->__get('db'),
  680. 'table' => $this->__get('table'),
  681. 'sql_query' => $this->__get('sql_query'),
  682. 'goto' => $this->__get('goto'),
  683. 'is_browse_distinct' => $this->__get('is_browse_distinct'),
  684. );
  685. //<form> to keep the form alignment of button < and <<
  686. // and also to know what to execute when the selector changes
  687. $table_navigation_html .= '<form action="sql.php'
  688. . PMA_URL_getCommon($_url_params)
  689. . '" method="post">';
  690. $table_navigation_html .= PMA_Util::pageselector(
  691. 'pos',
  692. $_SESSION['tmpval']['max_rows'],
  693. $pageNow, $nbTotalPage, 200, 5, 5, 20, 10
  694. );
  695. $table_navigation_html .= '</form>'
  696. . '</td>';
  697. }
  698. return array($table_navigation_html, $nbTotalPage);
  699. }
  700. /**
  701. * Get a navigation bar to browse among the results of a SQL query
  702. *
  703. * @param integer $pos_next the offset for the "next" page
  704. * @param integer $pos_prev the offset for the "previous" page
  705. * @param boolean $is_innodb whether its InnoDB or not
  706. *
  707. * @return string html content
  708. *
  709. * @access private
  710. *
  711. * @see _getTable()
  712. */
  713. private function _getTableNavigation(
  714. $pos_next, $pos_prev, $is_innodb
  715. ) {
  716. $table_navigation_html = '';
  717. // here, using htmlentities() would cause problems if the query
  718. // contains accented characters
  719. $html_sql_query = htmlspecialchars($this->__get('sql_query'));
  720. // Navigation bar
  721. $table_navigation_html .= '<table class="navigation nospacing nopadding print_ignore">'
  722. . '<tr>'
  723. . '<td class="navigation_separator"></td>';
  724. // Move to the beginning or to the previous page
  725. if ($_SESSION['tmpval']['pos']
  726. && ($_SESSION['tmpval']['max_rows'] != self::ALL_ROWS)
  727. ) {
  728. $table_navigation_html
  729. .= $this->_getMoveBackwardButtonsForTableNavigation(
  730. $html_sql_query, $pos_prev
  731. );
  732. } // end move back
  733. $nbTotalPage = 1;
  734. //page redirection
  735. // (unless we are showing all records)
  736. if ($_SESSION['tmpval']['max_rows'] != self::ALL_ROWS) {
  737. list(
  738. $table_navigation_html,
  739. $nbTotalPage
  740. ) = $this->_getHtmlPageSelector($table_navigation_html);
  741. }
  742. $showing_all = false;
  743. if ($_SESSION['tmpval']['max_rows'] == self::ALL_ROWS) {
  744. $showing_all = true;
  745. }
  746. // Move to the next page or to the last one
  747. $endpos = $_SESSION['tmpval']['pos']
  748. + $_SESSION['tmpval']['max_rows'];
  749. if (($endpos < $this->__get('unlim_num_rows'))
  750. && ($this->__get('num_rows') >= $_SESSION['tmpval']['max_rows'])
  751. && ($_SESSION['tmpval']['max_rows'] != self::ALL_ROWS)
  752. ) {
  753. $table_navigation_html
  754. .= $this->_getMoveForwardButtonsForTableNavigation(
  755. $html_sql_query, $pos_next, $is_innodb
  756. );
  757. } // end move toward
  758. // show separator if pagination happen
  759. if ($nbTotalPage > 1) {
  760. $table_navigation_html
  761. .= '<td><div class="navigation_separator">|</div></td>';
  762. }
  763. // Display the "Show all" button if allowed
  764. if ($GLOBALS['cfg']['ShowAll'] || ($this->__get('unlim_num_rows') <= 500) ) {
  765. $table_navigation_html .= $this->_getShowAllCheckboxForTableNavigation(
  766. $showing_all, $html_sql_query
  767. );
  768. $table_navigation_html
  769. .= '<td><div class="navigation_separator">|</div></td>';
  770. } // end show all
  771. $table_navigation_html .= '<td>'
  772. . '<div class="save_edited hide">'
  773. . '<input type="submit" value="' . __('Save edited data') . '" />'
  774. . '<div class="navigation_separator">|</div>'
  775. . '</div>'
  776. . '</td>'
  777. . '<td>'
  778. . '<div class="restore_column hide">'
  779. . '<input type="submit" value="' . __('Restore column order') . '" />'
  780. . '<div class="navigation_separator">|</div>'
  781. . '</div>'
  782. . '</td>';
  783. // if displaying a VIEW, $unlim_num_rows could be zero because
  784. // of $cfg['MaxExactCountViews']; in this case, avoid passing
  785. // the 5th parameter to checkFormElementInRange()
  786. // (this means we can't validate the upper limit
  787. $table_navigation_html .= '<td class="navigation_goto">';
  788. $table_navigation_html .= '<form action="sql.php" method="post" '
  789. . 'onsubmit="return '
  790. . '(checkFormElementInRange('
  791. . 'this, '
  792. . '\'session_max_rows\', '
  793. . '\''
  794. . str_replace('\'', '\\\'', __('%d is not valid row number.'))
  795. . '\', '
  796. . '1)'
  797. . ' &amp;&amp; '
  798. . 'checkFormElementInRange('
  799. . 'this, '
  800. . '\'pos\', '
  801. . '\''
  802. . str_replace('\'', '\\\'', __('%d is not valid row number.'))
  803. . '\', '
  804. . '0'
  805. . (($this->__get('unlim_num_rows') > 0)
  806. ? ', ' . ($this->__get('unlim_num_rows') - 1)
  807. : ''
  808. )
  809. . ')'
  810. . ')'
  811. . '">';
  812. $table_navigation_html .= PMA_URL_getHiddenInputs(
  813. $this->__get('db'), $this->__get('table')
  814. );
  815. $table_navigation_html .= $this->_getAdditionalFieldsForTableNavigation(
  816. $html_sql_query
  817. );
  818. $table_navigation_html .= '</form>'
  819. . '</td>'
  820. . '<td class="navigation_separator"></td>'
  821. . '<td>'
  822. . '<span>' . __('Filter rows') . ':</span>'
  823. . '<input type="text" class="filter_rows"'
  824. . ' placeholder="' . __('Search this table') . '"'
  825. . ' data-for="' . $this->__get('unique_id') . '" />'
  826. . '</td>'
  827. . '<td class="navigation_separator"></td>'
  828. . '</tr>'
  829. . '</table>';
  830. return $table_navigation_html;
  831. } // end of the '_getTableNavigation()' function
  832. /**
  833. * Prepare move backward buttons - previous and first
  834. *
  835. * @param string $html_sql_query the sql encoded by html special characters
  836. * @param integer $pos_prev the offset for the "previous" page
  837. *
  838. * @return string html content
  839. *
  840. * @access private
  841. *
  842. * @see _getTableNavigation()
  843. */
  844. private function _getMoveBackwardButtonsForTableNavigation(
  845. $html_sql_query, $pos_prev
  846. ) {
  847. return $this->_getTableNavigationButton(
  848. '&lt;&lt;', _pgettext('First page', 'Begin'), 0, $html_sql_query, true
  849. )
  850. . $this->_getTableNavigationButton(
  851. '&lt;', _pgettext('Previous page', 'Previous'), $pos_prev,
  852. $html_sql_query, true
  853. );
  854. } // end of the '_getMoveBackwardButtonsForTableNavigation()' function
  855. /**
  856. * Prepare Show All checkbox for table navigation
  857. *
  858. * @param bool $showing_all whether all rows are shown currently
  859. * @param string $html_sql_query the sql encoded by html special characters
  860. *
  861. * @return string html content
  862. *
  863. * @access private
  864. *
  865. * @see _getTableNavigation()
  866. */
  867. private function _getShowAllCheckboxForTableNavigation(
  868. $showing_all, $html_sql_query
  869. ) {
  870. return "\n"
  871. . '<td>'
  872. . '<form action="sql.php" method="post">'
  873. . PMA_URL_getHiddenInputs(
  874. $this->__get('db'), $this->__get('table')
  875. )
  876. . '<input type="hidden" name="sql_query" value="'
  877. . $html_sql_query . '" />'
  878. . '<input type="hidden" name="pos" value="0" />'
  879. . '<input type="hidden" name="is_browse_distinct" value="'
  880. . $this->__get('is_browse_distinct') . '" />'
  881. . '<input type="hidden" name="session_max_rows" value="'
  882. . (! $showing_all ? 'all' : $GLOBALS['cfg']['MaxRows']) . '" />'
  883. . '<input type="hidden" name="goto" value="' . $this->__get('goto')
  884. . '" />'
  885. . '<input type="checkbox" name="navig"'
  886. . ' id="showAll_' . $this->__get('unique_id') . '" class="showAllRows"'
  887. . (! $showing_all ? '' : ' checked="checked"') . ' value="all" />'
  888. . '<label for="showAll_' . $this->__get('unique_id') . '">'
  889. . __('Show all') . '</label>'
  890. . '</form>'
  891. . '</td>';
  892. } // end of the '_getShowAllButtonForTableNavigation()' function
  893. /**
  894. * Prepare move forward buttons - next and last
  895. *
  896. * @param string $html_sql_query the sql encoded by htmlspecialchars()
  897. * @param integer $pos_next the offset for the "next" page
  898. * @param boolean $is_innodb whether it's InnoDB or not
  899. *
  900. * @return string $buttons_html html content
  901. *
  902. * @access private
  903. *
  904. * @see _getTableNavigation()
  905. */
  906. private function _getMoveForwardButtonsForTableNavigation(
  907. $html_sql_query, $pos_next, $is_innodb
  908. ) {
  909. // display the Next button
  910. $buttons_html = $this->_getTableNavigationButton(
  911. '&gt;',
  912. _pgettext('Next page', 'Next'),
  913. $pos_next,
  914. $html_sql_query,
  915. false
  916. );
  917. // prepare some options for the End button
  918. if ($is_innodb
  919. && $this->__get('unlim_num_rows') > $GLOBALS['cfg']['MaxExactCount']
  920. ) {
  921. $input_for_real_end = '<input id="real_end_input" type="hidden" '
  922. . 'name="find_real_end" value="1" />';
  923. // no backquote around this message
  924. $onclick = '';
  925. } else {
  926. $input_for_real_end = $onclick = '';
  927. }
  928. $maxRows = $_SESSION['tmpval']['max_rows'];
  929. $onsubmit = 'onsubmit="return '
  930. . ($_SESSION['tmpval']['pos']
  931. + $maxRows
  932. < $this->__get('unlim_num_rows')
  933. && $this->__get('num_rows') >= $maxRows)
  934. ? 'true'
  935. : 'false' . '"';
  936. // display the End button
  937. $buttons_html .= $this->_getTableNavigationButton(
  938. '&gt;&gt;',
  939. _pgettext('Last page', 'End'),
  940. @((ceil(
  941. $this->__get('unlim_num_rows')
  942. / $_SESSION['tmpval']['max_rows']
  943. )- 1) * $maxRows),
  944. $html_sql_query, false, $onsubmit, $input_for_real_end, $onclick
  945. );
  946. return $buttons_html;
  947. } // end of the '_getMoveForwardButtonsForTableNavigation()' function
  948. /**
  949. * Prepare fields for table navigation
  950. * Number of rows
  951. *
  952. * @param string $html_sql_query the sql encoded by htmlspecialchars()
  953. *
  954. * @return string $additional_fields_html html content
  955. *
  956. * @access private
  957. *
  958. * @see _getTableNavigation()
  959. */
  960. private function _getAdditionalFieldsForTableNavigation(
  961. $html_sql_query
  962. ) {
  963. $additional_fields_html = '';
  964. $additional_fields_html .= '<input type="hidden" name="sql_query" '
  965. . 'value="' . $html_sql_query . '" />'
  966. . '<input type="hidden" name="goto" value="' . $this->__get('goto')
  967. . '" />'
  968. . '<input type="hidden" name="pos" size="3" value="'
  969. // Do not change the position when changing the number of rows
  970. . $_SESSION['tmpval']['pos'] . '" />'
  971. . '<input type="hidden" name="is_browse_distinct" value="'
  972. . $this->__get('is_browse_distinct') . '" />' ;
  973. $numberOfRowsPlaceholder = null;
  974. if ($_SESSION['tmpval']['max_rows'] == self::ALL_ROWS) {
  975. $numberOfRowsPlaceholder = __('All');
  976. }
  977. $numberOfRowsChoices = array(
  978. '25' => 25,
  979. '50' => 50,
  980. '100' => 100,
  981. '250' => 250,
  982. '500' => 500
  983. );
  984. $additional_fields_html .= __('Number of rows:') . ' ';
  985. $additional_fields_html .= PMA_Util::getDropdown(
  986. 'session_max_rows', $numberOfRowsChoices,
  987. $_SESSION['tmpval']['max_rows'], '',
  988. 'autosubmit', $numberOfRowsPlaceholder
  989. );
  990. return $additional_fields_html;
  991. } // end of the '_getAdditionalFieldsForTableNavigation()' function
  992. /**
  993. * Get the headers of the results table, for all of the columns
  994. *
  995. * @param array $displayParts which elements to display
  996. * @param array $analyzed_sql_results analyzed sql results
  997. * @param array $sort_expression sort expression
  998. * @param string $sort_expression_nodirection sort expression
  999. * without direction
  1000. * @param string $sort_direction sort direction
  1001. * @param boolean $is_limited_display with limited operations
  1002. * or not
  1003. * @param string $unsorted_sql_query query without the sort part
  1004. *
  1005. * @return string html content
  1006. *
  1007. * @access private
  1008. *
  1009. * @see getTableHeaders()
  1010. */
  1011. private function _getTableHeadersForColumns(
  1012. $displayParts, $analyzed_sql_results, $sort_expression,
  1013. $sort_expression_nodirection, $sort_direction, $is_limited_display,
  1014. $unsorted_sql_query
  1015. ) {
  1016. $html = '';
  1017. // required to generate sort links that will remember whether the
  1018. // "Show all" button has been clicked
  1019. $sql_md5 = md5($this->__get('sql_query'));
  1020. $session_max_rows = $is_limited_display
  1021. ? 0
  1022. : $_SESSION['tmpval']['query'][$sql_md5]['max_rows'];
  1023. // Following variable are needed for use in isset/empty or
  1024. // use with array indexes/safe use in the for loop
  1025. $highlight_columns = $this->__get('highlight_columns');
  1026. $fields_meta = $this->__get('fields_meta');
  1027. // Prepare Display column comments if enabled
  1028. // ($GLOBALS['cfg']['ShowBrowseComments']).
  1029. $comments_map = $this->_getTableCommentsArray($analyzed_sql_results);
  1030. list($col_order, $col_visib) = $this->_getColumnParams($analyzed_sql_results);
  1031. // optimize: avoid calling a method on each iteration
  1032. $number_of_columns = $this->__get('fields_cnt');
  1033. for ($j = 0; $j < $number_of_columns; $j++) {
  1034. // assign $i with the appropriate column order
  1035. $i = $col_order ? $col_order[$j] : $j;
  1036. // See if this column should get highlight because it's used in the
  1037. // where-query.
  1038. $condition_field = (isset($highlight_columns[$fields_meta[$i]->name])
  1039. || isset(
  1040. $highlight_columns[PMA_Util::backquote($fields_meta[$i]->name)])
  1041. )
  1042. ? true
  1043. : false;
  1044. // Prepare comment-HTML-wrappers for each row, if defined/enabled.
  1045. $comments = $this->_getCommentForRow($comments_map, $fields_meta[$i]);
  1046. $display_params = $this->__get('display_params');
  1047. if (($displayParts['sort_lnk'] == '1') && ! $is_limited_display) {
  1048. list($order_link, $sorted_header_html)
  1049. = $this->_getOrderLinkAndSortedHeaderHtml(
  1050. $fields_meta[$i], $sort_expression,
  1051. $sort_expression_nodirection, $i, $unsorted_sql_query,
  1052. $session_max_rows, $comments,
  1053. $sort_direction, $col_visib,
  1054. $col_visib[$j]
  1055. );
  1056. $html .= $sorted_header_html;
  1057. $display_params['desc'][] = ' <th '
  1058. . 'class="draggable'
  1059. . ($condition_field ? ' condition' : '')
  1060. . '" data-column="' . htmlspecialchars($fields_meta[$i]->name)
  1061. . '">' . "\n" . $order_link . $comments . ' </th>' . "\n";
  1062. } else {
  1063. // Results can't be sorted
  1064. $html
  1065. .= $this->_getDraggableClassForNonSortableColumns(
  1066. $col_visib, $col_visib[$j], $condition_field,
  1067. $fields_meta[$i], $comments
  1068. );
  1069. $display_params['desc'][] = ' <th '
  1070. . 'class="draggable'
  1071. . ($condition_field ? ' condition"' : '')
  1072. . '" data-column="' . htmlspecialchars($fields_meta[$i]->name)
  1073. . '">' . ' '
  1074. . htmlspecialchars($fields_meta[$i]->name)
  1075. . $comments . ' </th>';
  1076. } // end else
  1077. $this->__set('display_params', $display_params);
  1078. } // end for
  1079. return $html;
  1080. }
  1081. /**
  1082. * Get the headers of the results table
  1083. *
  1084. * @param array &$displayParts which elements to display
  1085. * @param array $analyzed_sql_results analyzed sql results
  1086. * @param array $sort_expression sort expression
  1087. * @param string $sort_expression_nodirection sort expression
  1088. * without direction
  1089. * @param string $sort_direction sort direction
  1090. * @param boolean $is_limited_display with limited operations
  1091. * or not
  1092. *
  1093. * @return string html content
  1094. *
  1095. * @access private
  1096. *
  1097. * @see getTable()
  1098. */
  1099. private function _getTableHeaders(
  1100. &$displayParts, $analyzed_sql_results, $sort_expression = array(),
  1101. $sort_expression_nodirection = '', $sort_direction = '',
  1102. $is_limited_display = false
  1103. ) {
  1104. $table_headers_html = '';
  1105. // Needed for use in isset/empty or
  1106. // use with array indexes/safe use in foreach
  1107. $printview = $this->__get('printview');
  1108. $display_params = $this->__get('display_params');
  1109. // can the result be sorted?
  1110. if ($displayParts['sort_lnk'] == '1') {
  1111. // At this point, $sort_expression is an array but we only verify
  1112. // the first element in case we could find that the table is
  1113. // sorted by one of the choices listed in the
  1114. // "Sort by key" drop-down
  1115. list($unsorted_sql_query, $drop_down_html)
  1116. = $this->_getUnsortedSqlAndSortByKeyDropDown(
  1117. $analyzed_sql_results, $sort_expression[0]
  1118. );
  1119. $table_headers_html .= $drop_down_html;
  1120. } else {
  1121. $unsorted_sql_query = '';
  1122. }
  1123. // Output data needed for grid editing
  1124. $table_headers_html .= '<input class="save_cells_at_once" type="hidden"'
  1125. . ' value="' . $GLOBALS['cfg']['SaveCellsAtOnce'] . '" />'
  1126. . '<div class="common_hidden_inputs">'
  1127. . PMA_URL_getHiddenInputs(
  1128. $this->__get('db'), $this->__get('table')
  1129. )
  1130. . '</div>';
  1131. // Output data needed for column reordering and show/hide column
  1132. if ($this->_isSelect($analyzed_sql_results)) {
  1133. $table_headers_html .= $this->_getDataForResettingColumnOrder();
  1134. }
  1135. $display_params['emptypre'] = 0;
  1136. $display_params['emptyafter'] = 0;
  1137. $display_params['textbtn'] = '';
  1138. $full_or_partial_text_link = null;
  1139. $this->__set('display_params', $display_params);
  1140. // Display options (if we are not in print view)
  1141. if (! (isset($printview) && ($printview == '1')) && ! $is_limited_display) {
  1142. $table_headers_html .= $this->_getOptionsBlock();
  1143. // prepare full/partial text button or link
  1144. $full_or_partial_text_link = $this->_getFullOrPartialTextButtonOrLink();
  1145. }
  1146. // Start of form for multi-rows edit/delete/export
  1147. $table_headers_html .= $this->_getFormForMultiRowOperations(
  1148. $displayParts['del_lnk']
  1149. );
  1150. // 1. Set $colspan and generate html with full/partial
  1151. // text button or link
  1152. list($colspan, $button_html)
  1153. = $this->_getFieldVisibilityParams(
  1154. $displayParts, $full_or_partial_text_link
  1155. );
  1156. $table_headers_html .= $button_html;
  1157. // 2. Displays the fields' name
  1158. // 2.0 If sorting links should be used, checks if the query is a "JOIN"
  1159. // statement (see 2.1.3)
  1160. // See if we have to highlight any header fields of a WHERE query.
  1161. // Uses SQL-Parser results.
  1162. $this->_setHighlightedColumnGlobalField($analyzed_sql_results);
  1163. // Get the headers for all of the columns
  1164. $table_headers_html .= $this->_getTableHeadersForColumns(
  1165. $displayParts, $analyzed_sql_results, $sort_expression,
  1166. $sort_expression_nodirection, $sort_direction,
  1167. $is_limited_display, $unsorted_sql_query
  1168. );
  1169. // Display column at rightside - checkboxes or empty column
  1170. if (! $printview) {
  1171. $table_headers_html .= $this->_getColumnAtRightSide(
  1172. $displayParts, $full_or_partial_text_link, $colspan
  1173. );
  1174. }
  1175. $table_headers_html .= '</tr>' . '</thead>';
  1176. return $table_headers_html;
  1177. } // end of the '_getTableHeaders()' function
  1178. /**
  1179. * Prepare unsorted sql query and sort by key drop down
  1180. *
  1181. * @param array $analyzed_sql_results analyzed sql results
  1182. * @param string $sort_expression sort expression
  1183. *
  1184. * @return array two element array - $unsorted_sql_query, $drop_down_html
  1185. *
  1186. * @access private
  1187. *
  1188. * @see _getTableHeaders()
  1189. */
  1190. private function _getUnsortedSqlAndSortByKeyDropDown(
  1191. $analyzed_sql_results, $sort_expression
  1192. ) {
  1193. $drop_down_html = '';
  1194. $unsorted_sql_query = SqlParser\Utils\Query::replaceClause(
  1195. $analyzed_sql_results['statement'],
  1196. $analyzed_sql_results['parser']->list,
  1197. 'ORDER BY',
  1198. ''
  1199. );
  1200. // Data is sorted by indexes only if it there is only one table.
  1201. if ($this->_isSelect($analyzed_sql_results)) {
  1202. // grab indexes data:
  1203. $indexes = PMA_Index::getFromTable(
  1204. $this->__get('table'),
  1205. $this->__get('db')
  1206. );
  1207. // do we have any index?
  1208. if (! empty($indexes)) {
  1209. $drop_down_html = $this->_getSortByKeyDropDown(
  1210. $indexes, $sort_expression,
  1211. $unsorted_sql_query
  1212. );
  1213. }
  1214. }
  1215. return array($uns

Large files files are truncated, but you can click here to view the full file