DBQbe.class.php 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Handles DB QBE search
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. if (! defined('PHPMYADMIN')) {
  9. exit;
  10. }
  11. /**
  12. * Class to handle database QBE search
  13. *
  14. * @package PhpMyAdmin
  15. */
  16. class PMA_DbQbe
  17. {
  18. /**
  19. * Database name
  20. *
  21. * @access private
  22. * @var string
  23. */
  24. private $_db;
  25. /**
  26. * Table Names (selected/non-selected)
  27. *
  28. * @access private
  29. * @var array
  30. */
  31. private $_criteriaTables;
  32. /**
  33. * Column Names
  34. *
  35. * @access private
  36. * @var array
  37. */
  38. private $_columnNames;
  39. /**
  40. * Number of columns
  41. *
  42. * @access private
  43. * @var integer
  44. */
  45. private $_criteria_column_count;
  46. /**
  47. * Number of Rows
  48. *
  49. * @access private
  50. * @var integer
  51. */
  52. private $_criteria_row_count;
  53. /**
  54. * Whether to insert a new column
  55. *
  56. * @access private
  57. * @var array
  58. */
  59. private $_criteriaColumnInsert;
  60. /**
  61. * Whether to delete a column
  62. *
  63. * @access private
  64. * @var array
  65. */
  66. private $_criteriaColumnDelete;
  67. /**
  68. * Whether to insert a new row
  69. *
  70. * @access private
  71. * @var array
  72. */
  73. private $_criteriaRowInsert;
  74. /**
  75. * Whether to delete a row
  76. *
  77. * @access private
  78. * @var array
  79. */
  80. private $_criteriaRowDelete;
  81. /**
  82. * Already set criteria values
  83. *
  84. * @access private
  85. * @var array
  86. */
  87. private $_criteria;
  88. /**
  89. * Previously set criteria values
  90. *
  91. * @access private
  92. * @var array
  93. */
  94. private $_prev_criteria;
  95. /**
  96. * AND/OR relation b/w criteria columns
  97. *
  98. * @access private
  99. * @var array
  100. */
  101. private $_criteriaAndOrColumn;
  102. /**
  103. * AND/OR relation b/w criteria rows
  104. *
  105. * @access private
  106. * @var array
  107. */
  108. private $_criteriaAndOrRow;
  109. /**
  110. * Larget width of a column
  111. *
  112. * @access private
  113. * @var string
  114. */
  115. private $_realwidth;
  116. /**
  117. * Minimum width of a column
  118. *
  119. * @access private
  120. * @var int
  121. */
  122. private $_form_column_width;
  123. /**
  124. * Current criteria field
  125. *
  126. * @access private
  127. * @var array
  128. */
  129. private $_curField;
  130. /**
  131. * Current criteria Sort options
  132. *
  133. * @access private
  134. * @var array
  135. */
  136. private $_curSort;
  137. /**
  138. * Current criteria Show options
  139. *
  140. * @access private
  141. * @var array
  142. */
  143. private $_curShow;
  144. /**
  145. * Current criteria values
  146. *
  147. * @access private
  148. * @var array
  149. */
  150. private $_curCriteria;
  151. /**
  152. * Current criteria AND/OR column relations
  153. *
  154. * @access private
  155. * @var array
  156. */
  157. private $_curAndOrCol;
  158. /**
  159. * Current criteria AND/OR row relations
  160. *
  161. * @access private
  162. * @var array
  163. */
  164. private $_curAndOrRow;
  165. /**
  166. * New column count in case of add/delete
  167. *
  168. * @access private
  169. * @var integer
  170. */
  171. private $_new_column_count;
  172. /**
  173. * New row count in case of add/delete
  174. *
  175. * @access private
  176. * @var integer
  177. */
  178. private $_new_row_count;
  179. /**
  180. * List of saved searches
  181. *
  182. * @access private
  183. * @var array
  184. */
  185. private $_savedSearchList = null;
  186. /**
  187. * Current search
  188. *
  189. * @access private
  190. * @var PMA_SavedSearches
  191. */
  192. private $_currentSearch = null;
  193. /**
  194. * Initialize criterias
  195. *
  196. * @return static
  197. */
  198. private function _loadCriterias()
  199. {
  200. if (null === $this->_currentSearch
  201. || null === $this->_currentSearch->getCriterias()
  202. ) {
  203. return $this;
  204. }
  205. $criterias = $this->_currentSearch->getCriterias();
  206. $_REQUEST = $criterias + $_REQUEST;
  207. return $this;
  208. }
  209. /**
  210. * Getter for current search
  211. *
  212. * @return PMA_SavedSearches
  213. */
  214. private function _getCurrentSearch()
  215. {
  216. return $this->_currentSearch;
  217. }
  218. /**
  219. * Public Constructor
  220. *
  221. * @param string $dbname Database name
  222. * @param array $savedSearchList List of saved searches
  223. * @param PMA_SavedSearches $currentSearch Current search id
  224. */
  225. public function __construct(
  226. $dbname, $savedSearchList = array(), $currentSearch = null
  227. ) {
  228. $this->_db = $dbname;
  229. $this->_savedSearchList = $savedSearchList;
  230. $this->_currentSearch = $currentSearch;
  231. $this->_loadCriterias();
  232. // Sets criteria parameters
  233. $this->_setSearchParams();
  234. $this->_setCriteriaTablesAndColumns();
  235. }
  236. /**
  237. * Sets search parameters
  238. *
  239. * @return void
  240. */
  241. private function _setSearchParams()
  242. {
  243. $criteriaColumnCount = $this->_initializeCriteriasCount();
  244. $this->_criteriaColumnInsert = PMA_ifSetOr(
  245. $_REQUEST['criteriaColumnInsert'],
  246. null,
  247. 'array'
  248. );
  249. $this->_criteriaColumnDelete = PMA_ifSetOr(
  250. $_REQUEST['criteriaColumnDelete'],
  251. null,
  252. 'array'
  253. );
  254. $this->_prev_criteria = isset($_REQUEST['prev_criteria'])
  255. ? $_REQUEST['prev_criteria']
  256. : array();
  257. $this->_criteria = isset($_REQUEST['criteria'])
  258. ? $_REQUEST['criteria']
  259. : array_fill(0, $criteriaColumnCount, '');
  260. $this->_criteriaRowInsert = isset($_REQUEST['criteriaRowInsert'])
  261. ? $_REQUEST['criteriaRowInsert']
  262. : array_fill(0, $criteriaColumnCount, '');
  263. $this->_criteriaRowDelete = isset($_REQUEST['criteriaRowDelete'])
  264. ? $_REQUEST['criteriaRowDelete']
  265. : array_fill(0, $criteriaColumnCount, '');
  266. $this->_criteriaAndOrRow = isset($_REQUEST['criteriaAndOrRow'])
  267. ? $_REQUEST['criteriaAndOrRow']
  268. : array_fill(0, $criteriaColumnCount, '');
  269. $this->_criteriaAndOrColumn = isset($_REQUEST['criteriaAndOrColumn'])
  270. ? $_REQUEST['criteriaAndOrColumn']
  271. : array_fill(0, $criteriaColumnCount, '');
  272. // sets minimum width
  273. $this->_form_column_width = 12;
  274. $this->_curField = array();
  275. $this->_curSort = array();
  276. $this->_curShow = array();
  277. $this->_curCriteria = array();
  278. $this->_curAndOrRow = array();
  279. $this->_curAndOrCol = array();
  280. }
  281. /**
  282. * Sets criteria tables and columns
  283. *
  284. * @return void
  285. */
  286. private function _setCriteriaTablesAndColumns()
  287. {
  288. // The tables list sent by a previously submitted form
  289. if (PMA_isValid($_REQUEST['TableList'], 'array')) {
  290. foreach ($_REQUEST['TableList'] as $each_table) {
  291. $this->_criteriaTables[$each_table] = ' selected="selected"';
  292. }
  293. } // end if
  294. $all_tables = $GLOBALS['dbi']->query(
  295. 'SHOW TABLES FROM ' . PMA_Util::backquote($this->_db) . ';',
  296. null,
  297. PMA_DatabaseInterface::QUERY_STORE
  298. );
  299. $all_tables_count = $GLOBALS['dbi']->numRows($all_tables);
  300. if (0 == $all_tables_count) {
  301. PMA_Message::error(__('No tables found in database.'))->display();
  302. exit;
  303. }
  304. // The tables list gets from MySQL
  305. while (list($table) = $GLOBALS['dbi']->fetchRow($all_tables)) {
  306. $columns = $GLOBALS['dbi']->getColumns($this->_db, $table);
  307. if (empty($this->_criteriaTables[$table])
  308. && ! empty($_REQUEST['TableList'])
  309. ) {
  310. $this->_criteriaTables[$table] = '';
  311. } else {
  312. $this->_criteriaTables[$table] = ' selected="selected"';
  313. } // end if
  314. // The fields list per selected tables
  315. if ($this->_criteriaTables[$table] == ' selected="selected"') {
  316. $each_table = PMA_Util::backquote($table);
  317. $this->_columnNames[] = $each_table . '.*';
  318. foreach ($columns as $each_column) {
  319. $each_column = $each_table . '.'
  320. . PMA_Util::backquote($each_column['Field']);
  321. $this->_columnNames[] = $each_column;
  322. // increase the width if necessary
  323. $this->_form_column_width = max(
  324. strlen($each_column),
  325. $this->_form_column_width
  326. );
  327. } // end foreach
  328. } // end if
  329. } // end while
  330. $GLOBALS['dbi']->freeResult($all_tables);
  331. // sets the largest width found
  332. $this->_realwidth = $this->_form_column_width . 'ex';
  333. }
  334. /**
  335. * Provides select options list containing column names
  336. *
  337. * @param integer $column_number Column Number (0,1,2) or more
  338. * @param string $selected Selected criteria column name
  339. *
  340. * @return string HTML for select options
  341. */
  342. private function _showColumnSelectCell($column_number, $selected = '')
  343. {
  344. $html_output = '';
  345. $html_output .= '<td class="center">';
  346. $html_output .= '<select name="criteriaColumn[' . $column_number
  347. . ']" size="1">';
  348. $html_output .= '<option value="">&nbsp;</option>';
  349. foreach ($this->_columnNames as $column) {
  350. $html_output .= '<option value="' . htmlspecialchars($column) . '"'
  351. . (($column === $selected) ? ' selected="selected"' : '') . '>'
  352. . str_replace(' ', '&nbsp;', htmlspecialchars($column))
  353. . '</option>';
  354. }
  355. $html_output .= '</select>';
  356. $html_output .= '</td>';
  357. return $html_output;
  358. }
  359. /**
  360. * Provides select options list containing sort options (ASC/DESC)
  361. *
  362. * @param integer $column_number Column Number (0,1,2) or more
  363. * @param string $asc_selected Selected criteria 'Ascending'
  364. * @param string $desc_selected Selected criteria 'Descending'
  365. *
  366. * @return string HTML for select options
  367. */
  368. private function _getSortSelectCell($column_number, $asc_selected = '',
  369. $desc_selected = ''
  370. ) {
  371. $html_output = '<td class="center">';
  372. $html_output .= '<select style="width: ' . $this->_realwidth
  373. . '" name="criteriaSort[' . $column_number . ']" size="1">';
  374. $html_output .= '<option value="">&nbsp;</option>';
  375. $html_output .= '<option value="ASC"' . $asc_selected . '>'
  376. . __('Ascending')
  377. . '</option>';
  378. $html_output .= '<option value="DESC"' . $desc_selected . '>'
  379. . __('Descending')
  380. . '</option>';
  381. $html_output .= '</select>';
  382. $html_output .= '</td>';
  383. return $html_output;
  384. }
  385. /**
  386. * Provides search form's row containing column select options
  387. *
  388. * @return string HTML for search table's row
  389. */
  390. private function _getColumnNamesRow()
  391. {
  392. $html_output = '<tr class="odd noclick">';
  393. $html_output .= '<th>' . __('Column:') . '</th>';
  394. $new_column_count = 0;
  395. for (
  396. $column_index = 0;
  397. $column_index < $this->_criteria_column_count;
  398. $column_index++
  399. ) {
  400. if (isset($this->_criteriaColumnInsert[$column_index])
  401. && $this->_criteriaColumnInsert[$column_index] == 'on'
  402. ) {
  403. $html_output .= $this->_showColumnSelectCell(
  404. $new_column_count
  405. );
  406. $new_column_count++;
  407. }
  408. if (! empty($this->_criteriaColumnDelete)
  409. && isset($this->_criteriaColumnDelete[$column_index])
  410. && $this->_criteriaColumnDelete[$column_index] == 'on'
  411. ) {
  412. continue;
  413. }
  414. $selected = '';
  415. if (isset($_REQUEST['criteriaColumn'][$column_index])) {
  416. $selected = $_REQUEST['criteriaColumn'][$column_index];
  417. $this->_curField[$new_column_count]
  418. = $_REQUEST['criteriaColumn'][$column_index];
  419. }
  420. $html_output .= $this->_showColumnSelectCell(
  421. $new_column_count,
  422. $selected
  423. );
  424. $new_column_count++;
  425. } // end for
  426. $this->_new_column_count = $new_column_count;
  427. $html_output .= '</tr>';
  428. return $html_output;
  429. }
  430. /**
  431. * Provides search form's row containing sort(ASC/DESC) select options
  432. *
  433. * @return string HTML for search table's row
  434. */
  435. private function _getSortRow()
  436. {
  437. $html_output = '<tr class="even noclick">';
  438. $html_output .= '<th>' . __('Sort:') . '</th>';
  439. $new_column_count = 0;
  440. for (
  441. $column_index = 0;
  442. $column_index < $this->_criteria_column_count;
  443. $column_index++
  444. ) {
  445. if (! empty($this->_criteriaColumnInsert)
  446. && isset($this->_criteriaColumnInsert[$column_index])
  447. && $this->_criteriaColumnInsert[$column_index] == 'on'
  448. ) {
  449. $html_output .= $this->_getSortSelectCell($new_column_count);
  450. $new_column_count++;
  451. } // end if
  452. if (! empty($this->_criteriaColumnDelete)
  453. && isset($this->_criteriaColumnDelete[$column_index])
  454. && $this->_criteriaColumnDelete[$column_index] == 'on'
  455. ) {
  456. continue;
  457. }
  458. // If they have chosen all fields using the * selector,
  459. // then sorting is not available, Fix for Bug #570698
  460. if (isset($_REQUEST['criteriaSort'][$column_index])
  461. && isset($_REQUEST['criteriaColumn'][$column_index])
  462. && substr($_REQUEST['criteriaColumn'][$column_index], -2) == '.*'
  463. ) {
  464. $_REQUEST['criteriaSort'][$column_index] = '';
  465. } //end if
  466. // Set asc_selected
  467. if (isset($_REQUEST['criteriaSort'][$column_index])
  468. && $_REQUEST['criteriaSort'][$column_index] == 'ASC'
  469. ) {
  470. $this->_curSort[$new_column_count]
  471. = $_REQUEST['criteriaSort'][$column_index];
  472. $asc_selected = ' selected="selected"';
  473. } else {
  474. $asc_selected = '';
  475. } // end if
  476. // Set desc selected
  477. if (isset($_REQUEST['criteriaSort'][$column_index])
  478. && $_REQUEST['criteriaSort'][$column_index] == 'DESC'
  479. ) {
  480. $this->_curSort[$new_column_count]
  481. = $_REQUEST['criteriaSort'][$column_index];
  482. $desc_selected = ' selected="selected"';
  483. } else {
  484. $desc_selected = '';
  485. } // end if
  486. $html_output .= $this->_getSortSelectCell(
  487. $new_column_count, $asc_selected, $desc_selected
  488. );
  489. $new_column_count++;
  490. } // end for
  491. $html_output .= '</tr>';
  492. return $html_output;
  493. }
  494. /**
  495. * Provides search form's row containing SHOW checkboxes
  496. *
  497. * @return string HTML for search table's row
  498. */
  499. private function _getShowRow()
  500. {
  501. $html_output = '<tr class="odd noclick">';
  502. $html_output .= '<th>' . __('Show:') . '</th>';
  503. $new_column_count = 0;
  504. for (
  505. $column_index = 0;
  506. $column_index < $this->_criteria_column_count;
  507. $column_index++
  508. ) {
  509. if (! empty($this->_criteriaColumnInsert)
  510. && isset($this->_criteriaColumnInsert[$column_index])
  511. && $this->_criteriaColumnInsert[$column_index] == 'on'
  512. ) {
  513. $html_output .= '<td class="center">';
  514. $html_output .= '<input type="checkbox"'
  515. . ' name="criteriaShow[' . $new_column_count . ']" />';
  516. $html_output .= '</td>';
  517. $new_column_count++;
  518. } // end if
  519. if (! empty($this->_criteriaColumnDelete)
  520. && isset($this->_criteriaColumnDelete[$column_index])
  521. && $this->_criteriaColumnDelete[$column_index] == 'on'
  522. ) {
  523. continue;
  524. }
  525. if (isset($_REQUEST['criteriaShow'][$column_index])) {
  526. $checked_options = ' checked="checked"';
  527. $this->_curShow[$new_column_count]
  528. = $_REQUEST['criteriaShow'][$column_index];
  529. } else {
  530. $checked_options = '';
  531. }
  532. $html_output .= '<td class="center">';
  533. $html_output .= '<input type="checkbox"'
  534. . ' name="criteriaShow[' . $new_column_count . ']"'
  535. . $checked_options . ' />';
  536. $html_output .= '</td>';
  537. $new_column_count++;
  538. } // end for
  539. $html_output .= '</tr>';
  540. return $html_output;
  541. }
  542. /**
  543. * Provides search form's row containing criteria Inputboxes
  544. *
  545. * @return string HTML for search table's row
  546. */
  547. private function _getCriteriaInputboxRow()
  548. {
  549. $html_output = '<tr class="even noclick">';
  550. $html_output .= '<th>' . __('Criteria:') . '</th>';
  551. $new_column_count = 0;
  552. for (
  553. $column_index = 0;
  554. $column_index < $this->_criteria_column_count;
  555. $column_index++
  556. ) {
  557. if (! empty($this->_criteriaColumnInsert)
  558. && isset($this->_criteriaColumnInsert[$column_index])
  559. && $this->_criteriaColumnInsert[$column_index] == 'on'
  560. ) {
  561. $html_output .= '<td class="center">';
  562. $html_output .= '<input type="text"'
  563. . ' name="criteria[' . $new_column_count . ']"'
  564. . ' value=""'
  565. . ' class="textfield"'
  566. . ' style="width: ' . $this->_realwidth . '"'
  567. . ' size="20" />';
  568. $html_output .= '</td>';
  569. $new_column_count++;
  570. } // end if
  571. if (! empty($this->_criteriaColumnDelete)
  572. && isset($this->_criteriaColumnDelete[$column_index])
  573. && $this->_criteriaColumnDelete[$column_index] == 'on'
  574. ) {
  575. continue;
  576. }
  577. if (isset($this->_criteria[$column_index])) {
  578. $tmp_criteria = $this->_criteria[$column_index];
  579. }
  580. if ((empty($this->_prev_criteria)
  581. || ! isset($this->_prev_criteria[$column_index]))
  582. || $this->_prev_criteria[$column_index] != htmlspecialchars($tmp_criteria)
  583. ) {
  584. $this->_curCriteria[$new_column_count] = $tmp_criteria;
  585. } else {
  586. $this->_curCriteria[$new_column_count]
  587. = $this->_prev_criteria[$column_index];
  588. }
  589. $html_output .= '<td class="center">';
  590. $html_output .= '<input type="hidden"'
  591. . ' name="prev_criteria[' . $new_column_count . ']"'
  592. . ' value="'
  593. . htmlspecialchars($this->_curCriteria[$new_column_count])
  594. . '" />';
  595. $html_output .= '<input type="text"'
  596. . ' name="criteria[' . $new_column_count . ']"'
  597. . ' value="' . htmlspecialchars($tmp_criteria) . '"'
  598. . ' class="textfield"'
  599. . ' style="width: ' . $this->_realwidth . '"'
  600. . ' size="20" />';
  601. $html_output .= '</td>';
  602. $new_column_count++;
  603. } // end for
  604. $html_output .= '</tr>';
  605. return $html_output;
  606. }
  607. /**
  608. * Provides footer options for adding/deleting row/columns
  609. *
  610. * @param string $type Whether row or column
  611. *
  612. * @return string HTML for footer options
  613. */
  614. private function _getFootersOptions($type)
  615. {
  616. $html_output = '<div class="floatleft">';
  617. $html_output .= (($type == 'row')
  618. ? __('Add/Delete criteria rows') : __('Add/Delete columns'));
  619. $html_output .= ':<select size="1" name="'
  620. . (($type == 'row') ? 'criteriaRowAdd' : 'criteriaColumnAdd') . '">';
  621. $html_output .= '<option value="-3">-3</option>';
  622. $html_output .= '<option value="-2">-2</option>';
  623. $html_output .= '<option value="-1">-1</option>';
  624. $html_output .= '<option value="0" selected="selected">0</option>';
  625. $html_output .= '<option value="1">1</option>';
  626. $html_output .= '<option value="2">2</option>';
  627. $html_output .= '<option value="3">3</option>';
  628. $html_output .= '</select>';
  629. $html_output .= '</div>';
  630. return $html_output;
  631. }
  632. /**
  633. * Provides search form table's footer options
  634. *
  635. * @return string HTML for table footer
  636. */
  637. private function _getTableFooters()
  638. {
  639. $html_output = '<fieldset class="tblFooters">';
  640. $html_output .= $this->_getFootersOptions("row");
  641. $html_output .= $this->_getFootersOptions("column");
  642. $html_output .= '<div class="floatleft">';
  643. $html_output .= '<input type="submit" name="modify"'
  644. . 'value="' . __('Update Query') . '" />';
  645. $html_output .= '</div>';
  646. $html_output .= '</fieldset>';
  647. return $html_output;
  648. }
  649. /**
  650. * Provides a select list of database tables
  651. *
  652. * @return string HTML for table select list
  653. */
  654. private function _getTablesList()
  655. {
  656. $html_output = '<div class="floatleft">';
  657. $html_output .= '<fieldset>';
  658. $html_output .= '<legend>' . __('Use Tables') . '</legend>';
  659. // Build the options list for each table name
  660. $options = '';
  661. $numTableListOptions = 0;
  662. foreach ($this->_criteriaTables as $key => $val) {
  663. $options .= '<option value="' . htmlspecialchars($key) . '"' . $val . '>'
  664. . (str_replace(' ', '&nbsp;', htmlspecialchars($key))) . '</option>';
  665. $numTableListOptions++;
  666. }
  667. $html_output .= '<select name="TableList[]"'
  668. . ' multiple="multiple" id="listTable"'
  669. . ' size="' . (($numTableListOptions > 30) ? '15' : '7') . '">';
  670. $html_output .= $options;
  671. $html_output .= '</select>';
  672. $html_output .= '</fieldset>';
  673. $html_output .= '<fieldset class="tblFooters">';
  674. $html_output .= '<input type="submit" name="modify" value="'
  675. . __('Update Query') . '" />';
  676. $html_output .= '</fieldset>';
  677. $html_output .= '</div>';
  678. return $html_output;
  679. }
  680. /**
  681. * Provides And/Or modification cell along with Insert/Delete options
  682. * (For modifying search form's table columns)
  683. *
  684. * @param integer $column_number Column Number (0,1,2) or more
  685. * @param array $selected Selected criteria column name
  686. *
  687. * @return string HTML for modification cell
  688. */
  689. private function _getAndOrColCell($column_number, $selected = null)
  690. {
  691. $html_output = '<td class="center">';
  692. $html_output .= '<strong>' . __('Or:') . '</strong>';
  693. $html_output .= '<input type="radio"'
  694. . ' name="criteriaAndOrColumn[' . $column_number . ']"'
  695. . ' value="or"' . $selected['or'] . ' />';
  696. $html_output .= '&nbsp;&nbsp;<strong>' . __('And:') . '</strong>';
  697. $html_output .= '<input type="radio"'
  698. . ' name="criteriaAndOrColumn[' . $column_number . ']"'
  699. . ' value="and"' . $selected['and'] . ' />';
  700. $html_output .= '<br />' . __('Ins');
  701. $html_output .= '<input type="checkbox"'
  702. . ' name="criteriaColumnInsert[' . $column_number . ']" />';
  703. $html_output .= '&nbsp;&nbsp;' . __('Del');
  704. $html_output .= '<input type="checkbox"'
  705. . ' name="criteriaColumnDelete[' . $column_number . ']" />';
  706. $html_output .= '</td>';
  707. return $html_output;
  708. }
  709. /**
  710. * Provides search form's row containing column modifications options
  711. * (For modifying search form's table columns)
  712. *
  713. * @return string HTML for search table's row
  714. */
  715. private function _getModifyColumnsRow()
  716. {
  717. $html_output = '<tr class="even noclick">';
  718. $html_output .= '<th>' . __('Modify:') . '</th>';
  719. $new_column_count = 0;
  720. for (
  721. $column_index = 0;
  722. $column_index < $this->_criteria_column_count;
  723. $column_index++
  724. ) {
  725. if (! empty($this->_criteriaColumnInsert)
  726. && isset($this->_criteriaColumnInsert[$column_index])
  727. && $this->_criteriaColumnInsert[$column_index] == 'on'
  728. ) {
  729. $html_output .= $this->_getAndOrColCell($new_column_count);
  730. $new_column_count++;
  731. } // end if
  732. if (! empty($this->_criteriaColumnDelete)
  733. && isset($this->_criteriaColumnDelete[$column_index])
  734. && $this->_criteriaColumnDelete[$column_index] == 'on'
  735. ) {
  736. continue;
  737. }
  738. if (isset($this->_criteriaAndOrColumn[$column_index])) {
  739. $this->_curAndOrCol[$new_column_count]
  740. = $this->_criteriaAndOrColumn[$column_index];
  741. }
  742. $checked_options = array();
  743. if (isset($this->_criteriaAndOrColumn[$column_index])
  744. && $this->_criteriaAndOrColumn[$column_index] == 'or'
  745. ) {
  746. $checked_options['or'] = ' checked="checked"';
  747. $checked_options['and'] = '';
  748. } else {
  749. $checked_options['and'] = ' checked="checked"';
  750. $checked_options['or'] = '';
  751. }
  752. $html_output .= $this->_getAndOrColCell(
  753. $new_column_count,
  754. $checked_options
  755. );
  756. $new_column_count++;
  757. } // end for
  758. $html_output .= '</tr>';
  759. return $html_output;
  760. }
  761. /**
  762. * Provides Insert/Delete options for criteria inputbox
  763. * with AND/OR relationship modification options
  764. *
  765. * @param integer $row_index Number of criteria row
  766. * @param array $checked_options If checked
  767. *
  768. * @return string HTML
  769. */
  770. private function _getInsDelAndOrCell($row_index, $checked_options)
  771. {
  772. $html_output = '<td class="' . $GLOBALS['cell_align_right'] . ' nowrap">';
  773. $html_output .= '<!-- Row controls -->';
  774. $html_output .= '<table class="nospacing nopadding">';
  775. $html_output .= '<tr>';
  776. $html_output .= '<td class="' . $GLOBALS['cell_align_right'] . ' nowrap">';
  777. $html_output .= '<small>' . __('Ins:') . '</small>';
  778. $html_output .= '<input type="checkbox"'
  779. . ' name="criteriaRowInsert[' . $row_index . ']" />';
  780. $html_output .= '</td>';
  781. $html_output .= '<td class="' . $GLOBALS['cell_align_right'] . '">';
  782. $html_output .= '<strong>' . __('And:') . '</strong>';
  783. $html_output .= '</td>';
  784. $html_output .= '<td>';
  785. $html_output .= '<input type="radio"'
  786. . ' name="criteriaAndOrRow[' . $row_index . ']" value="and"'
  787. . $checked_options['and'] . ' />';
  788. $html_output .= '</td>';
  789. $html_output .= '</tr>';
  790. $html_output .= '<tr>';
  791. $html_output .= '<td class="' . $GLOBALS['cell_align_right'] . ' nowrap">';
  792. $html_output .= '<small>' . __('Del:') . '</small>';
  793. $html_output .= '<input type="checkbox"'
  794. . ' name="criteriaRowDelete[' . $row_index . ']" />';
  795. $html_output .= '</td>';
  796. $html_output .= '<td class="' . $GLOBALS['cell_align_right'] . '">';
  797. $html_output .= '<strong>' . __('Or:') . '</strong>';
  798. $html_output .= '</td>';
  799. $html_output .= '<td>';
  800. $html_output .= '<input type="radio"'
  801. . ' name="criteriaAndOrRow[' . $row_index . ']"'
  802. . ' value="or"' . $checked_options['or'] . ' />';
  803. $html_output .= '</td>';
  804. $html_output .= '</tr>';
  805. $html_output .= '</table>';
  806. $html_output .= '</td>';
  807. return $html_output;
  808. }
  809. /**
  810. * Provides rows for criteria inputbox Insert/Delete options
  811. * with AND/OR relationship modification options
  812. *
  813. * @param integer $new_row_index New row index if rows are added/deleted
  814. * @param integer $row_index Row index
  815. *
  816. * @return string HTML table rows
  817. */
  818. private function _getInputboxRow($new_row_index, $row_index)
  819. {
  820. $html_output = '';
  821. $new_column_count = 0;
  822. for (
  823. $column_index = 0;
  824. $column_index < $this->_criteria_column_count;
  825. $column_index++
  826. ) {
  827. if (!empty($this->_criteriaColumnInsert)
  828. && isset($this->_criteriaColumnInsert[$column_index])
  829. && $this->_criteriaColumnInsert[$column_index] == 'on'
  830. ) {
  831. $orFieldName = 'Or' . $new_row_index . '[' . $new_column_count . ']';
  832. $html_output .= '<td class="center">';
  833. $html_output .= '<input type="text"'
  834. . ' name="Or' . $orFieldName . '" class="textfield"'
  835. . ' style="width: ' . $this->_realwidth . '" size="20" />';
  836. $html_output .= '</td>';
  837. $new_column_count++;
  838. } // end if
  839. if (!empty($this->_criteriaColumnDelete)
  840. && isset($this->_criteriaColumnDelete[$column_index])
  841. && $this->_criteriaColumnDelete[$column_index] == 'on'
  842. ) {
  843. continue;
  844. }
  845. $or = 'Or' . $new_row_index;
  846. if (! empty($_REQUEST[$or]) && isset($_REQUEST[$or][$column_index])) {
  847. $tmp_or = $_REQUEST[$or][$column_index];
  848. } else {
  849. $tmp_or = '';
  850. }
  851. $html_output .= '<td class="center">';
  852. $html_output .= '<input type="text"'
  853. . ' name="Or' . $new_row_index . '[' . $new_column_count . ']' . '"'
  854. . ' value="' . htmlspecialchars($tmp_or) . '" class="textfield"'
  855. . ' style="width: ' . $this->_realwidth . '" size="20" />';
  856. $html_output .= '</td>';
  857. if (!empty(${$or}) && isset(${$or}[$column_index])) {
  858. $GLOBALS[${'cur' . $or}][$new_column_count]
  859. = ${$or}[$column_index];
  860. }
  861. $new_column_count++;
  862. } // end for
  863. return $html_output;
  864. }
  865. /**
  866. * Provides rows for criteria inputbox Insert/Delete options
  867. * with AND/OR relationship modification options
  868. *
  869. * @return string HTML table rows
  870. */
  871. private function _getInsDelAndOrCriteriaRows()
  872. {
  873. $html_output = '';
  874. $new_row_count = 0;
  875. $odd_row = true;
  876. $checked_options = array();
  877. for (
  878. $row_index = 0;
  879. $row_index <= $this->_criteria_row_count;
  880. $row_index++
  881. ) {
  882. if (isset($this->_criteriaRowInsert[$row_index])
  883. && $this->_criteriaRowInsert[$row_index] == 'on'
  884. ) {
  885. $checked_options['or'] = ' checked="checked"';
  886. $checked_options['and'] = '';
  887. $html_output .= '<tr class="' . ($odd_row ? 'odd' : 'even')
  888. . ' noclick">';
  889. $html_output .= $this->_getInsDelAndOrCell(
  890. $new_row_count, $checked_options
  891. );
  892. $html_output .= $this->_getInputboxRow(
  893. $new_row_count, $row_index
  894. );
  895. $new_row_count++;
  896. $html_output .= '</tr>';
  897. $odd_row =! $odd_row;
  898. } // end if
  899. if (isset($this->_criteriaRowDelete[$row_index])
  900. && $this->_criteriaRowDelete[$row_index] == 'on'
  901. ) {
  902. continue;
  903. }
  904. if (isset($this->_criteriaAndOrRow[$row_index])) {
  905. $this->_curAndOrRow[$new_row_count]
  906. = $this->_criteriaAndOrRow[$row_index];
  907. }
  908. if (isset($this->_criteriaAndOrRow[$row_index])
  909. && $this->_criteriaAndOrRow[$row_index] == 'and'
  910. ) {
  911. $checked_options['and'] = ' checked="checked"';
  912. $checked_options['or'] = '';
  913. } else {
  914. $checked_options['or'] = ' checked="checked"';
  915. $checked_options['and'] = '';
  916. }
  917. $html_output .= '<tr class="' . ($odd_row ? 'odd' : 'even')
  918. . ' noclick">';
  919. $html_output .= $this->_getInsDelAndOrCell(
  920. $new_row_count, $checked_options
  921. );
  922. $html_output .= $this->_getInputboxRow(
  923. $new_row_count, $row_index
  924. );
  925. $new_row_count++;
  926. $html_output .= '</tr>';
  927. $odd_row =! $odd_row;
  928. } // end for
  929. $this->_new_row_count = $new_row_count;
  930. return $html_output;
  931. }
  932. /**
  933. * Provides SELECT clause for building SQL query
  934. *
  935. * @return string Select clause
  936. */
  937. private function _getSelectClause()
  938. {
  939. $select_clause = '';
  940. $select_clauses = array();
  941. for (
  942. $column_index = 0;
  943. $column_index < $this->_criteria_column_count;
  944. $column_index++
  945. ) {
  946. if (! empty($this->_curField[$column_index])
  947. && isset($this->_curShow[$column_index])
  948. && $this->_curShow[$column_index] == 'on'
  949. ) {
  950. $select_clauses[] = $this->_curField[$column_index];
  951. }
  952. } // end for
  953. if ($select_clauses) {
  954. $select_clause = 'SELECT '
  955. . htmlspecialchars(implode(", ", $select_clauses)) . "\n";
  956. }
  957. return $select_clause;
  958. }
  959. /**
  960. * Provides WHERE clause for building SQL query
  961. *
  962. * @return string Where clause
  963. */
  964. private function _getWhereClause()
  965. {
  966. $where_clause = '';
  967. $criteria_cnt = 0;
  968. for (
  969. $column_index = 0;
  970. $column_index < $this->_criteria_column_count;
  971. $column_index++
  972. ) {
  973. if (! empty($this->_curField[$column_index])
  974. && ! empty($this->_curCriteria[$column_index])
  975. && $column_index
  976. && isset($last_where)
  977. && isset($this->_curAndOrCol)
  978. ) {
  979. $where_clause .= ' '
  980. . strtoupper($this->_curAndOrCol[$last_where]) . ' ';
  981. }
  982. if (! empty($this->_curField[$column_index])
  983. && ! empty($this->_curCriteria[$column_index])
  984. ) {
  985. $where_clause .= '(' . $this->_curField[$column_index] . ' '
  986. . $this->_curCriteria[$column_index] . ')';
  987. $last_where = $column_index;
  988. $criteria_cnt++;
  989. }
  990. } // end for
  991. if ($criteria_cnt > 1) {
  992. $where_clause = '(' . $where_clause . ')';
  993. }
  994. // OR rows ${'cur' . $or}[$column_index]
  995. if (! isset($this->_curAndOrRow)) {
  996. $this->_curAndOrRow = array();
  997. }
  998. for (
  999. $row_index = 0;
  1000. $row_index <= $this->_criteria_row_count;
  1001. $row_index++
  1002. ) {
  1003. $criteria_cnt = 0;
  1004. $qry_orwhere = '';
  1005. $last_orwhere = '';
  1006. for (
  1007. $column_index = 0;
  1008. $column_index < $this->_criteria_column_count;
  1009. $column_index++
  1010. ) {
  1011. if (! empty($this->_curField[$column_index])
  1012. && ! empty($_REQUEST['Or' . $row_index][$column_index])
  1013. && $column_index
  1014. ) {
  1015. $qry_orwhere .= ' '
  1016. . strtoupper($this->_curAndOrCol[$last_orwhere]) . ' ';
  1017. }
  1018. if (! empty($this->_curField[$column_index])
  1019. && ! empty($_REQUEST['Or' . $row_index][$column_index])
  1020. ) {
  1021. $qry_orwhere .= '(' . $this->_curField[$column_index]
  1022. . ' '
  1023. . $_REQUEST['Or' . $row_index][$column_index]
  1024. . ')';
  1025. $last_orwhere = $column_index;
  1026. $criteria_cnt++;
  1027. }
  1028. } // end for
  1029. if ($criteria_cnt > 1) {
  1030. $qry_orwhere = '(' . $qry_orwhere . ')';
  1031. }
  1032. if (! empty($qry_orwhere)) {
  1033. $where_clause .= "\n"
  1034. . strtoupper(
  1035. isset($this->_curAndOrRow[$row_index])
  1036. ? $this->_curAndOrRow[$row_index] . ' '
  1037. : ''
  1038. )
  1039. . $qry_orwhere;
  1040. } // end if
  1041. } // end for
  1042. if (! empty($where_clause) && $where_clause != '()') {
  1043. $where_clause = 'WHERE ' . htmlspecialchars($where_clause) . "\n";
  1044. } // end if
  1045. return $where_clause;
  1046. }
  1047. /**
  1048. * Provides ORDER BY clause for building SQL query
  1049. *
  1050. * @return string Order By clause
  1051. */
  1052. private function _getOrderByClause()
  1053. {
  1054. $orderby_clause = '';
  1055. $orderby_clauses = array();
  1056. for (
  1057. $column_index = 0;
  1058. $column_index < $this->_criteria_column_count;
  1059. $column_index++
  1060. ) {
  1061. // if all columns are chosen with * selector,
  1062. // then sorting isn't available
  1063. // Fix for Bug #570698
  1064. if (! empty($this->_curField[$column_index])
  1065. && ! empty($this->_curSort[$column_index])
  1066. ) {
  1067. if (substr($this->_curField[$column_index], -2) == '.*') {
  1068. continue;
  1069. }
  1070. $orderby_clauses[] = $this->_curField[$column_index] . ' '
  1071. . $this->_curSort[$column_index];
  1072. }
  1073. } // end for
  1074. if ($orderby_clauses) {
  1075. $orderby_clause = 'ORDER BY '
  1076. . htmlspecialchars(implode(", ", $orderby_clauses)) . "\n";
  1077. }
  1078. return $orderby_clause;
  1079. }
  1080. /**
  1081. * Provides UNIQUE columns and INDEX columns present in criteria tables
  1082. *
  1083. * @param array $all_tables Tables involved in the search
  1084. * @param array $all_columns Columns involved in the search
  1085. * @param array $where_clause_columns Columns having criteria where clause
  1086. *
  1087. * @return array having UNIQUE and INDEX columns
  1088. */
  1089. private function _getIndexes($all_tables, $all_columns,
  1090. $where_clause_columns
  1091. ) {
  1092. $unique_columns = array();
  1093. $index_columns = array();
  1094. foreach ($all_tables as $table) {
  1095. $indexes = $GLOBALS['dbi']->getTableIndexes($this->_db, $table);
  1096. foreach ($indexes as $index) {
  1097. $column = $table . '.' . $index['Column_name'];
  1098. if (isset($all_columns[$column])) {
  1099. if ($index['Non_unique'] == 0) {
  1100. if (isset($where_clause_columns[$column])) {
  1101. $unique_columns[$column] = 'Y';
  1102. } else {
  1103. $unique_columns[$column] = 'N';
  1104. }
  1105. } else {
  1106. if (isset($where_clause_columns[$column])) {
  1107. $index_columns[$column] = 'Y';
  1108. } else {
  1109. $index_columns[$column] = 'N';
  1110. }
  1111. }
  1112. }
  1113. } // end while (each index of a table)
  1114. } // end while (each table)
  1115. return array(
  1116. 'unique' => $unique_columns,
  1117. 'index' => $index_columns
  1118. );
  1119. }
  1120. /**
  1121. * Provides UNIQUE columns and INDEX columns present in criteria tables
  1122. *
  1123. * @param array $all_tables Tables involved in the search
  1124. * @param array $all_columns Columns involved in the search
  1125. * @param array $where_clause_columns Columns having criteria where clause
  1126. *
  1127. * @return array having UNIQUE and INDEX columns
  1128. */
  1129. private function _getLeftJoinColumnCandidates($all_tables, $all_columns,
  1130. $where_clause_columns
  1131. ) {
  1132. $GLOBALS['dbi']->selectDb($this->_db);
  1133. // Get unique columns and index columns
  1134. $indexes = $this->_getIndexes(
  1135. $all_tables, $all_columns, $where_clause_columns
  1136. );
  1137. $unique_columns = $indexes['unique'];
  1138. $index_columns = $indexes['index'];
  1139. list($candidate_columns, $needsort)
  1140. = $this->_getLeftJoinColumnCandidatesBest(
  1141. $all_tables, $where_clause_columns, $unique_columns, $index_columns
  1142. );
  1143. // If we came up with $unique_columns (very good) or $index_columns (still
  1144. // good) as $candidate_columns we want to check if we have any 'Y' there
  1145. // (that would mean that they were also found in the whereclauses
  1146. // which would be great). if yes, we take only those
  1147. if ($needsort != 1) {
  1148. return $candidate_columns;
  1149. }
  1150. $vg = array();
  1151. $sg = array();
  1152. foreach ($candidate_columns as $column => $is_where) {
  1153. $table = explode('.', $column);
  1154. $table = $table[0];
  1155. if ($is_where == 'Y') {
  1156. $vg[$column] = $table;
  1157. } else {
  1158. $sg[$column] = $table;
  1159. }
  1160. }
  1161. if (count($vg) > 0) {
  1162. $candidate_columns = $vg;
  1163. // Candidates restricted in index+where
  1164. } else {
  1165. $candidate_columns = $sg;
  1166. // None of the candidates where in a where-clause
  1167. }
  1168. return $candidate_columns;
  1169. }
  1170. /**
  1171. * Provides the main table to form the LEFT JOIN clause
  1172. *
  1173. * @param array $all_tables Tables involved in the search
  1174. * @param array $all_columns Columns involved in the search
  1175. * @param array $where_clause_columns Columns having criteria where clause
  1176. * @param array $where_clause_tables Tables having criteria where clause
  1177. *
  1178. * @return string table name
  1179. */
  1180. private function _getMasterTable($all_tables, $all_columns,
  1181. $where_clause_columns, $where_clause_tables
  1182. ) {
  1183. if (count($where_clause_tables) == 1) {
  1184. // If there is exactly one column that has a decent where-clause
  1185. // we will just use this
  1186. $master = key($where_clause_tables);
  1187. return $master;
  1188. }
  1189. // Now let's find out which of the tables has an index
  1190. // (When the control user is the same as the normal user
  1191. // because he is using one of his databases as pmadb,
  1192. // the last db selected is not always the one where we need to work)
  1193. $candidate_columns = $this->_getLeftJoinColumnCandidates(
  1194. $all_tables, $all_columns, $where_clause_columns
  1195. );
  1196. // If our array of candidates has more than one member we'll just
  1197. // find the smallest table.
  1198. // Of course the actual query would be faster if we check for
  1199. // the Criteria which gives the smallest result set in its table,
  1200. // but it would take too much time to check this
  1201. if (!(count($candidate_columns) > 1)) {
  1202. reset($candidate_columns);
  1203. $master = current($candidate_columns); // Only one single candidate
  1204. return $master;
  1205. }
  1206. // Of course we only want to check each table once
  1207. $checked_tables = $candidate_columns;
  1208. $tsize = array();
  1209. $csize = array();
  1210. foreach ($candidate_columns as $table) {
  1211. if ($checked_tables[$table] != 1) {
  1212. $tsize[$table] = PMA_Table::countRecords(
  1213. $this->_db,
  1214. $table,
  1215. false
  1216. );
  1217. $checked_tables[$table] = 1;
  1218. }
  1219. $csize[$table] = $tsize[$table];
  1220. }
  1221. asort($csize);
  1222. reset($csize);
  1223. $master = key($csize); // Smallest
  1224. return $master;
  1225. }
  1226. /**
  1227. * Provides columns and tables that have valid where clause criteria
  1228. *
  1229. * @return array
  1230. */
  1231. private function _getWhereClauseTablesAndColumns()
  1232. {
  1233. $where_clause_columns = array();
  1234. $where_clause_tables = array();
  1235. // Now we need all tables that we have in the where clause
  1236. for (
  1237. $column_index = 0, $nb = count($this->_criteria);
  1238. $column_index < $nb;
  1239. $column_index++
  1240. ) {
  1241. $current_table = explode('.', $_POST['criteriaColumn'][$column_index]);
  1242. if (empty($current_table[0]) || empty($current_table[1])) {
  1243. continue;
  1244. } // end if
  1245. $table = str_replace('`', '', $current_table[0]);
  1246. $column = str_replace('`', '', $current_table[1]);
  1247. $column = $table . '.' . $column;
  1248. // Now we know that our array has the same numbers as $criteria
  1249. // we can check which of our columns has a where clause
  1250. if (! empty($this->_criteria[$column_index])) {
  1251. if (substr($this->_criteria[$column_index], 0, 1) == '='
  1252. || stristr($this->_criteria[$column_index], 'is')
  1253. ) {
  1254. $where_clause_columns[$column] = $column;
  1255. $where_clause_tables[$table] = $table;
  1256. }
  1257. } // end if
  1258. } // end for
  1259. return array(
  1260. 'where_clause_tables' => $where_clause_tables,
  1261. 'where_clause_columns' => $where_clause_columns
  1262. );
  1263. }
  1264. /**
  1265. * Provides FROM clause for building SQL query
  1266. *
  1267. * @param array $cfgRelation Relation Settings
  1268. *
  1269. * @return string FROM clause
  1270. */
  1271. private function _getFromClause($cfgRelation)
  1272. {
  1273. $from_clause = '';
  1274. if (isset($_POST['criteriaColumn']) && count($_POST['criteriaColumn']) > 0) {
  1275. // Initialize some variables
  1276. $all_tables = $all_columns = array();
  1277. // We only start this if we have fields, otherwise it would be dumb
  1278. foreach ($_POST['criteriaColumn'] as $value) {
  1279. $parts = explode('.', $value);
  1280. if (! empty($parts[0]) && ! empty($parts[1])) {
  1281. $table = str_replace('`', '', $parts[0]);
  1282. $all_tables[$table] = $table;
  1283. $all_columns[] = $table . '.' . str_replace('`', '', $parts[1]);
  1284. }
  1285. } // end while
  1286. // Create LEFT JOINS out of Relations
  1287. if ($cfgRelation['relwork'] && count($all_tables) > 0) {
  1288. // Get tables and columns with valid where clauses
  1289. $valid_where_clauses = $this->_getWhereClauseTablesAndColumns();
  1290. $where_clause_tables = $valid_where_clauses['where_clause_tables'];
  1291. $where_clause_columns = $valid_where_clauses['where_clause_columns'];
  1292. // Get master table
  1293. $master = $this->_getMasterTable(
  1294. $all_tables, $all_columns,
  1295. $where_clause_columns, $where_clause_tables
  1296. );
  1297. $from_clause = PMA_Util::backquote($master)
  1298. . PMA_getRelatives($all_tables, $master);
  1299. } // end if ($cfgRelation['relwork'] && count($all_tables) > 0)
  1300. } // end count($_POST['criteriaColumn']) > 0
  1301. // In case relations are not defined, just generate the FROM clause
  1302. // from the list of tables, however we don't generate any JOIN
  1303. if (empty($from_clause) && isset($all_tables)) {
  1304. $from_clause = implode(', ', $all_tables);
  1305. }
  1306. return $from_clause;
  1307. }
  1308. /**
  1309. * Provides the generated SQL query
  1310. *
  1311. * @param array $cfgRelation Relation Settings
  1312. *
  1313. * @return string SQL query
  1314. */
  1315. private function _getSQLQuery($cfgRelation)
  1316. {
  1317. $sql_query = '';
  1318. // get SELECT clause
  1319. $sql_query .= $this->_getSelectClause();
  1320. // get FROM clause
  1321. $from_clause = $this->_getFromClause($cfgRelation);
  1322. if (! empty($from_clause)) {
  1323. $sql_query .= 'FROM ' . htmlspecialchars($from_clause) . "\n";
  1324. }
  1325. // get WHERE clause
  1326. $sql_query .= $this->_getWhereClause();
  1327. // get ORDER BY clause
  1328. $sql_query .= $this->_getOrderByClause();
  1329. return $sql_query;
  1330. }
  1331. /**
  1332. * Provides the generated QBE form
  1333. *
  1334. * @param array $cfgRelation Relation Settings
  1335. *
  1336. * @return string QBE form
  1337. */
  1338. public function getSelectionForm($cfgRelation)
  1339. {
  1340. $html_output = '<form action="db_qbe.php" method="post" id="formQBE">';
  1341. $html_output .= '<fieldset>';
  1342. if ($GLOBALS['cfgRelation']['savedsearcheswork']) {
  1343. $html_output .= $this->_getSavedSearchesField();
  1344. }
  1345. $html_output .= '<table class="data" style="width: 100%;">';
  1346. // Get table's <tr> elements
  1347. $html_output .= $this->_getColumnNamesRow();
  1348. $html_output .= $this->_getSortRow();
  1349. $html_output .= $this->_getShowRow();
  1350. $html_output .= $this->_getCriteriaInputboxRow();
  1351. $html_output .= $this->_getInsDelAndOrCriteriaRows();
  1352. $html_output .= $this->_getModifyColumnsRow();
  1353. $html_output .= '</table>';
  1354. $this->_new_row_count--;
  1355. $url_params = array();
  1356. $url_params['db'] = $this->_db;
  1357. $url_params['criteriaColumnCount'] = $this->_new_column_count;
  1358. $url_params['rows'] = $this->_new_row_count;
  1359. $html_output .= PMA_URL_getHiddenInputs($url_params);
  1360. $html_output .= '</fieldset>';
  1361. // get footers
  1362. $html_output .= $this->_getTableFooters();
  1363. // get tables select list
  1364. $html_output .= $this->_getTablesList();
  1365. $html_output .= '</form>';
  1366. $html_output .= '<form action="db_qbe.php" method="post">';
  1367. $html_output .= PMA_URL_getHiddenInputs(array('db' => $this->_db));
  1368. // get SQL query
  1369. $html_output .= '<div class="floatleft">';
  1370. $html_output .= '<fieldset>';
  1371. $html_output .= '<legend>'
  1372. . sprintf(
  1373. __('SQL query on database <b>%s</b>:'),
  1374. PMA_Util::getDbLink($this->_db)
  1375. );
  1376. $html_output .= '</legend>';
  1377. $text_dir = 'ltr';
  1378. $html_output .= '<textarea cols="80" name="sql_query" id="textSqlquery"'
  1379. . ' rows="' . ((count($this->_criteriaTables) > 30) ? '15' : '7') . '"'
  1380. . ' dir="' . $text_dir . '">';
  1381. $html_output .= $this->_getSQLQuery($cfgRelation);
  1382. $html_output .= '</textarea>';
  1383. $html_output .= '</fieldset>';
  1384. // displays form's footers
  1385. $html_output .= '<fieldset class="tblFooters">';
  1386. $html_output .= '<input type="hidden" name="submit_sql" value="1" />';
  1387. $html_output .= '<input type="submit" value="' . __('Submit Query') . '" />';
  1388. $html_output .= '</fieldset>';
  1389. $html_output .= '</div>';
  1390. $html_output .= '</form>';
  1391. return $html_output;
  1392. }
  1393. /**
  1394. * Get fields to display
  1395. *
  1396. * @return string
  1397. */
  1398. private function _getSavedSearchesField()
  1399. {
  1400. $html_output = __('Saved bookmarked search:');
  1401. $html_output .= ' <select name="searchId" id="searchId">';
  1402. $html_output .= '<option value="">' . __('New bookmark') . '</option>';
  1403. $currentSearch = $this->_getCurrentSearch();
  1404. $currentSearchId = null;
  1405. $currentSearchName = null;
  1406. if (null != $currentSearch) {
  1407. $currentSearchId = $currentSearch->getId();
  1408. $currentSearchName = $currentSearch->getSearchName();
  1409. }
  1410. foreach ($this->_savedSearchList as $id => $name) {
  1411. $html_output .= '<option value="' . htmlspecialchars($id)
  1412. . '" ' . (
  1413. $id == $currentSearchId
  1414. ? 'selected="selected" '
  1415. : ''
  1416. )
  1417. . '>'
  1418. . htmlspecialchars($name)
  1419. . '</option>';
  1420. }
  1421. $html_output .= '</select>';
  1422. $html_output .= '<input type="text" name="searchName" id="searchName" '
  1423. . 'value="' . $currentSearchName . '" />';
  1424. $html_output .= '<input type="hidden" name="action" id="action" value="" />';
  1425. $html_output .= '<input type="submit" name="saveSearch" id="saveSearch" '
  1426. . 'value="' . __('Create bookmark') . '" />';
  1427. if (null !== $currentSearchId) {
  1428. $html_output .= '<input type="submit" name="updateSearch" '
  1429. . 'id="updateSearch" value="' . __('Update bookmark') . '" />';
  1430. $html_output .= '<input type="submit" name="deleteSearch" '
  1431. . 'id="deleteSearch" value="' . __('Delete bookmark') . '" />';
  1432. }
  1433. return $html_output;
  1434. }
  1435. /**
  1436. * Initialize _criteria_column_count
  1437. *
  1438. * @return int Previous number of columns
  1439. */
  1440. private function _initializeCriteriasCount()
  1441. {
  1442. // sets column count
  1443. $criteriaColumnCount = PMA_ifSetOr(
  1444. $_REQUEST['criteriaColumnCount'],
  1445. 3,
  1446. 'numeric'
  1447. );
  1448. $criteriaColumnAdd = PMA_ifSetOr(
  1449. $_REQUEST['criteriaColumnAdd'],
  1450. 0,
  1451. 'numeric'
  1452. );
  1453. $this->_criteria_column_count = max(
  1454. $criteriaColumnCount + $criteriaColumnAdd,
  1455. 0
  1456. );
  1457. // sets row count
  1458. $rows = PMA_ifSetOr($_REQUEST['rows'], 0, 'numeric');
  1459. $criteriaRowAdd = PMA_ifSetOr($_REQUEST['criteriaRowAdd'], 0, 'numeric');
  1460. $this->_criteria_row_count = max($rows + $criteriaRowAdd, 0);
  1461. return $criteriaColumnCount;
  1462. }
  1463. /**
  1464. * Get best
  1465. *
  1466. * @param array $all_tables All tables
  1467. * @param array $where_clause_columns Columns with where clause
  1468. * @param array $unique_columns Unique columns
  1469. * @param array $index_columns Indexed columns
  1470. *
  1471. * @return array
  1472. */
  1473. private function _getLeftJoinColumnCandidatesBest(
  1474. $all_tables, $where_clause_columns, $unique_columns, $index_columns
  1475. ) {
  1476. // now we want to find the best.
  1477. if (isset($unique_columns) && count($unique_columns) > 0) {
  1478. $candidate_columns = $unique_columns;
  1479. $needsort = 1;
  1480. return array($candidate_columns, $needsort);
  1481. } elseif (isset($index_columns) && count($index_columns) > 0) {
  1482. $candidate_columns = $index_columns;
  1483. $needsort = 1;
  1484. return array($candidate_columns, $needsort);
  1485. } elseif (isset($where_clause_columns) && count($where_clause_columns) > 0) {
  1486. $candidate_columns = $where_clause_columns;
  1487. $needsort = 0;
  1488. return array($candidate_columns, $needsort);
  1489. } else {
  1490. $candidate_columns = $all_tables;
  1491. $needsort = 0;
  1492. return array($candidate_columns, $needsort);
  1493. }
  1494. }
  1495. }
  1496. ?>