2 /* vim: set expandtab sw=4 ts=4 sts=4: */
4 * Handles DB QBE search
8 if (! defined('PHPMYADMIN')) {
13 * Class to handle database QBE search
27 * Table Names (selected/non-selected)
32 private $_criteriaTables;
39 private $_columnNames;
46 private $_criteria_column_count;
53 private $_criteria_row_count;
55 * Whether to insert a new column
60 private $_criteriaColumnInsert;
62 * Whether to delete a column
67 private $_criteriaColumnDelete;
69 * Whether to insert a new row
74 private $_criteriaRowInsert;
76 * Whether to delete a row
81 private $_criteriaRowDelete;
83 * Already set criteria values
90 * Previously set criteria values
95 private $_prev_criteria;
97 * AND/OR relation b/w criteria columns
102 private $_criteriaAndOrColumn;
104 * AND/OR relation b/w criteria rows
109 private $_criteriaAndOrRow;
111 * Large width of a column
118 * Minimum width of a column
123 private $_form_column_width;
125 * Current criteria field
139 * Current criteria Sort options
146 * Current criteria sort order
151 private $_curSortOrder;
153 * Current criteria Show options
160 * Current criteria values
165 private $_curCriteria;
167 * Current criteria AND/OR column relations
172 private $_curAndOrCol;
174 * Current criteria AND/OR row relations
179 private $_curAndOrRow;
181 * New column count in case of add/delete
186 private $_new_column_count;
188 * New row count in case of add/delete
193 private $_new_row_count;
195 * List of saved searches
200 private $_savedSearchList = null;
205 * @var PMA_SavedSearches
207 private $_currentSearch = null;
210 * Initialize criterias
214 private function _loadCriterias()
216 if (null === $this->_currentSearch
217 ||
null === $this->_currentSearch
->getCriterias()
222 $criterias = $this->_currentSearch
->getCriterias();
223 $_REQUEST = $criterias +
$_REQUEST;
229 * Getter for current search
231 * @return PMA_SavedSearches
233 private function _getCurrentSearch()
235 return $this->_currentSearch
;
241 * @param string $dbname Database name
242 * @param array $savedSearchList List of saved searches
243 * @param PMA_SavedSearches $currentSearch Current search id
245 public function __construct(
246 $dbname, $savedSearchList = array(), $currentSearch = null
248 $this->_db
= $dbname;
249 $this->_savedSearchList
= $savedSearchList;
250 $this->_currentSearch
= $currentSearch;
251 $this->_loadCriterias();
252 // Sets criteria parameters
253 $this->_setSearchParams();
254 $this->_setCriteriaTablesAndColumns();
258 * Sets search parameters
262 private function _setSearchParams()
264 $criteriaColumnCount = $this->_initializeCriteriasCount();
266 $this->_criteriaColumnInsert
= PMA_ifSetOr(
267 $_REQUEST['criteriaColumnInsert'],
271 $this->_criteriaColumnDelete
= PMA_ifSetOr(
272 $_REQUEST['criteriaColumnDelete'],
277 $this->_prev_criteria
= isset($_REQUEST['prev_criteria'])
278 ?
$_REQUEST['prev_criteria']
280 $this->_criteria
= isset($_REQUEST['criteria'])
281 ?
$_REQUEST['criteria']
282 : array_fill(0, $criteriaColumnCount, '');
284 $this->_criteriaRowInsert
= isset($_REQUEST['criteriaRowInsert'])
285 ?
$_REQUEST['criteriaRowInsert']
286 : array_fill(0, $criteriaColumnCount, '');
287 $this->_criteriaRowDelete
= isset($_REQUEST['criteriaRowDelete'])
288 ?
$_REQUEST['criteriaRowDelete']
289 : array_fill(0, $criteriaColumnCount, '');
290 $this->_criteriaAndOrRow
= isset($_REQUEST['criteriaAndOrRow'])
291 ?
$_REQUEST['criteriaAndOrRow']
292 : array_fill(0, $criteriaColumnCount, '');
293 $this->_criteriaAndOrColumn
= isset($_REQUEST['criteriaAndOrColumn'])
294 ?
$_REQUEST['criteriaAndOrColumn']
295 : array_fill(0, $criteriaColumnCount, '');
296 // sets minimum width
297 $this->_form_column_width
= 12;
298 $this->_curField
= array();
299 $this->_curSort
= array();
300 $this->_curShow
= array();
301 $this->_curCriteria
= array();
302 $this->_curAndOrRow
= array();
303 $this->_curAndOrCol
= array();
307 * Sets criteria tables and columns
311 private function _setCriteriaTablesAndColumns()
313 // The tables list sent by a previously submitted form
314 if (PMA_isValid($_REQUEST['TableList'], 'array')) {
315 foreach ($_REQUEST['TableList'] as $each_table) {
316 $this->_criteriaTables
[$each_table] = ' selected="selected"';
319 $all_tables = $GLOBALS['dbi']->query(
320 'SHOW TABLES FROM ' . PMA_Util
::backquote($this->_db
) . ';',
322 PMA_DatabaseInterface
::QUERY_STORE
324 $all_tables_count = $GLOBALS['dbi']->numRows($all_tables);
325 if (0 == $all_tables_count) {
326 PMA_Message
::error(__('No tables found in database.'))->display();
329 // The tables list gets from MySQL
330 while (list($table) = $GLOBALS['dbi']->fetchRow($all_tables)) {
331 $columns = $GLOBALS['dbi']->getColumns($this->_db
, $table);
333 if (empty($this->_criteriaTables
[$table])
334 && ! empty($_REQUEST['TableList'])
336 $this->_criteriaTables
[$table] = '';
338 $this->_criteriaTables
[$table] = ' selected="selected"';
341 // The fields list per selected tables
342 if ($this->_criteriaTables
[$table] == ' selected="selected"') {
343 $each_table = PMA_Util
::backquote($table);
344 $this->_columnNames
[] = $each_table . '.*';
345 foreach ($columns as $each_column) {
346 $each_column = $each_table . '.'
347 . PMA_Util
::backquote($each_column['Field']);
348 $this->_columnNames
[] = $each_column;
349 // increase the width if necessary
350 $this->_form_column_width
= max(
351 /*overload*/mb_strlen($each_column),
352 $this->_form_column_width
357 $GLOBALS['dbi']->freeResult($all_tables);
359 // sets the largest width found
360 $this->_realwidth
= $this->_form_column_width
. 'ex';
363 * Provides select options list containing column names
365 * @param integer $column_number Column Number (0,1,2) or more
366 * @param string $selected Selected criteria column name
368 * @return string HTML for select options
370 private function _showColumnSelectCell($column_number, $selected = '')
373 $html_output .= '<td class="center">';
374 $html_output .= '<select name="criteriaColumn[' . $column_number
376 $html_output .= '<option value=""> </option>';
377 foreach ($this->_columnNames
as $column) {
378 $html_output .= '<option value="' . htmlspecialchars($column) . '"'
379 . (($column === $selected) ?
' selected="selected"' : '') . '>'
380 . str_replace(' ', ' ', htmlspecialchars($column))
383 $html_output .= '</select>';
384 $html_output .= '</td>';
389 * Provides select options list containing sort options (ASC/DESC)
391 * @param integer $column_number Column Number (0,1,2) or more
392 * @param string $asc_selected Selected criteria 'Ascending'
393 * @param string $desc_selected Selected criteria 'Descending'
395 * @return string HTML for select options
397 private function _getSortSelectCell($column_number, $asc_selected = '',
400 $html_output = '<td class="center">';
401 $html_output .= '<select style="width: ' . $this->_realwidth
402 . '" name="criteriaSort[' . $column_number . ']" size="1">';
403 $html_output .= '<option value=""> </option>';
404 $html_output .= '<option value="ASC"' . $asc_selected . '>'
407 $html_output .= '<option value="DESC"' . $desc_selected . '>'
410 $html_output .= '</select>';
411 $html_output .= '</td>';
416 * Provides select options list containing sort order
418 * @param integer $columnNumber Column Number (0,1,2) or more
419 * @param integer $sortOrder Sort order
421 * @return string HTML for select options
423 private function _getSortOrderSelectCell($columnNumber, $sortOrder)
425 $totalColumnCount = $this->_getNewColumnCount();
426 $html_output = '<td class="center">';
427 $html_output .= '<select name="criteriaSortOrder[' . $columnNumber . ']">';
428 $html_output .= '<option value="1000">'
430 for ($a = 1; $a <= $totalColumnCount; $a++
) {
431 $html_output .= '<option value="' . $a . '"';
432 if ($a == $sortOrder) {
433 $html_output .= ' selected="selected"';
435 $html_output .= '>' . $a . '</option>';
437 $html_output .= '</select>';
438 $html_output .= '</td>';
443 * Returns the new column count after adding and removing columns as instructed
445 * @return int new column count
447 private function _getNewColumnCount()
449 $totalColumnCount = $this->_criteria_column_count
;
450 if (! empty($this->_criteriaColumnInsert
)) {
451 $totalColumnCount +
= count($this->_criteriaColumnInsert
);
453 if (! empty($this->_criteriaColumnDelete
)) {
454 $totalColumnCount -= count($this->_criteriaColumnDelete
);
456 return $totalColumnCount;
460 * Provides search form's row containing column select options
462 * @return string HTML for search table's row
464 private function _getColumnNamesRow()
466 $html_output = '<tr class="odd noclick">';
467 $html_output .= '<th>' . __('Column:') . '</th>';
468 $new_column_count = 0;
471 $column_index < $this->_criteria_column_count
;
474 if (isset($this->_criteriaColumnInsert
[$column_index])
475 && $this->_criteriaColumnInsert
[$column_index] == 'on'
477 $html_output .= $this->_showColumnSelectCell(
482 if (! empty($this->_criteriaColumnDelete
)
483 && isset($this->_criteriaColumnDelete
[$column_index])
484 && $this->_criteriaColumnDelete
[$column_index] == 'on'
489 if (isset($_REQUEST['criteriaColumn'][$column_index])) {
490 $selected = $_REQUEST['criteriaColumn'][$column_index];
491 $this->_curField
[$new_column_count]
492 = $_REQUEST['criteriaColumn'][$column_index];
494 $html_output .= $this->_showColumnSelectCell(
500 $this->_new_column_count
= $new_column_count;
501 $html_output .= '</tr>';
506 * Provides search form's row containing column aliases
508 * @return string HTML for search table's row
510 private function _getColumnAliasRow()
512 $html_output = '<tr class="even noclick">';
513 $html_output .= '<th>' . __('Alias:') . '</th>';
514 $new_column_count = 0;
518 $colInd < $this->_criteria_column_count
;
521 if (! empty($this->_criteriaColumnInsert
)
522 && isset($this->_criteriaColumnInsert
[$colInd])
523 && $this->_criteriaColumnInsert
[$colInd] == 'on'
525 $html_output .= '<td class="center">';
526 $html_output .= '<input type="text"'
527 . ' name="criteriaAlias[' . $new_column_count . ']"'
529 $html_output .= '</td>';
533 if (! empty($this->_criteriaColumnDelete
)
534 && isset($this->_criteriaColumnDelete
[$colInd])
535 && $this->_criteriaColumnDelete
[$colInd] == 'on'
541 if (! empty($_REQUEST['criteriaAlias'][$colInd])) {
543 = $this->_curAlias
[$new_column_count]
544 = $_REQUEST['criteriaAlias'][$colInd];
547 $html_output .= '<td class="center">';
548 $html_output .= '<input type="text"'
549 . ' name="criteriaAlias[' . $new_column_count . ']"'
550 . ' value="' . htmlspecialchars($tmp_alias) . '" />';
551 $html_output .= '</td>';
554 $html_output .= '</tr>';
559 * Provides search form's row containing sort(ASC/DESC) select options
561 * @return string HTML for search table's row
563 private function _getSortRow()
565 $html_output = '<tr class="even noclick">';
566 $html_output .= '<th>' . __('Sort:') . '</th>';
567 $new_column_count = 0;
571 $colInd < $this->_criteria_column_count
;
574 if (! empty($this->_criteriaColumnInsert
)
575 && isset($this->_criteriaColumnInsert
[$colInd])
576 && $this->_criteriaColumnInsert
[$colInd] == 'on'
578 $html_output .= $this->_getSortSelectCell($new_column_count);
582 if (! empty($this->_criteriaColumnDelete
)
583 && isset($this->_criteriaColumnDelete
[$colInd])
584 && $this->_criteriaColumnDelete
[$colInd] == 'on'
588 // If they have chosen all fields using the * selector,
589 // then sorting is not available, Fix for Bug #570698
590 if (isset($_REQUEST['criteriaSort'][$colInd])
591 && isset($_REQUEST['criteriaColumn'][$colInd])
592 && /*overload*/mb_substr($_REQUEST['criteriaColumn'][$colInd], -2) == '.*'
594 $_REQUEST['criteriaSort'][$colInd] = '';
597 $asc_selected = ''; $desc_selected = '';
598 if (isset($_REQUEST['criteriaSort'][$colInd])) {
599 $this->_curSort
[$new_column_count]
600 = $_REQUEST['criteriaSort'][$colInd];
602 if ($_REQUEST['criteriaSort'][$colInd] == 'ASC') {
603 $asc_selected = ' selected="selected"';
606 if ($_REQUEST['criteriaSort'][$colInd] == 'DESC') {
607 $desc_selected = ' selected="selected"';
610 $this->_curSort
[$new_column_count] = '';
613 $html_output .= $this->_getSortSelectCell(
614 $new_column_count, $asc_selected, $desc_selected
618 $html_output .= '</tr>';
623 * Provides search form's row containing sort order
625 * @return string HTML for search table's row
627 private function _getSortOrder()
629 $html_output = '<tr class="even noclick">';
630 $html_output .= '<th>' . __('Sort order:') . '</th>';
631 $new_column_count = 0;
635 $colInd < $this->_criteria_column_count
;
638 if (! empty($this->_criteriaColumnInsert
)
639 && isset($this->_criteriaColumnInsert
[$colInd])
640 && $this->_criteriaColumnInsert
[$colInd] == 'on'
642 $html_output .= $this->_getSortOrderSelectCell(
643 $new_column_count, null
648 if (! empty($this->_criteriaColumnDelete
)
649 && isset($this->_criteriaColumnDelete
[$colInd])
650 && $this->_criteriaColumnDelete
[$colInd] == 'on'
656 if (! empty($_REQUEST['criteriaSortOrder'][$colInd])) {
658 = $this->_curSortOrder
[$new_column_count]
659 = $_REQUEST['criteriaSortOrder'][$colInd];
662 $html_output .= $this->_getSortOrderSelectCell(
663 $new_column_count, $sortOrder
667 $html_output .= '</tr>';
672 * Provides search form's row containing SHOW checkboxes
674 * @return string HTML for search table's row
676 private function _getShowRow()
678 $html_output = '<tr class="odd noclick">';
679 $html_output .= '<th>' . __('Show:') . '</th>';
680 $new_column_count = 0;
683 $column_index < $this->_criteria_column_count
;
686 if (! empty($this->_criteriaColumnInsert
)
687 && isset($this->_criteriaColumnInsert
[$column_index])
688 && $this->_criteriaColumnInsert
[$column_index] == 'on'
690 $html_output .= '<td class="center">';
691 $html_output .= '<input type="checkbox"'
692 . ' name="criteriaShow[' . $new_column_count . ']" />';
693 $html_output .= '</td>';
696 if (! empty($this->_criteriaColumnDelete
)
697 && isset($this->_criteriaColumnDelete
[$column_index])
698 && $this->_criteriaColumnDelete
[$column_index] == 'on'
702 if (isset($_REQUEST['criteriaShow'][$column_index])) {
703 $checked_options = ' checked="checked"';
704 $this->_curShow
[$new_column_count]
705 = $_REQUEST['criteriaShow'][$column_index];
707 $checked_options = '';
709 $html_output .= '<td class="center">';
710 $html_output .= '<input type="checkbox"'
711 . ' name="criteriaShow[' . $new_column_count . ']"'
712 . $checked_options . ' />';
713 $html_output .= '</td>';
716 $html_output .= '</tr>';
721 * Provides search form's row containing criteria Inputboxes
723 * @return string HTML for search table's row
725 private function _getCriteriaInputboxRow()
727 $html_output = '<tr class="even noclick">';
728 $html_output .= '<th>' . __('Criteria:') . '</th>';
729 $new_column_count = 0;
732 $column_index < $this->_criteria_column_count
;
735 if (! empty($this->_criteriaColumnInsert
)
736 && isset($this->_criteriaColumnInsert
[$column_index])
737 && $this->_criteriaColumnInsert
[$column_index] == 'on'
739 $html_output .= '<td class="center">';
740 $html_output .= '<input type="text"'
741 . ' name="criteria[' . $new_column_count . ']"'
743 . ' class="textfield"'
744 . ' style="width: ' . $this->_realwidth
. '"'
746 $html_output .= '</td>';
749 if (! empty($this->_criteriaColumnDelete
)
750 && isset($this->_criteriaColumnDelete
[$column_index])
751 && $this->_criteriaColumnDelete
[$column_index] == 'on'
755 if (isset($this->_criteria
[$column_index])) {
756 $tmp_criteria = $this->_criteria
[$column_index];
758 if ((empty($this->_prev_criteria
)
759 ||
! isset($this->_prev_criteria
[$column_index]))
760 ||
$this->_prev_criteria
[$column_index] != htmlspecialchars($tmp_criteria)
762 $this->_curCriteria
[$new_column_count] = $tmp_criteria;
764 $this->_curCriteria
[$new_column_count]
765 = $this->_prev_criteria
[$column_index];
767 $html_output .= '<td class="center">';
768 $html_output .= '<input type="hidden"'
769 . ' name="prev_criteria[' . $new_column_count . ']"'
771 . htmlspecialchars($this->_curCriteria
[$new_column_count])
773 $html_output .= '<input type="text"'
774 . ' name="criteria[' . $new_column_count . ']"'
775 . ' value="' . htmlspecialchars($tmp_criteria) . '"'
776 . ' class="textfield"'
777 . ' style="width: ' . $this->_realwidth
. '"'
779 $html_output .= '</td>';
782 $html_output .= '</tr>';
787 * Provides footer options for adding/deleting row/columns
789 * @param string $type Whether row or column
791 * @return string HTML for footer options
793 private function _getFootersOptions($type)
795 $html_output = '<div class="floatleft">';
796 $html_output .= (($type == 'row')
797 ?
__('Add/Delete criteria rows') : __('Add/Delete columns'));
798 $html_output .= ':<select size="1" name="'
799 . (($type == 'row') ?
'criteriaRowAdd' : 'criteriaColumnAdd') . '">';
800 $html_output .= '<option value="-3">-3</option>';
801 $html_output .= '<option value="-2">-2</option>';
802 $html_output .= '<option value="-1">-1</option>';
803 $html_output .= '<option value="0" selected="selected">0</option>';
804 $html_output .= '<option value="1">1</option>';
805 $html_output .= '<option value="2">2</option>';
806 $html_output .= '<option value="3">3</option>';
807 $html_output .= '</select>';
808 $html_output .= '</div>';
813 * Provides search form table's footer options
815 * @return string HTML for table footer
817 private function _getTableFooters()
819 $html_output = '<fieldset class="tblFooters">';
820 $html_output .= $this->_getFootersOptions("row");
821 $html_output .= $this->_getFootersOptions("column");
822 $html_output .= '<div class="floatleft">';
823 $html_output .= '<input type="submit" name="modify"'
824 . 'value="' . __('Update Query') . '" />';
825 $html_output .= '</div>';
826 $html_output .= '</fieldset>';
831 * Provides a select list of database tables
833 * @return string HTML for table select list
835 private function _getTablesList()
837 $html_output = '<div class="floatleft">';
838 $html_output .= '<fieldset>';
839 $html_output .= '<legend>' . __('Use Tables') . '</legend>';
840 // Build the options list for each table name
842 $numTableListOptions = 0;
843 foreach ($this->_criteriaTables
as $key => $val) {
844 $options .= '<option value="' . htmlspecialchars($key) . '"' . $val . '>'
845 . (str_replace(' ', ' ', htmlspecialchars($key))) . '</option>';
846 $numTableListOptions++
;
848 $html_output .= '<select name="TableList[]"'
849 . ' multiple="multiple" id="listTable"'
850 . ' size="' . (($numTableListOptions > 30) ?
'15' : '7') . '">';
851 $html_output .= $options;
852 $html_output .= '</select>';
853 $html_output .= '</fieldset>';
854 $html_output .= '<fieldset class="tblFooters">';
855 $html_output .= '<input type="submit" name="modify" value="'
856 . __('Update Query') . '" />';
857 $html_output .= '</fieldset>';
858 $html_output .= '</div>';
863 * Provides And/Or modification cell along with Insert/Delete options
864 * (For modifying search form's table columns)
866 * @param integer $column_number Column Number (0,1,2) or more
867 * @param array $selected Selected criteria column name
868 * @param bool $last_column Whether this is the last column
870 * @return string HTML for modification cell
872 private function _getAndOrColCell(
873 $column_number, $selected = null, $last_column = false
875 $html_output = '<td class="center">';
876 if (! $last_column) {
877 $html_output .= '<strong>' . __('Or:') . '</strong>';
878 $html_output .= '<input type="radio"'
879 . ' name="criteriaAndOrColumn[' . $column_number . ']"'
880 . ' value="or"' . $selected['or'] . ' />';
881 $html_output .= ' <strong>' . __('And:') . '</strong>';
882 $html_output .= '<input type="radio"'
883 . ' name="criteriaAndOrColumn[' . $column_number . ']"'
884 . ' value="and"' . $selected['and'] . ' />';
886 $html_output .= '<br />' . __('Ins');
887 $html_output .= '<input type="checkbox"'
888 . ' name="criteriaColumnInsert[' . $column_number . ']" />';
889 $html_output .= ' ' . __('Del');
890 $html_output .= '<input type="checkbox"'
891 . ' name="criteriaColumnDelete[' . $column_number . ']" />';
892 $html_output .= '</td>';
897 * Provides search form's row containing column modifications options
898 * (For modifying search form's table columns)
900 * @return string HTML for search table's row
902 private function _getModifyColumnsRow()
904 $html_output = '<tr class="even noclick">';
905 $html_output .= '<th>' . __('Modify:') . '</th>';
906 $new_column_count = 0;
909 $column_index < $this->_criteria_column_count
;
912 if (! empty($this->_criteriaColumnInsert
)
913 && isset($this->_criteriaColumnInsert
[$column_index])
914 && $this->_criteriaColumnInsert
[$column_index] == 'on'
916 $html_output .= $this->_getAndOrColCell($new_column_count);
920 if (! empty($this->_criteriaColumnDelete
)
921 && isset($this->_criteriaColumnDelete
[$column_index])
922 && $this->_criteriaColumnDelete
[$column_index] == 'on'
927 if (isset($this->_criteriaAndOrColumn
[$column_index])) {
928 $this->_curAndOrCol
[$new_column_count]
929 = $this->_criteriaAndOrColumn
[$column_index];
931 $checked_options = array();
932 if (isset($this->_criteriaAndOrColumn
[$column_index])
933 && $this->_criteriaAndOrColumn
[$column_index] == 'or'
935 $checked_options['or'] = ' checked="checked"';
936 $checked_options['and'] = '';
938 $checked_options['and'] = ' checked="checked"';
939 $checked_options['or'] = '';
941 $html_output .= $this->_getAndOrColCell(
944 ($column_index +
1 == $this->_criteria_column_count
)
948 $html_output .= '</tr>';
953 * Provides Insert/Delete options for criteria inputbox
954 * with AND/OR relationship modification options
956 * @param integer $row_index Number of criteria row
957 * @param array $checked_options If checked
959 * @return string HTML
961 private function _getInsDelAndOrCell($row_index, $checked_options)
963 $html_output = '<td class="' . $GLOBALS['cell_align_right'] . ' nowrap">';
964 $html_output .= '<!-- Row controls -->';
965 $html_output .= '<table class="nospacing nopadding">';
966 $html_output .= '<tr>';
967 $html_output .= '<td class="' . $GLOBALS['cell_align_right'] . ' nowrap">';
968 $html_output .= '<small>' . __('Ins:') . '</small>';
969 $html_output .= '<input type="checkbox"'
970 . ' name="criteriaRowInsert[' . $row_index . ']" />';
971 $html_output .= '</td>';
972 $html_output .= '<td class="' . $GLOBALS['cell_align_right'] . '">';
973 $html_output .= '<strong>' . __('And:') . '</strong>';
974 $html_output .= '</td>';
975 $html_output .= '<td>';
976 $html_output .= '<input type="radio"'
977 . ' name="criteriaAndOrRow[' . $row_index . ']" value="and"'
978 . $checked_options['and'] . ' />';
979 $html_output .= '</td>';
980 $html_output .= '</tr>';
981 $html_output .= '<tr>';
982 $html_output .= '<td class="' . $GLOBALS['cell_align_right'] . ' nowrap">';
983 $html_output .= '<small>' . __('Del:') . '</small>';
984 $html_output .= '<input type="checkbox"'
985 . ' name="criteriaRowDelete[' . $row_index . ']" />';
986 $html_output .= '</td>';
987 $html_output .= '<td class="' . $GLOBALS['cell_align_right'] . '">';
988 $html_output .= '<strong>' . __('Or:') . '</strong>';
989 $html_output .= '</td>';
990 $html_output .= '<td>';
991 $html_output .= '<input type="radio"'
992 . ' name="criteriaAndOrRow[' . $row_index . ']"'
993 . ' value="or"' . $checked_options['or'] . ' />';
994 $html_output .= '</td>';
995 $html_output .= '</tr>';
996 $html_output .= '</table>';
997 $html_output .= '</td>';
1002 * Provides rows for criteria inputbox Insert/Delete options
1003 * with AND/OR relationship modification options
1005 * @param integer $new_row_index New row index if rows are added/deleted
1007 * @return string HTML table rows
1009 private function _getInputboxRow($new_row_index)
1012 $new_column_count = 0;
1015 $column_index < $this->_criteria_column_count
;
1018 if (!empty($this->_criteriaColumnInsert
)
1019 && isset($this->_criteriaColumnInsert
[$column_index])
1020 && $this->_criteriaColumnInsert
[$column_index] == 'on'
1022 $orFieldName = 'Or' . $new_row_index . '[' . $new_column_count . ']';
1023 $html_output .= '<td class="center">';
1024 $html_output .= '<input type="text"'
1025 . ' name="Or' . $orFieldName . '" class="textfield"'
1026 . ' style="width: ' . $this->_realwidth
. '" size="20" />';
1027 $html_output .= '</td>';
1028 $new_column_count++
;
1030 if (!empty($this->_criteriaColumnDelete
)
1031 && isset($this->_criteriaColumnDelete
[$column_index])
1032 && $this->_criteriaColumnDelete
[$column_index] == 'on'
1036 $or = 'Or' . $new_row_index;
1037 if (! empty($_REQUEST[$or]) && isset($_REQUEST[$or][$column_index])) {
1038 $tmp_or = $_REQUEST[$or][$column_index];
1042 $html_output .= '<td class="center">';
1043 $html_output .= '<input type="text"'
1044 . ' name="Or' . $new_row_index . '[' . $new_column_count . ']' . '"'
1045 . ' value="' . htmlspecialchars($tmp_or) . '" class="textfield"'
1046 . ' style="width: ' . $this->_realwidth
. '" size="20" />';
1047 $html_output .= '</td>';
1048 if (!empty($
{$or}) && isset($
{$or}[$column_index])) {
1049 $GLOBALS[$
{'cur' . $or}][$new_column_count]
1050 = $
{$or}[$column_index];
1052 $new_column_count++
;
1054 return $html_output;
1058 * Provides rows for criteria inputbox Insert/Delete options
1059 * with AND/OR relationship modification options
1061 * @return string HTML table rows
1063 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="' . ($odd_row ?
'odd' : 'even')
1081 $html_output .= $this->_getInsDelAndOrCell(
1082 $new_row_count, $checked_options
1084 $html_output .= $this->_getInputboxRow(
1088 $html_output .= '</tr>';
1089 $odd_row =! $odd_row;
1091 if (isset($this->_criteriaRowDelete
[$row_index])
1092 && $this->_criteriaRowDelete
[$row_index] == 'on'
1096 if (isset($this->_criteriaAndOrRow
[$row_index])) {
1097 $this->_curAndOrRow
[$new_row_count]
1098 = $this->_criteriaAndOrRow
[$row_index];
1100 if (isset($this->_criteriaAndOrRow
[$row_index])
1101 && $this->_criteriaAndOrRow
[$row_index] == 'and'
1103 $checked_options['and'] = ' checked="checked"';
1104 $checked_options['or'] = '';
1106 $checked_options['or'] = ' checked="checked"';
1107 $checked_options['and'] = '';
1109 $html_output .= '<tr class="' . ($odd_row ?
'odd' : 'even')
1111 $html_output .= $this->_getInsDelAndOrCell(
1112 $new_row_count, $checked_options
1114 $html_output .= $this->_getInputboxRow(
1118 $html_output .= '</tr>';
1119 $odd_row =! $odd_row;
1121 $this->_new_row_count
= $new_row_count;
1122 return $html_output;
1126 * Provides SELECT clause for building SQL query
1128 * @return string Select clause
1130 private function _getSelectClause()
1132 $select_clause = '';
1133 $select_clauses = array();
1136 $column_index < $this->_criteria_column_count
;
1139 if (! empty($this->_curField
[$column_index])
1140 && isset($this->_curShow
[$column_index])
1141 && $this->_curShow
[$column_index] == 'on'
1143 $select = $this->_curField
[$column_index];
1144 if (! empty($this->_curAlias
[$column_index])) {
1146 . PMA_Util
::backquote($this->_curAlias
[$column_index]);
1148 $select_clauses[] = $select;
1151 if ($select_clauses) {
1152 $select_clause = 'SELECT '
1153 . htmlspecialchars(implode(", ", $select_clauses)) . "\n";
1155 return $select_clause;
1159 * Provides WHERE clause for building SQL query
1161 * @return string Where clause
1163 private function _getWhereClause()
1169 $column_index < $this->_criteria_column_count
;
1172 if (! empty($this->_curField
[$column_index])
1173 && ! empty($this->_curCriteria
[$column_index])
1175 && isset($last_where)
1176 && isset($this->_curAndOrCol
)
1178 $where_clause .= ' '
1179 . /*overload*/mb_strtoupper($this->_curAndOrCol
[$last_where])
1182 if (! empty($this->_curField
[$column_index])
1183 && ! empty($this->_curCriteria
[$column_index])
1185 $where_clause .= '(' . $this->_curField
[$column_index] . ' '
1186 . $this->_curCriteria
[$column_index] . ')';
1187 $last_where = $column_index;
1191 if ($criteria_cnt > 1) {
1192 $where_clause = '(' . $where_clause . ')';
1194 // OR rows ${'cur' . $or}[$column_index]
1195 if (! isset($this->_curAndOrRow
)) {
1196 $this->_curAndOrRow
= array();
1200 $row_index <= $this->_criteria_row_count
;
1208 $column_index < $this->_criteria_column_count
;
1211 if (! empty($this->_curField
[$column_index])
1212 && ! empty($_REQUEST['Or' . $row_index][$column_index])
1216 . /*overload*/mb_strtoupper(
1217 $this->_curAndOrCol
[$last_orwhere]
1221 if (! empty($this->_curField
[$column_index])
1222 && ! empty($_REQUEST['Or' . $row_index][$column_index])
1224 $qry_orwhere .= '(' . $this->_curField
[$column_index]
1226 . $_REQUEST['Or' . $row_index][$column_index]
1228 $last_orwhere = $column_index;
1232 if ($criteria_cnt > 1) {
1233 $qry_orwhere = '(' . $qry_orwhere . ')';
1235 if (! empty($qry_orwhere)) {
1236 $where_clause .= "\n"
1237 . /*overload*/mb_strtoupper(
1238 isset($this->_curAndOrRow
[$row_index])
1239 ?
$this->_curAndOrRow
[$row_index] . ' '
1246 if (! empty($where_clause) && $where_clause != '()') {
1247 $where_clause = 'WHERE ' . htmlspecialchars($where_clause) . "\n";
1249 return $where_clause;
1253 * Provides ORDER BY clause for building SQL query
1255 * @return string Order By clause
1257 private function _getOrderByClause()
1259 $orderby_clause = '';
1260 $orderby_clauses = array();
1262 // Create copy of instance variables
1263 $field = $this->_curField
;
1264 $sort = $this->_curSort
;
1265 $sortOrder = $this->_curSortOrder
;
1267 && count($sortOrder) == count($sort)
1268 && count($sortOrder) == count($field)
1270 // Sort all three arrays based on sort order
1271 array_multisort($sortOrder, $sort, $field);
1276 $column_index < $this->_criteria_column_count
;
1279 // if all columns are chosen with * selector,
1280 // then sorting isn't available
1281 // Fix for Bug #570698
1282 if (empty($field[$column_index])
1283 && empty($sort[$column_index])
1288 if (/*overload*/mb_substr($field[$column_index], -2) == '.*') {
1292 if (! empty($sort[$column_index])) {
1293 $orderby_clauses[] = $field[$column_index] . ' '
1294 . $sort[$column_index];
1297 if ($orderby_clauses) {
1298 $orderby_clause = 'ORDER BY '
1299 . htmlspecialchars(implode(", ", $orderby_clauses)) . "\n";
1301 return $orderby_clause;
1305 * Provides UNIQUE columns and INDEX columns present in criteria tables
1307 * @param array $search_tables Tables involved in the search
1308 * @param array $search_columns Columns involved in the search
1309 * @param array $where_clause_columns Columns having criteria where clause
1311 * @return array having UNIQUE and INDEX columns
1313 private function _getIndexes($search_tables, $search_columns,
1314 $where_clause_columns
1316 $unique_columns = array();
1317 $index_columns = array();
1319 foreach ($search_tables as $table) {
1320 $indexes = $GLOBALS['dbi']->getTableIndexes($this->_db
, $table);
1321 foreach ($indexes as $index) {
1322 $column = $table . '.' . $index['Column_name'];
1323 if (isset($search_columns[$column])) {
1324 if ($index['Non_unique'] == 0) {
1325 if (isset($where_clause_columns[$column])) {
1326 $unique_columns[$column] = 'Y';
1328 $unique_columns[$column] = 'N';
1331 if (isset($where_clause_columns[$column])) {
1332 $index_columns[$column] = 'Y';
1334 $index_columns[$column] = 'N';
1338 } // end while (each index of a table)
1339 } // end while (each table)
1342 'unique' => $unique_columns,
1343 'index' => $index_columns
1348 * Provides UNIQUE columns and INDEX columns present in criteria tables
1350 * @param array $search_tables Tables involved in the search
1351 * @param array $search_columns Columns involved in the search
1352 * @param array $where_clause_columns Columns having criteria where clause
1354 * @return array having UNIQUE and INDEX columns
1356 private function _getLeftJoinColumnCandidates($search_tables, $search_columns,
1357 $where_clause_columns
1359 $GLOBALS['dbi']->selectDb($this->_db
);
1361 // Get unique columns and index columns
1362 $indexes = $this->_getIndexes(
1363 $search_tables, $search_columns, $where_clause_columns
1365 $unique_columns = $indexes['unique'];
1366 $index_columns = $indexes['index'];
1368 list($candidate_columns, $needsort)
1369 = $this->_getLeftJoinColumnCandidatesBest(
1370 $search_tables, $where_clause_columns, $unique_columns, $index_columns
1373 // If we came up with $unique_columns (very good) or $index_columns (still
1374 // good) as $candidate_columns we want to check if we have any 'Y' there
1375 // (that would mean that they were also found in the whereclauses
1376 // which would be great). if yes, we take only those
1377 if ($needsort != 1) {
1378 return $candidate_columns;
1381 $very_good = array();
1382 $still_good = array();
1383 foreach ($candidate_columns as $column => $is_where) {
1384 $table = explode('.', $column);
1386 if ($is_where == 'Y') {
1387 $very_good[$column] = $table;
1389 $still_good[$column] = $table;
1392 if (count($very_good) > 0) {
1393 $candidate_columns = $very_good;
1394 // Candidates restricted in index+where
1396 $candidate_columns = $still_good;
1397 // None of the candidates where in a where-clause
1400 return $candidate_columns;
1404 * Provides the main table to form the LEFT JOIN clause
1406 * @param array $search_tables Tables involved in the search
1407 * @param array $search_columns Columns involved in the search
1408 * @param array $where_clause_columns Columns having criteria where clause
1409 * @param array $where_clause_tables Tables having criteria where clause
1411 * @return string table name
1413 private function _getMasterTable($search_tables, $search_columns,
1414 $where_clause_columns, $where_clause_tables
1416 if (count($where_clause_tables) == 1) {
1417 // If there is exactly one column that has a decent where-clause
1418 // we will just use this
1419 $master = key($where_clause_tables);
1423 // Now let's find out which of the tables has an index
1424 // (When the control user is the same as the normal user
1425 // because he is using one of his databases as pmadb,
1426 // the last db selected is not always the one where we need to work)
1427 $candidate_columns = $this->_getLeftJoinColumnCandidates(
1428 $search_tables, $search_columns, $where_clause_columns
1431 // Generally, we need to display all the rows of foreign (referenced)
1432 // table, whether they have any matching row in child table or not.
1433 // So we select candidate tables which are foreign tables.
1434 $foreign_tables = array();
1435 foreach ($candidate_columns as $one_table) {
1436 $foreigners = PMA_getForeigners($this->_db
, $one_table);
1437 foreach ($foreigners as $key => $foreigner) {
1438 if ($key != 'foreign_keys_data') {
1439 if (in_array($foreigner['foreign_table'], $candidate_columns)) {
1440 $foreign_tables[$foreigner['foreign_table']]
1441 = $foreigner['foreign_table'];
1445 foreach ($foreigner as $one_key) {
1446 if (in_array($one_key['ref_table_name'], $candidate_columns)) {
1447 $foreign_tables[$one_key['ref_table_name']]
1448 = $one_key['ref_table_name'];
1453 if (count($foreign_tables)) {
1454 $candidate_columns = $foreign_tables;
1457 // If our array of candidates has more than one member we'll just
1458 // find the smallest table.
1459 // Of course the actual query would be faster if we check for
1460 // the Criteria which gives the smallest result set in its table,
1461 // but it would take too much time to check this
1462 if (!(count($candidate_columns) > 1)) {
1463 reset($candidate_columns);
1464 $master = current($candidate_columns); // Only one single candidate
1468 // Of course we only want to check each table once
1469 $checked_tables = $candidate_columns;
1472 foreach ($candidate_columns as $table) {
1473 if ($checked_tables[$table] != 1) {
1474 $tsize[$table] = PMA_Table
::countRecords(
1479 $checked_tables[$table] = 1;
1481 $csize[$table] = $tsize[$table];
1485 $master = key($csize); // Largest
1491 * Provides columns and tables that have valid where clause criteria
1495 private function _getWhereClauseTablesAndColumns()
1497 $where_clause_columns = array();
1498 $where_clause_tables = array();
1500 // Now we need all tables that we have in the where clause
1502 $column_index = 0, $nb = count($this->_criteria
);
1503 $column_index < $nb;
1506 $current_table = explode('.', $_POST['criteriaColumn'][$column_index]);
1507 if (empty($current_table[0]) ||
empty($current_table[1])) {
1510 $table = str_replace('`', '', $current_table[0]);
1511 $column = str_replace('`', '', $current_table[1]);
1512 $column = $table . '.' . $column;
1513 // Now we know that our array has the same numbers as $criteria
1514 // we can check which of our columns has a where clause
1515 if (! empty($this->_criteria
[$column_index])) {
1516 if (/*overload*/mb_substr($this->_criteria
[$column_index], 0, 1) == '='
1517 ||
/*$pmaString->*/stristr($this->_criteria
[$column_index], 'is')
1519 $where_clause_columns[$column] = $column;
1520 $where_clause_tables[$table] = $table;
1525 'where_clause_tables' => $where_clause_tables,
1526 'where_clause_columns' => $where_clause_columns
1531 * Provides FROM clause for building SQL query
1533 * @return string FROM clause
1535 private function _getFromClause()
1538 if (isset($_POST['criteriaColumn']) && count($_POST['criteriaColumn']) > 0) {
1539 // Initialize some variables
1540 $search_tables = $search_columns = array();
1542 // We only start this if we have fields, otherwise it would be dumb
1543 foreach ($_POST['criteriaColumn'] as $value) {
1544 $parts = explode('.', $value);
1545 if (! empty($parts[0]) && ! empty($parts[1])) {
1546 $table = str_replace('`', '', $parts[0]);
1547 $search_tables[$table] = $table;
1548 $search_columns[] = $table . '.' . str_replace('`', '', $parts[1]);
1552 // Create LEFT JOINS out of Relations
1553 $from_clause = $this->_getJoinForFromClause($search_tables, $search_columns);
1555 // In case relations are not defined, just generate the FROM clause
1556 // from the list of tables, however we don't generate any JOIN
1557 if (empty($from_clause)) {
1558 // Create cartesian product
1559 $from_clause = implode(
1560 ", ", array_map('PMA_Util::backquote', $search_tables)
1563 } // end count($_POST['criteriaColumn']) > 0
1565 return $from_clause;
1569 * Formulates the WHERE clause by JOINing tables
1571 * @param array $searchTables Tables involved in the search
1572 * @param array $searchColumns Columns involved in the search
1574 * @return string table name
1576 private function _getJoinForFromClause($searchTables, $searchColumns)
1578 // $relations[master_table][foreign_table] => clause
1579 $relations = array();
1581 // Fill $relations with inter table relationship data
1582 foreach ($searchTables as $oneTable) {
1583 $this->_loadRelationsForTable($relations, $oneTable);
1586 // Get tables and columns with valid where clauses
1587 $validWhereClauses = $this->_getWhereClauseTablesAndColumns();
1588 $whereClauseTables = $validWhereClauses['where_clause_tables'];
1589 $whereClauseColumns = $validWhereClauses['where_clause_columns'];
1592 $master = $this->_getMasterTable(
1593 $searchTables, $searchColumns,
1594 $whereClauseColumns, $whereClauseTables
1597 // Will incldue master tables and all tables that can be combined into
1598 // a cluster by their relation
1599 $finalized = array();
1600 if (mb_strlen($master) > 0) {
1601 // Add master tables
1602 $finalized[$master] = '';
1604 // Fill the $finalized array with JOIN clauses for each table
1605 $this->_fillJoinClauses($finalized, $relations, $searchTables);
1610 // Tables that can not be combined with the table cluster
1611 // which includes master table
1612 $unfinalized = array_diff($searchTables, array_keys($finalized));
1613 if (count($unfinalized) > 0) {
1615 // We need to look for intermediary tables to JOIN unfinalized tables
1616 // Heuristic to chose intermediary tables is to look for tables
1617 // having relationships with unfinalized tables
1618 foreach ($unfinalized as $oneTable) {
1620 $references = PMA_getChildReferences($this->_db
, $oneTable);
1621 foreach ($references as $column => $columnReferences) {
1622 foreach ($columnReferences as $reference) {
1624 // Only from this schema
1625 if ($reference['table_schema'] == $this->_db
) {
1626 $table = $reference['table_name'];
1628 $this->_loadRelationsForTable($relations, $table);
1631 $tempFinalized = $finalized;
1632 $tempSearchTables = $searchTables;
1633 $tempSearchTables[] = $table;
1635 // Try joining with the added table
1636 $this->_fillJoinClauses(
1637 $tempFinalized, $relations, $tempSearchTables
1640 $tempUnfinalized = array_diff(
1641 $tempSearchTables, array_keys($tempFinalized)
1643 // Take greedy approach.
1644 // If the unfinalized count drops we keep the new table
1645 // and switch temporary varibles with the original ones
1646 if (count($tempUnfinalized) < count($unfinalized)) {
1647 $finalized = $tempFinalized;
1648 $searchTables = $tempSearchTables;
1651 // We are done if no unfinalized tables anymore
1652 if (count($tempUnfinalized) == 0) {
1660 $unfinalized = array_diff($searchTables, array_keys($finalized));
1661 // If there are still unfinalized tables
1662 if (count($unfinalized) > 0) {
1663 // Add these tables as cartesian product before joined tables
1665 ', ', array_map('PMA_Util::backquote', $unfinalized)
1671 // Add joined tables
1672 foreach ($finalized as $table => $clause) {
1674 if (! empty($join)) {
1677 $join .= PMA_Util
::backquote($table);
1680 $join .= "\n LEFT JOIN " . PMA_Util
::backquote(
1682 ) . " ON " . $clause;
1690 * Loads relations for a given table into the $relations array
1692 * @param array &$relations array of relations
1693 * @param string $oneTable the table
1697 private function _loadRelationsForTable(&$relations, $oneTable)
1699 $relations[$oneTable] = array();
1701 $foreigners = PMA_getForeigners($GLOBALS['db'], $oneTable);
1702 foreach ($foreigners as $field => $foreigner) {
1703 // Foreign keys data
1704 if ($field == 'foreign_keys_data') {
1705 foreach ($foreigner as $oneKey) {
1707 // There may be multiple column relations
1708 foreach ($oneKey['index_list'] as $index => $oneField) {
1710 = PMA_Util
::backquote($oneTable) . "."
1711 . PMA_Util
::backquote($oneField) . " = "
1712 . PMA_Util
::backquote($oneKey['ref_table_name']) . "."
1713 . PMA_Util
::backquote($oneKey['ref_index_list'][$index]);
1715 // Combine multiple column relations with AND
1716 $relations[$oneTable][$oneKey['ref_table_name']]
1717 = implode(" AND ", $clauses);
1719 } else { // Internal relations
1720 $relations[$oneTable][$foreigner['foreign_table']]
1721 = PMA_Util
::backquote($oneTable) . "."
1722 . PMA_Util
::backquote($field) . " = "
1723 . PMA_Util
::backquote($foreigner['foreign_table']) . "."
1724 . PMA_Util
::backquote($foreigner['foreign_field']);
1730 * Fills the $finalized arrays with JOIN clauses for each of the tables
1732 * @param array &$finalized JOIN clauses for each table
1733 * @param array $relations Relations among tables
1734 * @param array $searchTables Tables involved in the search
1738 private function _fillJoinClauses(&$finalized, $relations, $searchTables)
1742 foreach ($searchTables as $masterTable) {
1743 $foreignData = $relations[$masterTable];
1744 foreach ($foreignData as $foreignTable => $clause) {
1745 if (! isset($finalized[$masterTable])
1746 && isset($finalized[$foreignTable])
1748 $finalized[$masterTable] = $clause;
1750 } elseif (! isset($finalized[$foreignTable])
1751 && isset($finalized[$masterTable])
1752 && in_array($foreignTable, $searchTables)
1754 $finalized[$foreignTable] = $clause;
1758 // We are done if all tables are in $finalized
1759 if (count($finalized) == count($searchTables)) {
1765 // If no new tables were added during this iteration, break;
1773 * Provides the generated SQL query
1775 * @return string SQL query
1777 private function _getSQLQuery()
1780 // get SELECT clause
1781 $sql_query .= $this->_getSelectClause();
1783 $from_clause = $this->_getFromClause();
1784 if (! empty($from_clause)) {
1785 $sql_query .= 'FROM ' . htmlspecialchars($from_clause) . "\n";
1788 $sql_query .= $this->_getWhereClause();
1789 // get ORDER BY clause
1790 $sql_query .= $this->_getOrderByClause();
1795 * Provides the generated QBE form
1797 * @return string QBE form
1799 public function getSelectionForm()
1801 $html_output = '<form action="db_qbe.php" method="post" id="formQBE" class="lock-page">';
1802 $html_output .= '<fieldset>';
1804 if ($GLOBALS['cfgRelation']['savedsearcheswork']) {
1805 $html_output .= $this->_getSavedSearchesField();
1808 $html_output .= '<table class="data" style="width: 100%;">';
1809 // Get table's <tr> elements
1810 $html_output .= $this->_getColumnNamesRow();
1811 $html_output .= $this->_getColumnAliasRow();
1812 $html_output .= $this->_getShowRow();
1813 $html_output .= $this->_getSortRow();
1814 $html_output .= $this->_getSortOrder();
1815 $html_output .= $this->_getCriteriaInputboxRow();
1816 $html_output .= $this->_getInsDelAndOrCriteriaRows();
1817 $html_output .= $this->_getModifyColumnsRow();
1818 $html_output .= '</table>';
1819 $this->_new_row_count
--;
1820 $url_params = array();
1821 $url_params['db'] = $this->_db
;
1822 $url_params['criteriaColumnCount'] = $this->_new_column_count
;
1823 $url_params['rows'] = $this->_new_row_count
;
1824 $html_output .= PMA_URL_getHiddenInputs($url_params);
1825 $html_output .= '</fieldset>';
1827 $html_output .= $this->_getTableFooters();
1828 // get tables select list
1829 $html_output .= $this->_getTablesList();
1830 $html_output .= '</form>';
1831 $html_output .= '<form action="db_qbe.php" method="post" class="lock-page">';
1832 $html_output .= PMA_URL_getHiddenInputs(array('db' => $this->_db
));
1834 $html_output .= '<div class="floatleft" style="width:50%">';
1835 $html_output .= '<fieldset>';
1836 $html_output .= '<legend>'
1838 __('SQL query on database <b>%s</b>:'),
1839 PMA_Util
::getDbLink($this->_db
)
1841 $html_output .= '</legend>';
1843 $html_output .= '<textarea cols="80" name="sql_query" id="textSqlquery"'
1844 . ' rows="' . ((count($this->_criteriaTables
) > 30) ?
'15' : '7') . '"'
1845 . ' dir="' . $text_dir . '">';
1846 $html_output .= $this->_getSQLQuery();
1847 $html_output .= '</textarea>';
1848 $html_output .= '</fieldset>';
1849 // displays form's footers
1850 $html_output .= '<fieldset class="tblFooters">';
1851 $html_output .= '<input type="hidden" name="submit_sql" value="1" />';
1852 $html_output .= '<input type="submit" value="' . __('Submit Query') . '" />';
1853 $html_output .= '</fieldset>';
1854 $html_output .= '</div>';
1855 $html_output .= '</form>';
1856 return $html_output;
1860 * Get fields to display
1864 private function _getSavedSearchesField()
1866 $html_output = __('Saved bookmarked search:');
1867 $html_output .= ' <select name="searchId" id="searchId">';
1868 $html_output .= '<option value="">' . __('New bookmark') . '</option>';
1870 $currentSearch = $this->_getCurrentSearch();
1871 $currentSearchId = null;
1872 $currentSearchName = null;
1873 if (null != $currentSearch) {
1874 $currentSearchId = $currentSearch->getId();
1875 $currentSearchName = $currentSearch->getSearchName();
1878 foreach ($this->_savedSearchList
as $id => $name) {
1879 $html_output .= '<option value="' . htmlspecialchars($id)
1881 $id == $currentSearchId
1882 ?
'selected="selected" '
1886 . htmlspecialchars($name)
1889 $html_output .= '</select>';
1890 $html_output .= '<input type="text" name="searchName" id="searchName" '
1891 . 'value="' . $currentSearchName . '" />';
1892 $html_output .= '<input type="hidden" name="action" id="action" value="" />';
1893 $html_output .= '<input type="submit" name="saveSearch" id="saveSearch" '
1894 . 'value="' . __('Create bookmark') . '" />';
1895 if (null !== $currentSearchId) {
1896 $html_output .= '<input type="submit" name="updateSearch" '
1897 . 'id="updateSearch" value="' . __('Update bookmark') . '" />';
1898 $html_output .= '<input type="submit" name="deleteSearch" '
1899 . 'id="deleteSearch" value="' . __('Delete bookmark') . '" />';
1902 return $html_output;
1906 * Initialize _criteria_column_count
1908 * @return int Previous number of columns
1910 private function _initializeCriteriasCount()
1912 // sets column count
1913 $criteriaColumnCount = PMA_ifSetOr(
1914 $_REQUEST['criteriaColumnCount'],
1918 $criteriaColumnAdd = PMA_ifSetOr(
1919 $_REQUEST['criteriaColumnAdd'],
1923 $this->_criteria_column_count
= max(
1924 $criteriaColumnCount +
$criteriaColumnAdd,
1929 $rows = PMA_ifSetOr($_REQUEST['rows'], 0, 'numeric');
1930 $criteriaRowAdd = PMA_ifSetOr($_REQUEST['criteriaRowAdd'], 0, 'numeric');
1931 $this->_criteria_row_count
= max($rows +
$criteriaRowAdd, 0);
1933 return $criteriaColumnCount;
1939 * @param array $search_tables Tables involved in the search
1940 * @param array $where_clause_columns Columns with where clause
1941 * @param array $unique_columns Unique columns
1942 * @param array $index_columns Indexed columns
1946 private function _getLeftJoinColumnCandidatesBest(
1947 $search_tables, $where_clause_columns, $unique_columns, $index_columns
1949 // now we want to find the best.
1950 if (isset($unique_columns) && count($unique_columns) > 0) {
1951 $candidate_columns = $unique_columns;
1953 return array($candidate_columns, $needsort);
1954 } elseif (isset($index_columns) && count($index_columns) > 0) {
1955 $candidate_columns = $index_columns;
1957 return array($candidate_columns, $needsort);
1958 } elseif (isset($where_clause_columns) && count($where_clause_columns) > 0) {
1959 $candidate_columns = $where_clause_columns;
1961 return array($candidate_columns, $needsort);
1963 $candidate_columns = $search_tables;
1965 return array($candidate_columns, $needsort);