2 /* vim: set expandtab sw=4 ts=4 sts=4: */
4 * Handles DB QBE search
8 namespace PMA\libraries
;
10 use PMA\libraries\URL
;
11 use PMA\libraries\Util
;
14 * Class to handle database QBE search
28 * Table Names (selected/non-selected)
33 private $_criteriaTables;
40 private $_columnNames;
47 private $_criteria_column_count;
54 private $_criteria_row_count;
56 * Whether to insert a new column
61 private $_criteriaColumnInsert;
63 * Whether to delete a column
68 private $_criteriaColumnDelete;
70 * Whether to insert a new row
75 private $_criteriaRowInsert;
77 * Whether to delete a row
82 private $_criteriaRowDelete;
84 * Already set criteria values
91 * Previously set criteria values
96 private $_prev_criteria;
98 * AND/OR relation b/w criteria columns
103 private $_criteriaAndOrColumn;
105 * AND/OR relation b/w criteria rows
110 private $_criteriaAndOrRow;
112 * Large width of a column
119 * Minimum width of a column
124 private $_form_column_width;
126 * Selected columns in the form
131 private $_formColumns;
133 * Entered aliases in the form
138 private $_formAliases;
140 * Chosen sort options in the form
147 * Chosen sort orders in the form
152 private $_formSortOrders;
154 * Show checkboxes in the form
161 * Entered criteria values in the form
166 private $_formCriterions;
168 * AND/OR column radio buttons in the form
173 private $_formAndOrCols;
175 * AND/OR row radio buttons in the form
180 private $_formAndOrRows;
182 * New column count in case of add/delete
187 private $_new_column_count;
189 * New row count in case of add/delete
194 private $_new_row_count;
196 * List of saved searches
201 private $_savedSearchList = null;
208 private $_currentSearch = null;
211 * Initialize criterias
215 private function _loadCriterias()
217 if (null === $this->_currentSearch
218 ||
null === $this->_currentSearch
->getCriterias()
223 $criterias = $this->_currentSearch
->getCriterias();
224 $_REQUEST = $criterias +
$_REQUEST;
230 * Getter for current search
232 * @return SavedSearches
234 private function _getCurrentSearch()
236 return $this->_currentSearch
;
242 * @param string $dbname Database name
243 * @param array $savedSearchList List of saved searches
244 * @param SavedSearches $currentSearch Current search id
246 public function __construct(
247 $dbname, $savedSearchList = array(), $currentSearch = null
249 $this->_db
= $dbname;
250 $this->_savedSearchList
= $savedSearchList;
251 $this->_currentSearch
= $currentSearch;
252 $this->_loadCriterias();
253 // Sets criteria parameters
254 $this->_setSearchParams();
255 $this->_setCriteriaTablesAndColumns();
259 * Sets search parameters
263 private function _setSearchParams()
265 $criteriaColumnCount = $this->_initializeCriteriasCount();
267 $this->_criteriaColumnInsert
= PMA_ifSetOr(
268 $_REQUEST['criteriaColumnInsert'],
272 $this->_criteriaColumnDelete
= PMA_ifSetOr(
273 $_REQUEST['criteriaColumnDelete'],
278 $this->_prev_criteria
= isset($_REQUEST['prev_criteria'])
279 ?
$_REQUEST['prev_criteria']
281 $this->_criteria
= isset($_REQUEST['criteria'])
282 ?
$_REQUEST['criteria']
283 : array_fill(0, $criteriaColumnCount, '');
285 $this->_criteriaRowInsert
= isset($_REQUEST['criteriaRowInsert'])
286 ?
$_REQUEST['criteriaRowInsert']
287 : array_fill(0, $criteriaColumnCount, '');
288 $this->_criteriaRowDelete
= isset($_REQUEST['criteriaRowDelete'])
289 ?
$_REQUEST['criteriaRowDelete']
290 : array_fill(0, $criteriaColumnCount, '');
291 $this->_criteriaAndOrRow
= isset($_REQUEST['criteriaAndOrRow'])
292 ?
$_REQUEST['criteriaAndOrRow']
293 : array_fill(0, $criteriaColumnCount, '');
294 $this->_criteriaAndOrColumn
= isset($_REQUEST['criteriaAndOrColumn'])
295 ?
$_REQUEST['criteriaAndOrColumn']
296 : array_fill(0, $criteriaColumnCount, '');
297 // sets minimum width
298 $this->_form_column_width
= 12;
299 $this->_formColumns
= array();
300 $this->_formSorts
= array();
301 $this->_formShows
= array();
302 $this->_formCriterions
= array();
303 $this->_formAndOrRows
= array();
304 $this->_formAndOrCols
= array();
308 * Sets criteria tables and columns
312 private function _setCriteriaTablesAndColumns()
314 // The tables list sent by a previously submitted form
315 if (PMA_isValid($_REQUEST['TableList'], 'array')) {
316 foreach ($_REQUEST['TableList'] as $each_table) {
317 $this->_criteriaTables
[$each_table] = ' selected="selected"';
320 $all_tables = $GLOBALS['dbi']->query(
321 'SHOW TABLES FROM ' . Util
::backquote($this->_db
) . ';',
323 DatabaseInterface
::QUERY_STORE
325 $all_tables_count = $GLOBALS['dbi']->numRows($all_tables);
326 if (0 == $all_tables_count) {
327 Message
::error(__('No tables found in database.'))->display();
330 // The tables list gets from MySQL
331 while (list($table) = $GLOBALS['dbi']->fetchRow($all_tables)) {
332 $columns = $GLOBALS['dbi']->getColumns($this->_db
, $table);
334 if (empty($this->_criteriaTables
[$table])
335 && ! empty($_REQUEST['TableList'])
337 $this->_criteriaTables
[$table] = '';
339 $this->_criteriaTables
[$table] = ' selected="selected"';
342 // The fields list per selected tables
343 if ($this->_criteriaTables
[$table] == ' selected="selected"') {
344 $each_table = Util
::backquote($table);
345 $this->_columnNames
[] = $each_table . '.*';
346 foreach ($columns as $each_column) {
347 $each_column = $each_table . '.'
348 . Util
::backquote($each_column['Field']);
349 $this->_columnNames
[] = $each_column;
350 // increase the width if necessary
351 $this->_form_column_width
= max(
352 mb_strlen($each_column),
353 $this->_form_column_width
358 $GLOBALS['dbi']->freeResult($all_tables);
360 // sets the largest width found
361 $this->_realwidth
= $this->_form_column_width
. 'ex';
364 * Provides select options list containing column names
366 * @param integer $column_number Column Number (0,1,2) or more
367 * @param string $selected Selected criteria column name
369 * @return string HTML for select options
371 private function _showColumnSelectCell($column_number, $selected = '')
374 $html_output .= '<td class="center">';
375 $html_output .= '<select name="criteriaColumn[' . $column_number
377 $html_output .= '<option value=""> </option>';
378 foreach ($this->_columnNames
as $column) {
379 $html_output .= '<option value="' . htmlspecialchars($column) . '"'
380 . (($column === $selected) ?
' selected="selected"' : '') . '>'
381 . str_replace(' ', ' ', htmlspecialchars($column))
384 $html_output .= '</select>';
385 $html_output .= '</td>';
390 * Provides select options list containing sort options (ASC/DESC)
392 * @param integer $column_number Column Number (0,1,2) or more
393 * @param string $asc_selected Selected criteria 'Ascending'
394 * @param string $desc_selected Selected criteria 'Descending'
396 * @return string HTML for select options
398 private function _getSortSelectCell($column_number, $asc_selected = '',
401 $html_output = '<td class="center">';
402 $html_output .= '<select style="width: ' . $this->_realwidth
403 . '" name="criteriaSort[' . $column_number . ']" size="1">';
404 $html_output .= '<option value=""> </option>';
405 $html_output .= '<option value="ASC"' . $asc_selected . '>'
408 $html_output .= '<option value="DESC"' . $desc_selected . '>'
411 $html_output .= '</select>';
412 $html_output .= '</td>';
417 * Provides select options list containing sort order
419 * @param integer $columnNumber Column Number (0,1,2) or more
420 * @param integer $sortOrder Sort order
422 * @return string HTML for select options
424 private function _getSortOrderSelectCell($columnNumber, $sortOrder)
426 $totalColumnCount = $this->_getNewColumnCount();
427 $html_output = '<td class="center">';
428 $html_output .= '<select name="criteriaSortOrder[' . $columnNumber . ']">';
429 $html_output .= '<option value="1000">'
431 for ($a = 1; $a <= $totalColumnCount; $a++
) {
432 $html_output .= '<option value="' . $a . '"';
433 if ($a == $sortOrder) {
434 $html_output .= ' selected="selected"';
436 $html_output .= '>' . $a . '</option>';
438 $html_output .= '</select>';
439 $html_output .= '</td>';
444 * Returns the new column count after adding and removing columns as instructed
446 * @return int new column count
448 private function _getNewColumnCount()
450 $totalColumnCount = $this->_criteria_column_count
;
451 if (! empty($this->_criteriaColumnInsert
)) {
452 $totalColumnCount +
= count($this->_criteriaColumnInsert
);
454 if (! empty($this->_criteriaColumnDelete
)) {
455 $totalColumnCount -= count($this->_criteriaColumnDelete
);
457 return $totalColumnCount;
461 * Provides search form's row containing column select options
463 * @return string HTML for search table's row
465 private function _getColumnNamesRow()
467 $html_output = '<tr class="noclick">';
468 $html_output .= '<th>' . __('Column:') . '</th>';
469 $new_column_count = 0;
472 $column_index < $this->_criteria_column_count
;
475 if (isset($this->_criteriaColumnInsert
[$column_index])
476 && $this->_criteriaColumnInsert
[$column_index] == 'on'
478 $html_output .= $this->_showColumnSelectCell(
483 if (! empty($this->_criteriaColumnDelete
)
484 && isset($this->_criteriaColumnDelete
[$column_index])
485 && $this->_criteriaColumnDelete
[$column_index] == 'on'
490 if (isset($_REQUEST['criteriaColumn'][$column_index])) {
491 $selected = $_REQUEST['criteriaColumn'][$column_index];
492 $this->_formColumns
[$new_column_count]
493 = $_REQUEST['criteriaColumn'][$column_index];
495 $html_output .= $this->_showColumnSelectCell(
501 $this->_new_column_count
= $new_column_count;
502 $html_output .= '</tr>';
507 * Provides search form's row containing column aliases
509 * @return string HTML for search table's row
511 private function _getColumnAliasRow()
513 $html_output = '<tr class="noclick">';
514 $html_output .= '<th>' . __('Alias:') . '</th>';
515 $new_column_count = 0;
519 $colInd < $this->_criteria_column_count
;
522 if (! empty($this->_criteriaColumnInsert
)
523 && isset($this->_criteriaColumnInsert
[$colInd])
524 && $this->_criteriaColumnInsert
[$colInd] == 'on'
526 $html_output .= '<td class="center">';
527 $html_output .= '<input type="text"'
528 . ' name="criteriaAlias[' . $new_column_count . ']"'
530 $html_output .= '</td>';
534 if (! empty($this->_criteriaColumnDelete
)
535 && isset($this->_criteriaColumnDelete
[$colInd])
536 && $this->_criteriaColumnDelete
[$colInd] == 'on'
542 if (! empty($_REQUEST['criteriaAlias'][$colInd])) {
544 = $this->_formAliases
[$new_column_count]
545 = $_REQUEST['criteriaAlias'][$colInd];
548 $html_output .= '<td class="center">';
549 $html_output .= '<input type="text"'
550 . ' name="criteriaAlias[' . $new_column_count . ']"'
551 . ' value="' . htmlspecialchars($tmp_alias) . '" />';
552 $html_output .= '</td>';
555 $html_output .= '</tr>';
560 * Provides search form's row containing sort(ASC/DESC) select options
562 * @return string HTML for search table's row
564 private function _getSortRow()
566 $html_output = '<tr class="noclick">';
567 $html_output .= '<th>' . __('Sort:') . '</th>';
568 $new_column_count = 0;
572 $colInd < $this->_criteria_column_count
;
575 if (! empty($this->_criteriaColumnInsert
)
576 && isset($this->_criteriaColumnInsert
[$colInd])
577 && $this->_criteriaColumnInsert
[$colInd] == 'on'
579 $html_output .= $this->_getSortSelectCell($new_column_count);
583 if (! empty($this->_criteriaColumnDelete
)
584 && isset($this->_criteriaColumnDelete
[$colInd])
585 && $this->_criteriaColumnDelete
[$colInd] == 'on'
589 // If they have chosen all fields using the * selector,
590 // then sorting is not available, Fix for Bug #570698
591 if (isset($_REQUEST['criteriaSort'][$colInd])
592 && isset($_REQUEST['criteriaColumn'][$colInd])
593 && mb_substr($_REQUEST['criteriaColumn'][$colInd], -2) == '.*'
595 $_REQUEST['criteriaSort'][$colInd] = '';
598 $asc_selected = ''; $desc_selected = '';
599 if (isset($_REQUEST['criteriaSort'][$colInd])) {
600 $this->_formSorts
[$new_column_count]
601 = $_REQUEST['criteriaSort'][$colInd];
603 if ($_REQUEST['criteriaSort'][$colInd] == 'ASC') {
604 $asc_selected = ' selected="selected"';
607 if ($_REQUEST['criteriaSort'][$colInd] == 'DESC') {
608 $desc_selected = ' selected="selected"';
611 $this->_formSorts
[$new_column_count] = '';
614 $html_output .= $this->_getSortSelectCell(
615 $new_column_count, $asc_selected, $desc_selected
619 $html_output .= '</tr>';
624 * Provides search form's row containing sort order
626 * @return string HTML for search table's row
628 private function _getSortOrder()
630 $html_output = '<tr class="noclick">';
631 $html_output .= '<th>' . __('Sort order:') . '</th>';
632 $new_column_count = 0;
636 $colInd < $this->_criteria_column_count
;
639 if (! empty($this->_criteriaColumnInsert
)
640 && isset($this->_criteriaColumnInsert
[$colInd])
641 && $this->_criteriaColumnInsert
[$colInd] == 'on'
643 $html_output .= $this->_getSortOrderSelectCell(
644 $new_column_count, null
649 if (! empty($this->_criteriaColumnDelete
)
650 && isset($this->_criteriaColumnDelete
[$colInd])
651 && $this->_criteriaColumnDelete
[$colInd] == 'on'
657 if (! empty($_REQUEST['criteriaSortOrder'][$colInd])) {
659 = $this->_formSortOrders
[$new_column_count]
660 = $_REQUEST['criteriaSortOrder'][$colInd];
663 $html_output .= $this->_getSortOrderSelectCell(
664 $new_column_count, $sortOrder
668 $html_output .= '</tr>';
673 * Provides search form's row containing SHOW checkboxes
675 * @return string HTML for search table's row
677 private function _getShowRow()
679 $html_output = '<tr class="noclick">';
680 $html_output .= '<th>' . __('Show:') . '</th>';
681 $new_column_count = 0;
684 $column_index < $this->_criteria_column_count
;
687 if (! empty($this->_criteriaColumnInsert
)
688 && isset($this->_criteriaColumnInsert
[$column_index])
689 && $this->_criteriaColumnInsert
[$column_index] == 'on'
691 $html_output .= '<td class="center">';
692 $html_output .= '<input type="checkbox"'
693 . ' name="criteriaShow[' . $new_column_count . ']" />';
694 $html_output .= '</td>';
697 if (! empty($this->_criteriaColumnDelete
)
698 && isset($this->_criteriaColumnDelete
[$column_index])
699 && $this->_criteriaColumnDelete
[$column_index] == 'on'
703 if (isset($_REQUEST['criteriaShow'][$column_index])) {
704 $checked_options = ' checked="checked"';
705 $this->_formShows
[$new_column_count]
706 = $_REQUEST['criteriaShow'][$column_index];
708 $checked_options = '';
710 $html_output .= '<td class="center">';
711 $html_output .= '<input type="checkbox"'
712 . ' name="criteriaShow[' . $new_column_count . ']"'
713 . $checked_options . ' />';
714 $html_output .= '</td>';
717 $html_output .= '</tr>';
722 * Provides search form's row containing criteria Inputboxes
724 * @return string HTML for search table's row
726 private function _getCriteriaInputboxRow()
728 $html_output = '<tr class="noclick">';
729 $html_output .= '<th>' . __('Criteria:') . '</th>';
730 $new_column_count = 0;
733 $column_index < $this->_criteria_column_count
;
736 if (! empty($this->_criteriaColumnInsert
)
737 && isset($this->_criteriaColumnInsert
[$column_index])
738 && $this->_criteriaColumnInsert
[$column_index] == 'on'
740 $html_output .= '<td class="center">';
741 $html_output .= '<input type="text"'
742 . ' name="criteria[' . $new_column_count . ']"'
744 . ' class="textfield"'
745 . ' style="width: ' . $this->_realwidth
. '"'
747 $html_output .= '</td>';
750 if (! empty($this->_criteriaColumnDelete
)
751 && isset($this->_criteriaColumnDelete
[$column_index])
752 && $this->_criteriaColumnDelete
[$column_index] == 'on'
756 if (isset($this->_criteria
[$column_index])) {
757 $tmp_criteria = $this->_criteria
[$column_index];
759 if ((empty($this->_prev_criteria
)
760 ||
! isset($this->_prev_criteria
[$column_index]))
761 ||
$this->_prev_criteria
[$column_index] != htmlspecialchars($tmp_criteria)
763 $this->_formCriterions
[$new_column_count] = $tmp_criteria;
765 $this->_formCriterions
[$new_column_count]
766 = $this->_prev_criteria
[$column_index];
768 $html_output .= '<td class="center">';
769 $html_output .= '<input type="hidden"'
770 . ' name="prev_criteria[' . $new_column_count . ']"'
772 . htmlspecialchars($this->_formCriterions
[$new_column_count])
774 $html_output .= '<input type="text"'
775 . ' name="criteria[' . $new_column_count . ']"'
776 . ' value="' . htmlspecialchars($tmp_criteria) . '"'
777 . ' class="textfield"'
778 . ' style="width: ' . $this->_realwidth
. '"'
780 $html_output .= '</td>';
783 $html_output .= '</tr>';
788 * Provides footer options for adding/deleting row/columns
790 * @param string $type Whether row or column
792 * @return string HTML for footer options
794 private function _getFootersOptions($type)
796 $html_output = '<div class="floatleft">';
797 $html_output .= (($type == 'row')
798 ?
__('Add/Delete criteria rows') : __('Add/Delete columns'));
799 $html_output .= ':<select size="1" name="'
800 . (($type == 'row') ?
'criteriaRowAdd' : 'criteriaColumnAdd') . '">';
801 $html_output .= '<option value="-3">-3</option>';
802 $html_output .= '<option value="-2">-2</option>';
803 $html_output .= '<option value="-1">-1</option>';
804 $html_output .= '<option value="0" selected="selected">0</option>';
805 $html_output .= '<option value="1">1</option>';
806 $html_output .= '<option value="2">2</option>';
807 $html_output .= '<option value="3">3</option>';
808 $html_output .= '</select>';
809 $html_output .= '</div>';
814 * Provides search form table's footer options
816 * @return string HTML for table footer
818 private function _getTableFooters()
820 $html_output = '<fieldset class="tblFooters">';
821 $html_output .= $this->_getFootersOptions("row");
822 $html_output .= $this->_getFootersOptions("column");
823 $html_output .= '<div class="floatleft">';
824 $html_output .= '<input type="submit" name="modify"'
825 . 'value="' . __('Update Query') . '" />';
826 $html_output .= '</div>';
827 $html_output .= '</fieldset>';
832 * Provides a select list of database tables
834 * @return string HTML for table select list
836 private function _getTablesList()
838 $html_output = '<div class="floatleft">';
839 $html_output .= '<fieldset>';
840 $html_output .= '<legend>' . __('Use Tables') . '</legend>';
841 // Build the options list for each table name
843 $numTableListOptions = 0;
844 foreach ($this->_criteriaTables
as $key => $val) {
845 $options .= '<option value="' . htmlspecialchars($key) . '"' . $val . '>'
846 . (str_replace(' ', ' ', htmlspecialchars($key))) . '</option>';
847 $numTableListOptions++
;
849 $html_output .= '<select name="TableList[]"'
850 . ' multiple="multiple" id="listTable"'
851 . ' size="' . (($numTableListOptions > 30) ?
'15' : '7') . '">';
852 $html_output .= $options;
853 $html_output .= '</select>';
854 $html_output .= '</fieldset>';
855 $html_output .= '<fieldset class="tblFooters">';
856 $html_output .= '<input type="submit" name="modify" value="'
857 . __('Update Query') . '" />';
858 $html_output .= '</fieldset>';
859 $html_output .= '</div>';
864 * Provides And/Or modification cell along with Insert/Delete options
865 * (For modifying search form's table columns)
867 * @param integer $column_number Column Number (0,1,2) or more
868 * @param array $selected Selected criteria column name
869 * @param bool $last_column Whether this is the last column
871 * @return string HTML for modification cell
873 private function _getAndOrColCell(
874 $column_number, $selected = null, $last_column = false
876 $html_output = '<td class="center">';
877 if (! $last_column) {
878 $html_output .= '<strong>' . __('Or:') . '</strong>';
879 $html_output .= '<input type="radio"'
880 . ' name="criteriaAndOrColumn[' . $column_number . ']"'
881 . ' value="or"' . $selected['or'] . ' />';
882 $html_output .= ' <strong>' . __('And:') . '</strong>';
883 $html_output .= '<input type="radio"'
884 . ' name="criteriaAndOrColumn[' . $column_number . ']"'
885 . ' value="and"' . $selected['and'] . ' />';
887 $html_output .= '<br />' . __('Ins');
888 $html_output .= '<input type="checkbox"'
889 . ' name="criteriaColumnInsert[' . $column_number . ']" />';
890 $html_output .= ' ' . __('Del');
891 $html_output .= '<input type="checkbox"'
892 . ' name="criteriaColumnDelete[' . $column_number . ']" />';
893 $html_output .= '</td>';
898 * Provides search form's row containing column modifications options
899 * (For modifying search form's table columns)
901 * @return string HTML for search table's row
903 private function _getModifyColumnsRow()
905 $html_output = '<tr class="noclick">';
906 $html_output .= '<th>' . __('Modify:') . '</th>';
907 $new_column_count = 0;
910 $column_index < $this->_criteria_column_count
;
913 if (! empty($this->_criteriaColumnInsert
)
914 && isset($this->_criteriaColumnInsert
[$column_index])
915 && $this->_criteriaColumnInsert
[$column_index] == 'on'
917 $html_output .= $this->_getAndOrColCell($new_column_count);
921 if (! empty($this->_criteriaColumnDelete
)
922 && isset($this->_criteriaColumnDelete
[$column_index])
923 && $this->_criteriaColumnDelete
[$column_index] == 'on'
928 if (isset($this->_criteriaAndOrColumn
[$column_index])) {
929 $this->_formAndOrCols
[$new_column_count]
930 = $this->_criteriaAndOrColumn
[$column_index];
932 $checked_options = array();
933 if (isset($this->_criteriaAndOrColumn
[$column_index])
934 && $this->_criteriaAndOrColumn
[$column_index] == 'or'
936 $checked_options['or'] = ' checked="checked"';
937 $checked_options['and'] = '';
939 $checked_options['and'] = ' checked="checked"';
940 $checked_options['or'] = '';
942 $html_output .= $this->_getAndOrColCell(
945 ($column_index +
1 == $this->_criteria_column_count
)
949 $html_output .= '</tr>';
954 * Provides Insert/Delete options for criteria inputbox
955 * with AND/OR relationship modification options
957 * @param integer $row_index Number of criteria row
958 * @param array $checked_options If checked
960 * @return string HTML
962 private function _getInsDelAndOrCell($row_index, $checked_options)
964 $html_output = '<td class="' . $GLOBALS['cell_align_right'] . ' nowrap">';
965 $html_output .= '<!-- Row controls -->';
966 $html_output .= '<table class="nospacing nopadding">';
967 $html_output .= '<tr>';
968 $html_output .= '<td class="' . $GLOBALS['cell_align_right'] . ' nowrap">';
969 $html_output .= '<small>' . __('Ins:') . '</small>';
970 $html_output .= '<input type="checkbox"'
971 . ' name="criteriaRowInsert[' . $row_index . ']" />';
972 $html_output .= '</td>';
973 $html_output .= '<td class="' . $GLOBALS['cell_align_right'] . '">';
974 $html_output .= '<strong>' . __('And:') . '</strong>';
975 $html_output .= '</td>';
976 $html_output .= '<td>';
977 $html_output .= '<input type="radio"'
978 . ' name="criteriaAndOrRow[' . $row_index . ']" value="and"'
979 . $checked_options['and'] . ' />';
980 $html_output .= '</td>';
981 $html_output .= '</tr>';
982 $html_output .= '<tr>';
983 $html_output .= '<td class="' . $GLOBALS['cell_align_right'] . ' nowrap">';
984 $html_output .= '<small>' . __('Del:') . '</small>';
985 $html_output .= '<input type="checkbox"'
986 . ' name="criteriaRowDelete[' . $row_index . ']" />';
987 $html_output .= '</td>';
988 $html_output .= '<td class="' . $GLOBALS['cell_align_right'] . '">';
989 $html_output .= '<strong>' . __('Or:') . '</strong>';
990 $html_output .= '</td>';
991 $html_output .= '<td>';
992 $html_output .= '<input type="radio"'
993 . ' name="criteriaAndOrRow[' . $row_index . ']"'
994 . ' value="or"' . $checked_options['or'] . ' />';
995 $html_output .= '</td>';
996 $html_output .= '</tr>';
997 $html_output .= '</table>';
998 $html_output .= '</td>';
1003 * Provides rows for criteria inputbox Insert/Delete options
1004 * with AND/OR relationship modification options
1006 * @param integer $new_row_index New row index if rows are added/deleted
1008 * @return string HTML table rows
1010 private function _getInputboxRow($new_row_index)
1013 $new_column_count = 0;
1016 $column_index < $this->_criteria_column_count
;
1019 if (!empty($this->_criteriaColumnInsert
)
1020 && isset($this->_criteriaColumnInsert
[$column_index])
1021 && $this->_criteriaColumnInsert
[$column_index] == 'on'
1023 $orFieldName = 'Or' . $new_row_index . '[' . $new_column_count . ']';
1024 $html_output .= '<td class="center">';
1025 $html_output .= '<input type="text"'
1026 . ' name="Or' . $orFieldName . '" class="textfield"'
1027 . ' style="width: ' . $this->_realwidth
. '" size="20" />';
1028 $html_output .= '</td>';
1029 $new_column_count++
;
1031 if (!empty($this->_criteriaColumnDelete
)
1032 && isset($this->_criteriaColumnDelete
[$column_index])
1033 && $this->_criteriaColumnDelete
[$column_index] == 'on'
1037 $or = 'Or' . $new_row_index;
1038 if (! empty($_REQUEST[$or]) && isset($_REQUEST[$or][$column_index])) {
1039 $tmp_or = $_REQUEST[$or][$column_index];
1043 $html_output .= '<td class="center">';
1044 $html_output .= '<input type="text"'
1045 . ' name="Or' . $new_row_index . '[' . $new_column_count . ']' . '"'
1046 . ' value="' . htmlspecialchars($tmp_or) . '" class="textfield"'
1047 . ' style="width: ' . $this->_realwidth
. '" size="20" />';
1048 $html_output .= '</td>';
1049 if (!empty($
{$or}) && isset($
{$or}[$column_index])) {
1050 $GLOBALS[$
{'cur' . $or}][$new_column_count]
1051 = $
{$or}[$column_index];
1053 $new_column_count++
;
1055 return $html_output;
1059 * Provides rows for criteria inputbox Insert/Delete options
1060 * with AND/OR relationship modification options
1062 * @return string HTML table rows
1064 private function _getInsDelAndOrCriteriaRows()
1068 $checked_options = array();
1071 $row_index <= $this->_criteria_row_count
;
1074 if (isset($this->_criteriaRowInsert
[$row_index])
1075 && $this->_criteriaRowInsert
[$row_index] == 'on'
1077 $checked_options['or'] = ' checked="checked"';
1078 $checked_options['and'] = '';
1079 $html_output .= '<tr class="noclick">';
1080 $html_output .= $this->_getInsDelAndOrCell(
1081 $new_row_count, $checked_options
1083 $html_output .= $this->_getInputboxRow(
1087 $html_output .= '</tr>';
1089 if (isset($this->_criteriaRowDelete
[$row_index])
1090 && $this->_criteriaRowDelete
[$row_index] == 'on'
1094 if (isset($this->_criteriaAndOrRow
[$row_index])) {
1095 $this->_formAndOrRows
[$new_row_count]
1096 = $this->_criteriaAndOrRow
[$row_index];
1098 if (isset($this->_criteriaAndOrRow
[$row_index])
1099 && $this->_criteriaAndOrRow
[$row_index] == 'and'
1101 $checked_options['and'] = ' checked="checked"';
1102 $checked_options['or'] = '';
1104 $checked_options['or'] = ' checked="checked"';
1105 $checked_options['and'] = '';
1107 $html_output .= '<tr class="noclick">';
1108 $html_output .= $this->_getInsDelAndOrCell(
1109 $new_row_count, $checked_options
1111 $html_output .= $this->_getInputboxRow(
1115 $html_output .= '</tr>';
1117 $this->_new_row_count
= $new_row_count;
1118 return $html_output;
1122 * Provides SELECT clause for building SQL query
1124 * @return string Select clause
1126 private function _getSelectClause()
1128 $select_clause = '';
1129 $select_clauses = array();
1132 $column_index < $this->_criteria_column_count
;
1135 if (! empty($this->_formColumns
[$column_index])
1136 && isset($this->_formShows
[$column_index])
1137 && $this->_formShows
[$column_index] == 'on'
1139 $select = $this->_formColumns
[$column_index];
1140 if (! empty($this->_formAliases
[$column_index])) {
1142 . Util
::backquote($this->_formAliases
[$column_index]);
1144 $select_clauses[] = $select;
1147 if (!empty($select_clauses)) {
1148 $select_clause = 'SELECT '
1149 . htmlspecialchars(implode(", ", $select_clauses)) . "\n";
1151 return $select_clause;
1155 * Provides WHERE clause for building SQL query
1157 * @return string Where clause
1159 private function _getWhereClause()
1165 $column_index < $this->_criteria_column_count
;
1168 if (! empty($this->_formColumns
[$column_index])
1169 && ! empty($this->_formCriterions
[$column_index])
1171 && isset($last_where)
1172 && isset($this->_formAndOrCols
)
1174 $where_clause .= ' '
1175 . mb_strtoupper($this->_formAndOrCols
[$last_where])
1178 if (! empty($this->_formColumns
[$column_index])
1179 && ! empty($this->_formCriterions
[$column_index])
1181 $where_clause .= '(' . $this->_formColumns
[$column_index] . ' '
1182 . $this->_formCriterions
[$column_index] . ')';
1183 $last_where = $column_index;
1187 if ($criteria_cnt > 1) {
1188 $where_clause = '(' . $where_clause . ')';
1190 // OR rows ${'cur' . $or}[$column_index]
1191 if (! isset($this->_formAndOrRows
)) {
1192 $this->_formAndOrRows
= array();
1196 $row_index <= $this->_criteria_row_count
;
1204 $column_index < $this->_criteria_column_count
;
1207 if (! empty($this->_formColumns
[$column_index])
1208 && ! empty($_REQUEST['Or' . $row_index][$column_index])
1213 $this->_formAndOrCols
[$last_orwhere]
1217 if (! empty($this->_formColumns
[$column_index])
1218 && ! empty($_REQUEST['Or' . $row_index][$column_index])
1220 $qry_orwhere .= '(' . $this->_formColumns
[$column_index]
1222 . $_REQUEST['Or' . $row_index][$column_index]
1224 $last_orwhere = $column_index;
1228 if ($criteria_cnt > 1) {
1229 $qry_orwhere = '(' . $qry_orwhere . ')';
1231 if (! empty($qry_orwhere)) {
1232 $where_clause .= "\n"
1234 isset($this->_formAndOrRows
[$row_index])
1235 ?
$this->_formAndOrRows
[$row_index] . ' '
1242 if (! empty($where_clause) && $where_clause != '()') {
1243 $where_clause = 'WHERE ' . htmlspecialchars($where_clause) . "\n";
1245 return $where_clause;
1249 * Provides ORDER BY clause for building SQL query
1251 * @return string Order By clause
1253 private function _getOrderByClause()
1255 $orderby_clause = '';
1256 $orderby_clauses = array();
1258 // Create copy of instance variables
1259 $columns = $this->_formColumns
;
1260 $sort = $this->_formSorts
;
1261 $sortOrder = $this->_formSortOrders
;
1262 if (!empty($sortOrder)
1263 && count($sortOrder) == count($sort)
1264 && count($sortOrder) == count($columns)
1266 // Sort all three arrays based on sort order
1267 array_multisort($sortOrder, $sort, $columns);
1272 $column_index < $this->_criteria_column_count
;
1275 // if all columns are chosen with * selector,
1276 // then sorting isn't available
1277 // Fix for Bug #570698
1278 if (empty($columns[$column_index])
1279 && empty($sort[$column_index])
1284 if (mb_substr($columns[$column_index], -2) == '.*') {
1288 if (! empty($sort[$column_index])) {
1289 $orderby_clauses[] = $columns[$column_index] . ' '
1290 . $sort[$column_index];
1293 if (!empty($orderby_clauses)) {
1294 $orderby_clause = 'ORDER BY '
1295 . htmlspecialchars(implode(", ", $orderby_clauses)) . "\n";
1297 return $orderby_clause;
1301 * Provides UNIQUE columns and INDEX columns present in criteria tables
1303 * @param array $search_tables Tables involved in the search
1304 * @param array $search_columns Columns involved in the search
1305 * @param array $where_clause_columns Columns having criteria where clause
1307 * @return array having UNIQUE and INDEX columns
1309 private function _getIndexes($search_tables, $search_columns,
1310 $where_clause_columns
1312 $unique_columns = array();
1313 $index_columns = array();
1315 foreach ($search_tables as $table) {
1316 $indexes = $GLOBALS['dbi']->getTableIndexes($this->_db
, $table);
1317 foreach ($indexes as $index) {
1318 $column = $table . '.' . $index['Column_name'];
1319 if (isset($search_columns[$column])) {
1320 if ($index['Non_unique'] == 0) {
1321 if (isset($where_clause_columns[$column])) {
1322 $unique_columns[$column] = 'Y';
1324 $unique_columns[$column] = 'N';
1327 if (isset($where_clause_columns[$column])) {
1328 $index_columns[$column] = 'Y';
1330 $index_columns[$column] = 'N';
1334 } // end while (each index of a table)
1335 } // end while (each table)
1338 'unique' => $unique_columns,
1339 'index' => $index_columns
1344 * Provides UNIQUE columns and INDEX columns present in criteria tables
1346 * @param array $search_tables Tables involved in the search
1347 * @param array $search_columns Columns involved in the search
1348 * @param array $where_clause_columns Columns having criteria where clause
1350 * @return array having UNIQUE and INDEX columns
1352 private function _getLeftJoinColumnCandidates($search_tables, $search_columns,
1353 $where_clause_columns
1355 $GLOBALS['dbi']->selectDb($this->_db
);
1357 // Get unique columns and index columns
1358 $indexes = $this->_getIndexes(
1359 $search_tables, $search_columns, $where_clause_columns
1361 $unique_columns = $indexes['unique'];
1362 $index_columns = $indexes['index'];
1364 list($candidate_columns, $needsort)
1365 = $this->_getLeftJoinColumnCandidatesBest(
1367 $where_clause_columns,
1372 // If we came up with $unique_columns (very good) or $index_columns (still
1373 // good) as $candidate_columns we want to check if we have any 'Y' there
1374 // (that would mean that they were also found in the whereclauses
1375 // which would be great). if yes, we take only those
1376 if ($needsort != 1) {
1377 return $candidate_columns;
1380 $very_good = array();
1381 $still_good = array();
1382 foreach ($candidate_columns as $column => $is_where) {
1383 $table = explode('.', $column);
1385 if ($is_where == 'Y') {
1386 $very_good[$column] = $table;
1388 $still_good[$column] = $table;
1391 if (count($very_good) > 0) {
1392 $candidate_columns = $very_good;
1393 // Candidates restricted in index+where
1395 $candidate_columns = $still_good;
1396 // None of the candidates where in a where-clause
1399 return $candidate_columns;
1403 * Provides the main table to form the LEFT JOIN clause
1405 * @param array $search_tables Tables involved in the search
1406 * @param array $search_columns Columns involved in the search
1407 * @param array $where_clause_columns Columns having criteria where clause
1408 * @param array $where_clause_tables Tables having criteria where clause
1410 * @return string table name
1412 private function _getMasterTable($search_tables, $search_columns,
1413 $where_clause_columns, $where_clause_tables
1415 if (count($where_clause_tables) == 1) {
1416 // If there is exactly one column that has a decent where-clause
1417 // we will just use this
1418 $master = key($where_clause_tables);
1422 // Now let's find out which of the tables has an index
1423 // (When the control user is the same as the normal user
1424 // because he is using one of his databases as pmadb,
1425 // the last db selected is not always the one where we need to work)
1426 $candidate_columns = $this->_getLeftJoinColumnCandidates(
1427 $search_tables, $search_columns, $where_clause_columns
1430 // Generally, we need to display all the rows of foreign (referenced)
1431 // table, whether they have any matching row in child table or not.
1432 // So we select candidate tables which are foreign tables.
1433 $foreign_tables = array();
1434 foreach ($candidate_columns as $one_table) {
1435 $foreigners = PMA_getForeigners($this->_db
, $one_table);
1436 foreach ($foreigners as $key => $foreigner) {
1437 if ($key != 'foreign_keys_data') {
1438 if (in_array($foreigner['foreign_table'], $candidate_columns)) {
1439 $foreign_tables[$foreigner['foreign_table']]
1440 = $foreigner['foreign_table'];
1444 foreach ($foreigner as $one_key) {
1445 if (in_array($one_key['ref_table_name'], $candidate_columns)) {
1446 $foreign_tables[$one_key['ref_table_name']]
1447 = $one_key['ref_table_name'];
1452 if (count($foreign_tables)) {
1453 $candidate_columns = $foreign_tables;
1456 // If our array of candidates has more than one member we'll just
1457 // find the smallest table.
1458 // Of course the actual query would be faster if we check for
1459 // the Criteria which gives the smallest result set in its table,
1460 // but it would take too much time to check this
1461 if (!(count($candidate_columns) > 1)) {
1462 // Only one single candidate
1463 return reset($candidate_columns);
1466 // Of course we only want to check each table once
1467 $checked_tables = $candidate_columns;
1471 foreach ($candidate_columns as $table) {
1472 if ($checked_tables[$table] != 1) {
1473 $_table = new Table($table, $this->_db
);
1474 $tsize[$table] = $_table->countRecords();
1475 $checked_tables[$table] = 1;
1477 if ($tsize[$table] > $maxsize) {
1478 $maxsize = $tsize[$table];
1482 // Return largest table
1487 * Provides columns and tables that have valid where clause criteria
1491 private function _getWhereClauseTablesAndColumns()
1493 $where_clause_columns = array();
1494 $where_clause_tables = array();
1496 // Now we need all tables that we have in the where clause
1498 $column_index = 0, $nb = count($this->_criteria
);
1499 $column_index < $nb;
1502 $current_table = explode('.', $_POST['criteriaColumn'][$column_index]);
1503 if (empty($current_table[0]) ||
empty($current_table[1])) {
1506 $table = str_replace('`', '', $current_table[0]);
1507 $column = str_replace('`', '', $current_table[1]);
1508 $column = $table . '.' . $column;
1509 // Now we know that our array has the same numbers as $criteria
1510 // we can check which of our columns has a where clause
1511 if (! empty($this->_criteria
[$column_index])) {
1512 if (mb_substr($this->_criteria
[$column_index], 0, 1) == '='
1513 ||
stristr($this->_criteria
[$column_index], 'is')
1515 $where_clause_columns[$column] = $column;
1516 $where_clause_tables[$table] = $table;
1521 'where_clause_tables' => $where_clause_tables,
1522 'where_clause_columns' => $where_clause_columns
1527 * Provides FROM clause for building SQL query
1529 * @param array $formColumns List of selected columns in the form
1531 * @return string FROM clause
1533 private function _getFromClause($formColumns)
1536 if (empty($formColumns)) {
1537 return $from_clause;
1540 // Initialize some variables
1541 $search_tables = $search_columns = array();
1543 // We only start this if we have fields, otherwise it would be dumb
1544 foreach ($formColumns as $value) {
1545 $parts = explode('.', $value);
1546 if (! empty($parts[0]) && ! empty($parts[1])) {
1547 $table = str_replace('`', '', $parts[0]);
1548 $search_tables[$table] = $table;
1549 $search_columns[] = $table . '.' . str_replace(
1555 // Create LEFT JOINS out of Relations
1556 $from_clause = $this->_getJoinForFromClause(
1557 $search_tables, $search_columns
1560 // In case relations are not defined, just generate the FROM clause
1561 // from the list of tables, however we don't generate any JOIN
1562 if (empty($from_clause)) {
1563 // Create cartesian product
1564 $from_clause = implode(
1565 ", ", array_map(array('PMA\libraries\Util', 'backquote'), $search_tables)
1569 return $from_clause;
1573 * Formulates the WHERE clause by JOINing tables
1575 * @param array $searchTables Tables involved in the search
1576 * @param array $searchColumns Columns involved in the search
1578 * @return string table name
1580 private function _getJoinForFromClause($searchTables, $searchColumns)
1582 // $relations[master_table][foreign_table] => clause
1583 $relations = array();
1585 // Fill $relations with inter table relationship data
1586 foreach ($searchTables as $oneTable) {
1587 $this->_loadRelationsForTable($relations, $oneTable);
1590 // Get tables and columns with valid where clauses
1591 $validWhereClauses = $this->_getWhereClauseTablesAndColumns();
1592 $whereClauseTables = $validWhereClauses['where_clause_tables'];
1593 $whereClauseColumns = $validWhereClauses['where_clause_columns'];
1596 $master = $this->_getMasterTable(
1597 $searchTables, $searchColumns,
1598 $whereClauseColumns, $whereClauseTables
1601 // Will include master tables and all tables that can be combined into
1602 // a cluster by their relation
1603 $finalized = array();
1604 if (strlen($master) > 0) {
1605 // Add master tables
1606 $finalized[$master] = '';
1608 // Fill the $finalized array with JOIN clauses for each table
1609 $this->_fillJoinClauses($finalized, $relations, $searchTables);
1614 // Tables that can not be combined with the table cluster
1615 // which includes master table
1616 $unfinalized = array_diff($searchTables, array_keys($finalized));
1617 if (count($unfinalized) > 0) {
1619 // We need to look for intermediary tables to JOIN unfinalized tables
1620 // Heuristic to chose intermediary tables is to look for tables
1621 // having relationships with unfinalized tables
1622 foreach ($unfinalized as $oneTable) {
1624 $references = PMA_getChildReferences($this->_db
, $oneTable);
1625 foreach ($references as $column => $columnReferences) {
1626 foreach ($columnReferences as $reference) {
1628 // Only from this schema
1629 if ($reference['table_schema'] != $this->_db
) {
1633 $table = $reference['table_name'];
1635 $this->_loadRelationsForTable($relations, $table);
1638 $tempFinalized = $finalized;
1639 $tempSearchTables = $searchTables;
1640 $tempSearchTables[] = $table;
1642 // Try joining with the added table
1643 $this->_fillJoinClauses(
1644 $tempFinalized, $relations, $tempSearchTables
1647 $tempUnfinalized = array_diff(
1648 $tempSearchTables, array_keys($tempFinalized)
1650 // Take greedy approach.
1651 // If the unfinalized count drops we keep the new table
1652 // and switch temporary varibles with the original ones
1653 if (count($tempUnfinalized) < count($unfinalized)) {
1654 $finalized = $tempFinalized;
1655 $searchTables = $tempSearchTables;
1658 // We are done if no unfinalized tables anymore
1659 if (count($tempUnfinalized) == 0) {
1666 $unfinalized = array_diff($searchTables, array_keys($finalized));
1667 // If there are still unfinalized tables
1668 if (count($unfinalized) > 0) {
1669 // Add these tables as cartesian product before joined tables
1671 ', ', array_map(array('PMA\libraries\Util', 'backquote'), $unfinalized)
1677 // Add joined tables
1678 foreach ($finalized as $table => $clause) {
1680 if (! empty($join)) {
1683 $join .= Util
::backquote($table);
1686 $join .= "\n LEFT JOIN " . Util
::backquote(
1688 ) . " ON " . $clause;
1696 * Loads relations for a given table into the $relations array
1698 * @param array &$relations array of relations
1699 * @param string $oneTable the table
1703 private function _loadRelationsForTable(&$relations, $oneTable)
1705 $relations[$oneTable] = array();
1707 $foreigners = PMA_getForeigners($GLOBALS['db'], $oneTable);
1708 foreach ($foreigners as $field => $foreigner) {
1709 // Foreign keys data
1710 if ($field == 'foreign_keys_data') {
1711 foreach ($foreigner as $oneKey) {
1713 // There may be multiple column relations
1714 foreach ($oneKey['index_list'] as $index => $oneField) {
1716 = Util
::backquote($oneTable) . "."
1717 . Util
::backquote($oneField) . " = "
1718 . Util
::backquote($oneKey['ref_table_name']) . "."
1719 . Util
::backquote($oneKey['ref_index_list'][$index]);
1721 // Combine multiple column relations with AND
1722 $relations[$oneTable][$oneKey['ref_table_name']]
1723 = implode(" AND ", $clauses);
1725 } else { // Internal relations
1726 $relations[$oneTable][$foreigner['foreign_table']]
1727 = Util
::backquote($oneTable) . "."
1728 . Util
::backquote($field) . " = "
1729 . Util
::backquote($foreigner['foreign_table']) . "."
1730 . Util
::backquote($foreigner['foreign_field']);
1736 * Fills the $finalized arrays with JOIN clauses for each of the tables
1738 * @param array &$finalized JOIN clauses for each table
1739 * @param array $relations Relations among tables
1740 * @param array $searchTables Tables involved in the search
1744 private function _fillJoinClauses(&$finalized, $relations, $searchTables)
1748 foreach ($searchTables as $masterTable) {
1749 $foreignData = $relations[$masterTable];
1750 foreach ($foreignData as $foreignTable => $clause) {
1751 if (! isset($finalized[$masterTable])
1752 && isset($finalized[$foreignTable])
1754 $finalized[$masterTable] = $clause;
1756 } elseif (! isset($finalized[$foreignTable])
1757 && isset($finalized[$masterTable])
1758 && in_array($foreignTable, $searchTables)
1760 $finalized[$foreignTable] = $clause;
1764 // We are done if all tables are in $finalized
1765 if (count($finalized) == count($searchTables)) {
1771 // If no new tables were added during this iteration, break;
1779 * Provides the generated SQL query
1781 * @param array $formColumns List of selected columns in the form
1783 * @return string SQL query
1785 private function _getSQLQuery($formColumns)
1788 // get SELECT clause
1789 $sql_query .= $this->_getSelectClause();
1791 $from_clause = $this->_getFromClause($formColumns);
1792 if (! empty($from_clause)) {
1793 $sql_query .= 'FROM ' . htmlspecialchars($from_clause) . "\n";
1796 $sql_query .= $this->_getWhereClause();
1797 // get ORDER BY clause
1798 $sql_query .= $this->_getOrderByClause();
1803 * Provides the generated QBE form
1805 * @return string QBE form
1807 public function getSelectionForm()
1809 $html_output = '<form action="db_qbe.php" method="post" id="formQBE" '
1810 . 'class="lock-page">';
1811 $html_output .= '<fieldset>';
1813 if ($GLOBALS['cfgRelation']['savedsearcheswork']) {
1814 $html_output .= $this->_getSavedSearchesField();
1817 $html_output .= '<table class="data" style="width: 100%;">';
1818 // Get table's <tr> elements
1819 $html_output .= $this->_getColumnNamesRow();
1820 $html_output .= $this->_getColumnAliasRow();
1821 $html_output .= $this->_getShowRow();
1822 $html_output .= $this->_getSortRow();
1823 $html_output .= $this->_getSortOrder();
1824 $html_output .= $this->_getCriteriaInputboxRow();
1825 $html_output .= $this->_getInsDelAndOrCriteriaRows();
1826 $html_output .= $this->_getModifyColumnsRow();
1827 $html_output .= '</table>';
1828 $this->_new_row_count
--;
1829 $url_params = array();
1830 $url_params['db'] = $this->_db
;
1831 $url_params['criteriaColumnCount'] = $this->_new_column_count
;
1832 $url_params['rows'] = $this->_new_row_count
;
1833 $html_output .= URL
::getHiddenInputs($url_params);
1834 $html_output .= '</fieldset>';
1836 $html_output .= $this->_getTableFooters();
1837 // get tables select list
1838 $html_output .= $this->_getTablesList();
1839 $html_output .= '</form>';
1840 $html_output .= '<form action="db_qbe.php" method="post" class="lock-page">';
1841 $html_output .= URL
::getHiddenInputs(array('db' => $this->_db
));
1843 $html_output .= '<div class="floatleft" style="width:50%">';
1844 $html_output .= '<fieldset>';
1845 $html_output .= '<legend>'
1847 __('SQL query on database <b>%s</b>:'),
1848 Util
::getDbLink($this->_db
)
1850 $html_output .= '</legend>';
1852 $html_output .= '<textarea cols="80" name="sql_query" id="textSqlquery"'
1853 . ' rows="' . ((count($this->_criteriaTables
) > 30) ?
'15' : '7') . '"'
1854 . ' dir="' . $text_dir . '">';
1856 if (empty($this->_formColumns
)) {
1857 $this->_formColumns
= array();
1859 $html_output .= $this->_getSQLQuery($this->_formColumns
);
1861 $html_output .= '</textarea>';
1862 $html_output .= '</fieldset>';
1863 // displays form's footers
1864 $html_output .= '<fieldset class="tblFooters">';
1865 $html_output .= '<input type="hidden" name="submit_sql" value="1" />';
1866 $html_output .= '<input type="submit" value="' . __('Submit Query') . '" />';
1867 $html_output .= '</fieldset>';
1868 $html_output .= '</div>';
1869 $html_output .= '</form>';
1870 return $html_output;
1874 * Get fields to display
1878 private function _getSavedSearchesField()
1880 $html_output = __('Saved bookmarked search:');
1881 $html_output .= ' <select name="searchId" id="searchId">';
1882 $html_output .= '<option value="">' . __('New bookmark') . '</option>';
1884 $currentSearch = $this->_getCurrentSearch();
1885 $currentSearchId = null;
1886 $currentSearchName = null;
1887 if (null != $currentSearch) {
1888 $currentSearchId = $currentSearch->getId();
1889 $currentSearchName = $currentSearch->getSearchName();
1892 foreach ($this->_savedSearchList
as $id => $name) {
1893 $html_output .= '<option value="' . htmlspecialchars($id)
1895 $id == $currentSearchId
1896 ?
'selected="selected" '
1900 . htmlspecialchars($name)
1903 $html_output .= '</select>';
1904 $html_output .= '<input type="text" name="searchName" id="searchName" '
1905 . 'value="' . htmlspecialchars($currentSearchName) . '" />';
1906 $html_output .= '<input type="hidden" name="action" id="action" value="" />';
1907 $html_output .= '<input type="submit" name="saveSearch" id="saveSearch" '
1908 . 'value="' . __('Create bookmark') . '" />';
1909 if (null !== $currentSearchId) {
1910 $html_output .= '<input type="submit" name="updateSearch" '
1911 . 'id="updateSearch" value="' . __('Update bookmark') . '" />';
1912 $html_output .= '<input type="submit" name="deleteSearch" '
1913 . 'id="deleteSearch" value="' . __('Delete bookmark') . '" />';
1916 return $html_output;
1920 * Initialize _criteria_column_count
1922 * @return int Previous number of columns
1924 private function _initializeCriteriasCount()
1926 // sets column count
1927 $criteriaColumnCount = PMA_ifSetOr(
1928 $_REQUEST['criteriaColumnCount'],
1932 $criteriaColumnAdd = PMA_ifSetOr(
1933 $_REQUEST['criteriaColumnAdd'],
1937 $this->_criteria_column_count
= max(
1938 $criteriaColumnCount +
$criteriaColumnAdd,
1943 $rows = PMA_ifSetOr($_REQUEST['rows'], 0, 'numeric');
1944 $criteriaRowAdd = PMA_ifSetOr($_REQUEST['criteriaRowAdd'], 0, 'numeric');
1945 $this->_criteria_row_count
= min(
1947 max($rows +
$criteriaRowAdd, 0)
1950 return $criteriaColumnCount;
1956 * @param array $search_tables Tables involved in the search
1957 * @param array $where_clause_columns Columns with where clause
1958 * @param array $unique_columns Unique columns
1959 * @param array $index_columns Indexed columns
1963 private function _getLeftJoinColumnCandidatesBest(
1964 $search_tables, $where_clause_columns, $unique_columns, $index_columns
1966 // now we want to find the best.
1967 if (isset($unique_columns) && count($unique_columns) > 0) {
1968 $candidate_columns = $unique_columns;
1970 return array($candidate_columns, $needsort);
1971 } elseif (isset($index_columns) && count($index_columns) > 0) {
1972 $candidate_columns = $index_columns;
1974 return array($candidate_columns, $needsort);
1975 } elseif (isset($where_clause_columns) && count($where_clause_columns) > 0) {
1976 $candidate_columns = $where_clause_columns;
1978 return array($candidate_columns, $needsort);
1980 $candidate_columns = $search_tables;
1982 return array($candidate_columns, $needsort);