Upgraded phpmyadmin to 4.0.4 (All Languages) - No modifications yet
[openemr.git] / phpmyadmin / libraries / DBQbe.class.php
blob6213dd795471fbcd3fa103d369eebeff6890fc2b
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * Handles DB QBE search
6 * @package PhpMyAdmin
7 */
8 if (! defined('PHPMYADMIN')) {
9 exit;
12 /**
13 * Class to handle database QBE search
15 * @package PhpMyAdmin
17 class PMA_DbQbe
19 /**
20 * Database name
22 * @access private
23 * @var string
25 private $_db;
26 /**
27 * Table Names (selected/non-selected)
29 * @access private
30 * @var array
32 private $_criteriaTables;
33 /**
34 * Column Names
36 * @access private
37 * @var array
39 private $_columnNames;
40 /**
41 * Number of columns
43 * @access private
44 * @var integer
46 private $_criteria_column_count;
47 /**
48 * Number of Rows
50 * @access private
51 * @var integer
53 private $_criteria_row_count;
54 /**
55 * Whether to insert a new column
57 * @access private
58 * @var array
60 private $_criteriaColumnInsert;
61 /**
62 * Whether to delete a column
64 * @access private
65 * @var array
67 private $_criteriaColumnDelete;
68 /**
69 * Whether to insert a new row
71 * @access private
72 * @var array
74 private $_criteriaRowInsert;
75 /**
76 * Already set criteria values
78 * @access private
79 * @var array
81 private $_criteria;
82 /**
83 * Previously set criteria values
85 * @access private
86 * @var array
88 private $_prev_criteria;
89 /**
90 * AND/OR relation b/w criteria columns
92 * @access private
93 * @var array
95 private $_criteriaAndOrColumn;
96 /**
97 * AND/OR relation b/w criteria rows
99 * @access private
100 * @var array
102 private $_criteriaAndOrRow;
104 * Larget width of a column
106 * @access private
107 * @var string
109 private $_realwidth;
111 * Minimum width of a column
113 * @access private
114 * @var string
116 private $_form_column_width;
118 * Current criteria field
120 * @access private
121 * @var array
123 private $_curField;
125 * Current criteria Sort options
127 * @access private
128 * @var array
130 private $_curSort;
132 * Current criteria Show options
134 * @access private
135 * @var array
137 private $_curShow;
139 * Current criteria values
141 * @access private
142 * @var array
144 private $_curCriteria;
146 * Current criteria AND/OR column realtions
148 * @access private
149 * @var array
151 private $_curAndOrCol;
153 * New column count in case of add/delete
155 * @access private
156 * @var integer
158 private $_new_column_count;
160 * New row count in case of add/delete
162 * @access private
163 * @var integer
165 private $_new_row_count;
168 * Public Constructor
170 * @param string $db Database name
172 public function __construct($db)
174 $this->_db = $db;
175 // Sets criteria parameters
176 $this->_setSearchParams();
177 $this->_setCriteriaTablesAndColumns();
181 * Sets search parameters
183 * @return void
185 private function _setSearchParams()
187 // sets column count
188 $criteriaColumnCount = PMA_ifSetOr(
189 $_REQUEST['criteriaColumnCount'],
191 'numeric'
193 $criteriaColumnAdd = PMA_ifSetOr(
194 $_REQUEST['criteriaColumnAdd'],
196 'numeric'
198 $this->_criteria_column_count = max(
199 $criteriaColumnCount + $criteriaColumnAdd,
203 // sets row count
204 $rows = PMA_ifSetOr($_REQUEST['rows'], 0, 'numeric');
205 $criteriaRowAdd = PMA_ifSetOr($_REQUEST['criteriaRowAdd'], 0, 'numeric');
206 $this->_criteria_row_count = max($rows + $criteriaRowAdd, 0);
208 $this->_criteriaColumnInsert = PMA_ifSetOr(
209 $_REQUEST['criteriaColumnInsert'],
210 null,
211 'array'
213 $this->_criteriaColumnDelete = PMA_ifSetOr(
214 $_REQUEST['criteriaColumnDelete'],
215 null,
216 'array'
219 $this->_prev_criteria = isset($_REQUEST['prev_criteria'])
220 ? $_REQUEST['prev_criteria']
221 : array();
222 $this->_criteria = isset($_REQUEST['criteria'])
223 ? $_REQUEST['criteria']
224 : array_fill(0, $criteriaColumnCount, '');
226 $this->_criteriaRowInsert = isset($_REQUEST['criteriaRowInsert'])
227 ? $_REQUEST['criteriaRowInsert']
228 : array_fill(0, $criteriaColumnCount, '');
229 $this->_criteriaRowDelete = isset($_REQUEST['criteriaRowDelete'])
230 ? $_REQUEST['criteriaRowDelete']
231 : array_fill(0, $criteriaColumnCount, '');
232 $this->_criteriaAndOrRow = isset($_REQUEST['criteriaAndOrRow'])
233 ? $_REQUEST['criteriaAndOrRow']
234 : array_fill(0, $criteriaColumnCount, '');
235 $this->_criteriaAndOrColumn = isset($_REQUEST['criteriaAndOrColumn'])
236 ? $_REQUEST['criteriaAndOrColumn']
237 : array_fill(0, $criteriaColumnCount, '');
238 // sets minimum width
239 $this->_form_column_width = 12;
240 $this->_curField = array();
241 $this->_curSort = array();
242 $this->_curShow = array();
243 $this->_curCriteria = array();
244 $this->_curAndOrRow = array();
245 $this->_curAndOrCol = array();
249 * Sets criteria tables and columns
251 * @return void
253 private function _setCriteriaTablesAndColumns()
255 // The tables list sent by a previously submitted form
256 if (PMA_isValid($_REQUEST['TableList'], 'array')) {
257 foreach ($_REQUEST['TableList'] as $each_table) {
258 $this->_criteriaTables[$each_table] = ' selected="selected"';
260 } // end if
261 $all_tables = PMA_DBI_query(
262 'SHOW TABLES FROM ' . PMA_Util::backquote($this->_db) . ';',
263 null,
264 PMA_DBI_QUERY_STORE
266 $all_tables_count = PMA_DBI_num_rows($all_tables);
267 if (0 == $all_tables_count) {
268 PMA_Message::error(__('No tables found in database.'))->display();
269 exit;
271 // The tables list gets from MySQL
272 while (list($table) = PMA_DBI_fetch_row($all_tables)) {
273 $columns = PMA_DBI_get_columns($this->_db, $table);
275 if (empty($this->_criteriaTables[$table])
276 && ! empty($_REQUEST['TableList'])
278 $this->_criteriaTables[$table] = '';
279 } else {
280 $this->_criteriaTables[$table] = ' selected="selected"';
281 } // end if
283 // The fields list per selected tables
284 if ($this->_criteriaTables[$table] == ' selected="selected"') {
285 $each_table = PMA_Util::backquote($table);
286 $this->_columnNames[] = $each_table . '.*';
287 foreach ($columns as $each_column) {
288 $each_column = $each_table . '.'
289 . PMA_Util::backquote($each_column['Field']);
290 $this->_columnNames[] = $each_column;
291 // increase the width if necessary
292 $this->_form_column_width = max(
293 strlen($each_column),
294 $this->_form_column_width
296 } // end foreach
297 } // end if
298 } // end while
299 PMA_DBI_free_result($all_tables);
301 // sets the largest width found
302 $this->_realwidth = $this->_form_column_width . 'ex';
305 * Provides select options list containing column names
307 * @param integer $column_number Column Number (0,1,2) or more
308 * @param string $selected Selected criteria column name
310 * @return HTML for select options
312 private function _showColumnSelectCell($column_number, $selected = '')
314 $html_output = '';
315 $html_output .= '<td class="center">';
316 $html_output .= '<select name="criteriaColumn[' . $column_number . ']" size="1">';
317 $html_output .= '<option value="">&nbsp;</option>';
318 foreach ($this->_columnNames as $column) {
319 $html_output .= '<option value="' . htmlspecialchars($column) . '"'
320 . (($column === $selected) ? ' selected="selected"' : '') . '>'
321 . str_replace(' ', '&nbsp;', htmlspecialchars($column))
322 . '</option>';
324 $html_output .= '</select>';
325 $html_output .= '</td>';
326 return $html_output;
330 * Provides select options list containing sort options (ASC/DESC)
332 * @param integer $column_number Column Number (0,1,2) or more
333 * @param string $asc_selected Selected criteria 'Ascending'
334 * @param string $desc_selected Selected criteria 'Descending'
336 * @return HTML for select options
338 private function _getSortSelectCell($column_number, $asc_selected = '',
339 $desc_selected = ''
341 $html_output = '<td class="center">';
342 $html_output .= '<select style="width: ' . $this->_realwidth
343 . '" name="criteriaSort[' . $column_number . ']" size="1">';
344 $html_output .= '<option value="">&nbsp;</option>';
345 $html_output .= '<option value="ASC"' . $asc_selected . '>'
346 . __('Ascending')
347 . '</option>';
348 $html_output .= '<option value="DESC"' . $desc_selected . '>'
349 . __('Descending')
350 . '</option>';
351 $html_output .= '</select>';
352 $html_output .= '</td>';
353 return $html_output;
357 * Provides search form's row containing column select options
359 * @return HTML for search table's row
361 private function _getColumnNamesRow()
363 $html_output = '<tr class="odd noclick">';
364 $html_output .= '<th>' . __('Column') . ':</th>';
365 $new_column_count = 0;
366 for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) {
367 if (isset($this->_criteriaColumnInsert[$column_index])
368 && $this->_criteriaColumnInsert[$column_index] == 'on'
370 $html_output .= $this->_showColumnSelectCell(
371 $new_column_count
373 $new_column_count++;
375 if (! empty($this->_criteriaColumnDelete)
376 && isset($this->_criteriaColumnDelete[$column_index])
377 && $this->_criteriaColumnDelete[$column_index] == 'on'
379 continue;
381 $selected = '';
382 if (isset($_REQUEST['criteriaColumn'][$column_index])) {
383 $selected = $_REQUEST['criteriaColumn'][$column_index];
384 $this->_curField[$new_column_count]
385 = $_REQUEST['criteriaColumn'][$column_index];
387 $html_output .= $this->_showColumnSelectCell(
388 $new_column_count,
389 $selected
391 $new_column_count++;
392 } // end for
393 $this->_new_column_count = $new_column_count;
394 $html_output .= '</tr>';
395 return $html_output;
399 * Provides search form's row containing sort(ASC/DESC) select options
401 * @return HTML for search table's row
403 private function _getSortRow()
405 $html_output = '<tr class="even noclick">';
406 $html_output .= '<th>' . __('Sort') . ':</th>';
407 $new_column_count = 0;
408 for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) {
409 if (! empty($this->_criteriaColumnInsert)
410 && isset($this->_criteriaColumnInsert[$column_index])
411 && $this->_criteriaColumnInsert[$column_index] == 'on'
413 $html_output .= $this->_getSortSelectCell($new_column_count);
414 $new_column_count++;
415 } // end if
417 if (! empty($this->_criteriaColumnDelete)
418 && isset($this->_criteriaColumnDelete[$column_index])
419 && $this->_criteriaColumnDelete[$column_index] == 'on'
421 continue;
423 // If they have chosen all fields using the * selector,
424 // then sorting is not available, Fix for Bug #570698
425 if (isset($_REQUEST['criteriaSort'][$column_index])
426 && isset($_REQUEST['criteriaColumn'][$column_index])
427 && substr($_REQUEST['criteriaColumn'][$column_index], -2) == '.*'
429 $_REQUEST['criteriaSort'][$column_index] = '';
430 } //end if
431 // Set asc_selected
432 if (isset($_REQUEST['criteriaSort'][$column_index])
433 && $_REQUEST['criteriaSort'][$column_index] == 'ASC'
435 $this->_curSort[$new_column_count]
436 = $_REQUEST['criteriaSort'][$column_index];
437 $asc_selected = ' selected="selected"';
438 } else {
439 $asc_selected = '';
440 } // end if
441 // Set desc selected
442 if (isset($_REQUEST['criteriaSort'][$column_index])
443 && $_REQUEST['criteriaSort'][$column_index] == 'DESC'
445 $this->_curSort[$new_column_count]
446 = $_REQUEST['criteriaSort'][$column_index];
447 $desc_selected = ' selected="selected"';
448 } else {
449 $desc_selected = '';
450 } // end if
451 $html_output .= $this->_getSortSelectCell(
452 $new_column_count, $asc_selected, $desc_selected
454 $new_column_count++;
455 } // end for
456 $html_output .= '</tr>';
457 return $html_output;
461 * Provides search form's row containing SHOW checkboxes
463 * @return HTML for search table's row
465 private function _getShowRow()
467 $html_output = '<tr class="odd noclick">';
468 $html_output .= '<th>' . __('Show') . ':</th>';
469 $new_column_count = 0;
470 for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) {
471 if (! empty($this->_criteriaColumnInsert)
472 && isset($this->_criteriaColumnInsert[$column_index])
473 && $this->_criteriaColumnInsert[$column_index] == 'on'
475 $html_output .= '<td class="center">';
476 $html_output .= '<input type="checkbox"'
477 . ' name="criteriaShow[' . $new_column_count . ']" />';
478 $html_output .= '</td>';
479 $new_column_count++;
480 } // end if
481 if (! empty($this->_criteriaColumnDelete)
482 && isset($this->_criteriaColumnDelete[$column_index])
483 && $this->_criteriaColumnDelete[$column_index] == 'on'
485 continue;
487 if (isset($_REQUEST['criteriaShow'][$column_index])) {
488 $checked_options = ' checked="checked"';
489 $this->_curShow[$new_column_count]
490 = $_REQUEST['criteriaShow'][$column_index];
491 } else {
492 $checked_options = '';
494 $html_output .= '<td class="center">';
495 $html_output .= '<input type="checkbox"'
496 . ' name="criteriaShow[' . $new_column_count . ']"'
497 . $checked_options . ' />';
498 $html_output .= '</td>';
499 $new_column_count++;
500 } // end for
501 $html_output .= '</tr>';
502 return $html_output;
506 * Provides search form's row containing criteria Inputboxes
508 * @return HTML for search table's row
510 private function _getCriteriaInputboxRow()
512 $html_output = '<tr class="even noclick">';
513 $html_output .= '<th>' . __('Criteria') . ':</th>';
514 $new_column_count = 0;
515 for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) {
516 if (! empty($this->_criteriaColumnInsert)
517 && isset($this->_criteriaColumnInsert[$column_index])
518 && $this->_criteriaColumnInsert[$column_index] == 'on'
520 $html_output .= '<td class="center">';
521 $html_output .= '<input type="text"'
522 . ' name="criteria[' . $new_column_count . ']"'
523 . ' value=""'
524 . ' class="textfield"'
525 . ' style="width: ' . $this->_realwidth . '"'
526 . ' size="20" />';
527 $html_output .= '</td>';
528 $new_column_count++;
529 } // end if
530 if (! empty($this->_criteriaColumnDelete)
531 && isset($this->_criteriaColumnDelete[$column_index])
532 && $this->_criteriaColumnDelete[$column_index] == 'on'
534 continue;
536 if (isset($this->_criteria[$column_index])) {
537 $tmp_criteria = $this->_criteria[$column_index];
539 if ((empty($this->_prev_criteria)
540 || ! isset($this->_prev_criteria[$column_index]))
541 || $this->_prev_criteria[$column_index] != htmlspecialchars($tmp_criteria)
543 $this->_curCriteria[$new_column_count] = $tmp_criteria;
544 } else {
545 $this->_curCriteria[$new_column_count]
546 = $this->_prev_criteria[$column_index];
548 $html_output .= '<td class="center">';
549 $html_output .= '<input type="hidden"'
550 . ' name="prev_criteria[' . $new_column_count . ']"'
551 . ' value="' . htmlspecialchars($this->_curCriteria[$new_column_count]) . '" />';
552 $html_output .= '<input type="text"'
553 . ' name="criteria[' . $new_column_count . ']"'
554 . ' value="' . htmlspecialchars($tmp_criteria) . '"'
555 . ' class="textfield"'
556 . ' style="width: ' . $this->_realwidth . '"'
557 . ' size="20" />';
558 $html_output .= '</td>';
559 $new_column_count++;
560 } // end for
561 $html_output .= '</tr>';
562 return $html_output;
566 * Provides footer options for adding/deleting row/columns
568 * @param string $type Whether row or column
570 * @return HTML for footer options
572 private function _getFootersOptions($type)
574 $html_output = '<div class="floatleft">';
575 $html_output .= (($type == 'row')
576 ? __('Add/Delete criteria rows') : __('Add/Delete columns'));
577 $html_output .= ':<select size="1" name="'
578 . (($type == 'row') ? 'criteriaRowAdd' : 'criteriaColumnAdd') . '">';
579 $html_output .= '<option value="-3">-3</option>';
580 $html_output .= '<option value="-2">-2</option>';
581 $html_output .= '<option value="-1">-1</option>';
582 $html_output .= '<option value="0" selected="selected">0</option>';
583 $html_output .= '<option value="1">1</option>';
584 $html_output .= '<option value="2">2</option>';
585 $html_output .= '<option value="3">3</option>';
586 $html_output .= '</select>';
587 $html_output .= '</div>';
588 return $html_output;
592 * Provides search form table's footer options
594 * @return HTML for table footer
596 private function _getTableFooters()
598 $html_output = '<fieldset class="tblFooters">';
599 $html_output .= $this->_getFootersOptions("row");
600 $html_output .= $this->_getFootersOptions("column");
601 $html_output .= '<div class="floatleft">';
602 $html_output .= '<input type="submit" name="modify"'
603 . 'value="' . __('Update Query') . '" />';
604 $html_output .= '</div>';
605 $html_output .= '</fieldset>';
606 return $html_output;
610 * Provides a select list of database tables
612 * @return HTML for table select list
614 private function _getTablesList()
616 $html_output = '<div class="floatleft">';
617 $html_output .= '<fieldset>';
618 $html_output .= '<legend>' . __('Use Tables') . '</legend>';
619 // Build the options list for each table name
620 $options = '';
621 $numTableListOptions = 0;
622 foreach ($this->_criteriaTables as $key => $val) {
623 $options .= '<option value="' . htmlspecialchars($key) . '"' . $val . '>'
624 . (str_replace(' ', '&nbsp;', htmlspecialchars($key))) . '</option>';
625 $numTableListOptions++;
627 $html_output .= '<select name="TableList[]"'
628 . ' multiple="multiple" id="listTable"'
629 . ' size="' . (($numTableListOptions > 30) ? '15' : '7') . '">';
630 $html_output .= $options;
631 $html_output .= '</select>';
632 $html_output .= '</fieldset>';
633 $html_output .= '<fieldset class="tblFooters">';
634 $html_output .= '<input type="submit" name="modify" value="'
635 . __('Update Query') . '" />';
636 $html_output .= '</fieldset>';
637 $html_output .= '</div>';
638 return $html_output;
642 * Provides And/Or modification cell along with Insert/Delete options
643 * (For modifying search form's table columns)
645 * @param integer $column_number Column Number (0,1,2) or more
646 * @param array $selected Selected criteria column name
648 * @return HTML for modification cell
650 private function _getAndOrColCell($column_number, $selected = null)
652 $html_output = '<td class="center">';
653 $html_output .= '<strong>' . __('Or') . ':</strong>';
654 $html_output .= '<input type="radio"'
655 . ' name="criteriaAndOrColumn[' . $column_number . ']"'
656 . ' value="or"' . $selected['or'] . ' />';
657 $html_output .= '&nbsp;&nbsp;<strong>' . __('And') . ':</strong>';
658 $html_output .= '<input type="radio"'
659 . ' name="criteriaAndOrColumn[' . $column_number . ']"'
660 . ' value="and"' . $selected['and'] . ' />';
661 $html_output .= '<br />' . __('Ins');
662 $html_output .= '<input type="checkbox"'
663 . ' name="criteriaColumnInsert[' . $column_number . ']" />';
664 $html_output .= '&nbsp;&nbsp;' . __('Del');
665 $html_output .= '<input type="checkbox"'
666 . ' name="criteriaColumnDelete[' . $column_number . ']" />';
667 $html_output .= '</td>';
668 return $html_output;
672 * Provides search form's row containing column modifications options
673 * (For modifying search form's table columns)
675 * @return HTML for search table's row
677 private function _getModifyColumnsRow()
679 $html_output = '<tr class="even noclick">';
680 $html_output .= '<th>' . __('Modify') . ':</th>';
681 $new_column_count = 0;
682 for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) {
683 if (! empty($this->_criteriaColumnInsert)
684 && isset($this->_criteriaColumnInsert[$column_index])
685 && $this->_criteriaColumnInsert[$column_index] == 'on'
687 $html_output .= $this->_getAndOrColCell($new_column_count);
688 $new_column_count++;
689 } // end if
691 if (! empty($this->_criteriaColumnDelete)
692 && isset($this->_criteriaColumnDelete[$column_index])
693 && $this->_criteriaColumnDelete[$column_index] == 'on'
695 continue;
698 if (isset($this->_criteriaAndOrColumn[$column_index])) {
699 $this->_curAndOrCol[$new_column_count]
700 = $this->_criteriaAndOrColumn[$column_index];
702 if (isset($this->_criteriaAndOrColumn[$column_index])
703 && $this->_criteriaAndOrColumn[$column_index] == 'or'
705 $checked_options['or'] = ' checked="checked"';
706 $checked_options['and'] = '';
707 } else {
708 $checked_options['and'] = ' checked="checked"';
709 $checked_options['or'] = '';
711 $html_output .= $this->_getAndOrColCell(
712 $new_column_count,
713 $checked_options
715 $new_column_count++;
716 } // end for
717 $html_output .= '</tr>';
718 return $html_output;
722 * Provides Insert/Delete options for criteria inputbox
723 * with AND/OR relationship modification options
725 * @param integer $row_index Number of criteria row
726 * @param string $checked_options If checked
728 * @return HTML
730 private function _getInsDelAndOrCell($row_index, $checked_options)
732 $html_output = '<td class="' . $GLOBALS['cell_align_right'] . ' nowrap">';
733 $html_output .= '<!-- Row controls -->';
734 $html_output .= '<table class="nospacing nopadding">';
735 $html_output .= '<tr>';
736 $html_output .= '<td class="' . $GLOBALS['cell_align_right'] . ' nowrap">';
737 $html_output .= '<small>' . __('Ins') . ':</small>';
738 $html_output .= '<input type="checkbox"'
739 . ' name="criteriaRowInsert[' . $row_index . ']" />';
740 $html_output .= '</td>';
741 $html_output .= '<td class="' . $GLOBALS['cell_align_right'] . '">';
742 $html_output .= '<strong>' . __('And') . ':</strong>';
743 $html_output .= '</td>';
744 $html_output .= '<td>';
745 $html_output .= '<input type="radio"'
746 . ' name="criteriaAndOrRow[' . $row_index . ']" value="and"'
747 . $checked_options['and'] . ' />';
748 $html_output .= '</td>';
749 $html_output .= '</tr>';
750 $html_output .= '<tr>';
751 $html_output .= '<td class="' . $GLOBALS['cell_align_right'] . ' nowrap">';
752 $html_output .= '<small>' . __('Del') . ':</small>';
753 $html_output .= '<input type="checkbox"'
754 . ' name="criteriaRowDelete[' . $row_index . ']" />';
755 $html_output .= '</td>';
756 $html_output .= '<td class="' . $GLOBALS['cell_align_right'] . '">';
757 $html_output .= '<strong>' . __('Or') . ':</strong>';
758 $html_output .= '</td>';
759 $html_output .= '<td>';
760 $html_output .= '<input type="radio"'
761 . ' name="criteriaAndOrRow[' . $row_index . ']"'
762 . ' value="or"' . $checked_options['or'] . ' />';
763 $html_output .= '</td>';
764 $html_output .= '</tr>';
765 $html_output .= '</table>';
766 $html_output .= '</td>';
767 return $html_output;
771 * Provides rows for criteria inputbox Insert/Delete options
772 * with AND/OR relationship modification options
774 * @param integer $new_row_index New row index if rows are added/deleted
775 * @param integer $row_index Row index
777 * @return HTML table rows
779 private function _getInputboxRow($new_row_index, $row_index)
781 $html_output = '';
782 $new_column_count = 0;
783 for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) {
784 if (! empty($this->_criteriaColumnInsert)
785 && isset($this->_criteriaColumnInsert[$column_index])
786 && $this->_criteriaColumnInsert[$column_index] == 'on'
788 $or = 'Or' . $new_row_index . '[' . $new_column_count . ']';
789 $html_output .= '<td class="center">';
790 $html_output .= '<input type="text"'
791 . ' name="Or' . $or . '" class="textfield"'
792 . ' style="width: ' . $this->_realwidth . '" size="20" />';
793 $html_output .= '</td>';
794 $new_column_count++;
795 } // end if
796 if (! empty($this->_criteriaColumnDelete)
797 && isset($this->_criteriaColumnDelete[$column_index])
798 && $this->_criteriaColumnDelete[$column_index] == 'on'
800 continue;
802 $or = 'Or' . $new_row_index;
803 if (! empty($_POST[$or]) && isset($_POST[$or][$column_index])) {
804 $tmp_or = $_POST[$or][$column_index];
805 } else {
806 $tmp_or = '';
808 $html_output .= '<td class="center">';
809 $html_output .= '<input type="text"'
810 . ' name="Or' . $new_row_index . '[' . $new_column_count . ']' . '"'
811 . ' value="' . htmlspecialchars($tmp_or) . '" class="textfield"'
812 . ' style="width: ' . $this->_realwidth . '" size="20" />';
813 $html_output .= '</td>';
814 if (! empty(${$or}) && isset(${$or}[$column_index])) {
815 $GLOBALS[${'cur' . $or}][$new_column_count] = ${$or}[$column_index];
817 $new_column_count++;
818 } // end for
819 return $html_output;
823 * Provides rows for criteria inputbox Insert/Delete options
824 * with AND/OR relationship modification options
826 * @return HTML table rows
828 private function _getInsDelAndOrCriteriaRows()
830 $html_output = '';
831 $new_row_count = 0;
832 $odd_row = true;
833 for ($row_index = 0; $row_index <= $this->_criteria_row_count; $row_index++) {
834 if (isset($this->_criteriaRowInsert[$row_index])
835 && $this->_criteriaRowInsert[$row_index] == 'on'
837 $checked_options['or'] = ' checked="checked"';
838 $checked_options['and'] = '';
839 $html_output .= '<tr class="' . ($odd_row ? 'odd' : 'even') . ' noclick">';
840 $html_output .= $this->_getInsDelAndOrCell(
841 $new_row_count, $checked_options
843 $html_output .= $this->_getInputboxRow(
844 $new_row_count, $row_index
846 $new_row_count++;
847 $html_output .= '</tr>';
848 $odd_row =! $odd_row;
849 } // end if
850 if (isset($this->_criteriaRowDelete[$row_index])
851 && $this->_criteriaRowDelete[$row_index] == 'on'
853 continue;
855 if (isset($this->_criteriaAndOrRow[$row_index])) {
856 $this->_curAndOrRow[$new_row_count]
857 = $this->_criteriaAndOrRow[$row_index];
859 if (isset($this->_criteriaAndOrRow[$row_index])
860 && $this->_criteriaAndOrRow[$row_index] == 'and'
862 $checked_options['and'] = ' checked="checked"';
863 $checked_options['or'] = '';
864 } else {
865 $checked_options['or'] = ' checked="checked"';
866 $checked_options['and'] = '';
868 $html_output .= '<tr class="' . ($odd_row ? 'odd' : 'even') . ' noclick">';
869 $html_output .= $this->_getInsDelAndOrCell(
870 $new_row_count, $checked_options
872 $html_output .= $this->_getInputboxRow(
873 $new_row_count, $row_index
875 $new_row_count++;
876 $html_output .= '</tr>';
877 $odd_row =! $odd_row;
878 } // end for
879 $this->_new_row_count = $new_row_count;
880 return $html_output;
884 * Provides SELECT clause for building SQL query
886 * @return Select clause
888 private function _getSelectClause()
890 $select_clause = '';
891 $select_clauses = array();
892 for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) {
893 if (! empty($this->_curField[$column_index])
894 && isset($this->_curShow[$column_index])
895 && $this->_curShow[$column_index] == 'on'
897 $select_clauses[] = $this->_curField[$column_index];
899 } // end for
900 if ($select_clauses) {
901 $select_clause = 'SELECT '
902 . htmlspecialchars(implode(", ", $select_clauses)) . "\n";
904 return $select_clause;
908 * Provides WHERE clause for building SQL query
910 * @return Where clause
912 private function _getWhereClause()
914 $where_clause = '';
915 $criteria_cnt = 0;
916 for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) {
917 if (! empty($this->_curField[$column_index])
918 && ! empty($this->_curCriteria[$column_index])
919 && $column_index
920 && isset($last_where)
921 && isset($this->_curAndOrCol)
923 $where_clause .= ' ' . strtoupper($this->_curAndOrCol[$last_where]) . ' ';
925 if (! empty($this->_curField[$column_index])
926 && ! empty($this->_curCriteria[$column_index])
928 $where_clause .= '(' . $this->_curField[$column_index] . ' '
929 . $this->_curCriteria[$column_index] . ')';
930 $last_where = $column_index;
931 $criteria_cnt++;
933 } // end for
934 if ($criteria_cnt > 1) {
935 $where_clause = '(' . $where_clause . ')';
937 // OR rows ${'cur' . $or}[$column_index]
938 if (! isset($this->_curAndOrRow)) {
939 $this->_curAndOrRow = array();
941 for ($row_index = 0; $row_index <= $this->_criteria_row_count; $row_index++) {
942 $criteria_cnt = 0;
943 $qry_orwhere = '';
944 $last_orwhere = '';
945 for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) {
946 if (! empty($this->_curField[$column_index])
947 && ! empty(${'curOr' . $row_index}[$column_index])
948 && $column_index
950 $qry_orwhere .= ' ' . strtoupper($this->_curAndOrCol[$last_orwhere]) . ' ';
952 if (! empty($this->_curField[$column_index])
953 && ! empty(${'curOr' . $row_index}[$column_index])
955 $qry_orwhere .= '(' . $this->_curField[$column_index]
956 . ' '
957 . ${'curOr' . $row_index}[$column_index]
958 . ')';
959 $last_orwhere = $column_index;
960 $criteria_cnt++;
962 } // end for
963 if ($criteria_cnt > 1) {
964 $qry_orwhere = '(' . $qry_orwhere . ')';
966 if (! empty($qry_orwhere)) {
967 $where_clause .= "\n"
968 . strtoupper(
969 isset($this->_curAndOrRow[$row_index])
970 ? $this->_curAndOrRow[$row_index] . ' '
971 : ''
973 . $qry_orwhere;
974 } // end if
975 } // end for
977 if (! empty($where_clause) && $where_clause != '()') {
978 $where_clause = 'WHERE ' . htmlspecialchars($where_clause) . "\n";
979 } // end if
980 return $where_clause;
984 * Provides ORDER BY clause for building SQL query
986 * @return Order By clause
988 private function _getOrderByClause()
990 $orderby_clause = '';
991 $orderby_clauses = array();
992 for ($column_index = 0; $column_index < $this->_criteria_column_count; $column_index++) {
993 // if all columns are chosen with * selector,
994 // then sorting isn't available
995 // Fix for Bug #570698
996 if (! empty($this->_curField[$column_index])
997 && ! empty($this->_curSort[$column_index])
999 if (substr($this->_curField[$column_index], -2) == '.*') {
1000 continue;
1002 $orderby_clauses[] = $this->_curField[$column_index] . ' '
1003 . $this->_curSort[$column_index];
1005 } // end for
1006 if ($orderby_clauses) {
1007 $orderby_clause = 'ORDER BY '
1008 . htmlspecialchars(implode(", ", $orderby_clauses)) . "\n";
1010 return $orderby_clause;
1014 * Provides UNIQUE columns and INDEX columns present in criteria tables
1016 * @param array $all_tables Tables involved in the search
1017 * @param array $all_columns Columns involved in the search
1018 * @param array $where_clause_columns Columns having criteria where clause
1020 * @return array having UNIQUE and INDEX columns
1022 private function _getIndexes($all_tables, $all_columns,
1023 $where_clause_columns
1025 $unique_columns = array();
1026 $index_columns = array();
1028 foreach ($all_tables as $table) {
1029 $indexes = PMA_DBI_get_table_indexes($this->_db, $table);
1030 foreach ($indexes as $index) {
1031 $column = $table . '.' . $index['Column_name'];
1032 if (isset($all_columns[$column])) {
1033 if ($index['Non_unique'] == 0) {
1034 if (isset($where_clause_columns[$column])) {
1035 $unique_columns[$column] = 'Y';
1036 } else {
1037 $unique_columns[$column] = 'N';
1039 } else {
1040 if (isset($where_clause_columns[$column])) {
1041 $index_columns[$column] = 'Y';
1042 } else {
1043 $index_columns[$column] = 'N';
1047 } // end while (each index of a table)
1048 } // end while (each table)
1050 return array(
1051 'unique' => $unique_columns,
1052 'index' => $index_columns
1057 * Provides UNIQUE columns and INDEX columns present in criteria tables
1059 * @param array $all_tables Tables involved in the search
1060 * @param array $all_columns Columns involved in the search
1061 * @param array $where_clause_columns Columns having criteria where clause
1063 * @return array having UNIQUE and INDEX columns
1065 private function _getLeftJoinColumnCandidates($all_tables, $all_columns,
1066 $where_clause_columns
1068 PMA_DBI_select_db($this->_db);
1069 $candidate_columns = array();
1071 // Get unique columns and index columns
1072 $indexes = $this->_getIndexes(
1073 $all_tables, $all_columns, $where_clause_columns
1075 $unique_columns = $indexes['unique'];
1076 $index_columns = $indexes['index'];
1078 // now we want to find the best.
1079 if (isset($unique_columns) && count($unique_columns) > 0) {
1080 $candidate_columns = $unique_columns;
1081 $needsort = 1;
1082 } elseif (isset($index_columns) && count($index_columns) > 0) {
1083 $candidate_columns = $index_columns;
1084 $needsort = 1;
1085 } elseif (isset($where_clause_columns) && count($where_clause_columns) > 0) {
1086 $candidate_columns = $where_clause_columns;
1087 $needsort = 0;
1088 } else {
1089 $candidate_columns = $all_tables;
1090 $needsort = 0;
1093 // If we came up with $unique_columns (very good) or $index_columns (still
1094 // good) as $candidate_columns we want to check if we have any 'Y' there
1095 // (that would mean that they were also found in the whereclauses
1096 // which would be great). if yes, we take only those
1097 if ($needsort == 1) {
1098 foreach ($candidate_columns as $column => $is_where) {
1099 $table = explode('.', $column);
1100 $table = $table[0];
1101 if ($is_where == 'Y') {
1102 $vg[$column] = $table;
1103 } else {
1104 $sg[$column] = $table;
1107 if (isset($vg)) {
1108 $candidate_columns = $vg;
1109 // Candidates restricted in index+where
1110 } else {
1111 $candidate_columns = $sg;
1112 // None of the candidates where in a where-clause
1116 return $candidate_columns;
1120 * Provides the main table to form the LEFT JOIN clause
1122 * @param array $all_tables Tables involved in the search
1123 * @param array $all_columns Columns involved in the search
1124 * @param array $where_clause_columns Columns having criteria where clause
1125 * @param array $where_clause_tables Tables having criteria where clause
1127 * @return string table name
1129 private function _getMasterTable($all_tables, $all_columns,
1130 $where_clause_columns, $where_clause_tables
1132 $master = '';
1133 if (count($where_clause_tables) == 1) {
1134 // If there is exactly one column that has a decent where-clause
1135 // we will just use this
1136 $master = key($where_clause_tables);
1137 } else {
1138 // Now let's find out which of the tables has an index
1139 // (When the control user is the same as the normal user
1140 // because he is using one of his databases as pmadb,
1141 // the last db selected is not always the one where we need to work)
1142 $candidate_columns = $this->_getLeftJoinColumnCandidates(
1143 $all_tables, $all_columns, $where_clause_columns
1145 // If our array of candidates has more than one member we'll just
1146 // find the smallest table.
1147 // Of course the actual query would be faster if we check for
1148 // the Criteria which gives the smallest result set in its table,
1149 // but it would take too much time to check this
1150 if (count($candidate_columns) > 1) {
1151 // Of course we only want to check each table once
1152 $checked_tables = $candidate_columns;
1153 foreach ($candidate_columns as $table) {
1154 if ($checked_tables[$table] != 1) {
1155 $tsize[$table] = PMA_Table::countRecords(
1156 $this->_db,
1157 $table,
1158 false
1160 $checked_tables[$table] = 1;
1162 $csize[$table] = $tsize[$table];
1164 asort($csize);
1165 reset($csize);
1166 $master = key($csize); // Smallest
1167 } else {
1168 reset($candidate_columns);
1169 $master = current($candidate_columns); // Only one single candidate
1171 } // end if (exactly one where clause)
1172 return $master;
1176 * Provides columns and tables that have valid where clause criteria
1178 * @return array
1180 private function _getWhereClauseTablesAndColumns()
1182 $where_clause_columns = array();
1183 $where_clause_tables = array();
1184 // Now we need all tables that we have in the where clause
1185 for ($column_index = 0; $column_index < count($this->_criteria); $column_index++) {
1186 $current_table = explode('.', $_POST['criteriaColumn'][$column_index]);
1187 if (empty($current_table[0]) || empty($current_table[1])) {
1188 continue;
1189 } // end if
1190 $table = str_replace('`', '', $current_table[0]);
1191 $column = str_replace('`', '', $current_table[1]);
1192 $column = $table . '.' . $column;
1193 // Now we know that our array has the same numbers as $criteria
1194 // we can check which of our columns has a where clause
1195 if (! empty($this->_criteria[$column_index])) {
1196 if (substr($this->_criteria[$column_index], 0, 1) == '='
1197 || stristr($this->_criteria[$column_index], 'is')
1199 $where_clause_columns[$column] = $column;
1200 $where_clause_tables[$table] = $table;
1202 } // end if
1203 } // end for
1204 return array(
1205 'where_clause_tables' => $where_clause_tables,
1206 'where_clause_columns' => $where_clause_columns
1211 * Provides FROM clause for building SQL query
1213 * @param string $cfgRelation Relation Settings
1215 * @return FROM clause
1217 private function _getFromClause($cfgRelation)
1219 $from_clause = '';
1220 if (isset($_POST['criteriaColumn']) && count($_POST['criteriaColumn']) > 0) {
1221 // Initialize some variables
1222 $all_tables = $all_columns = $known_tables = $remaining_tables = array();
1223 $left_join = '';
1225 // We only start this if we have fields, otherwise it would be dumb
1226 foreach ($_POST['criteriaColumn'] as $value) {
1227 $parts = explode('.', $value);
1228 if (! empty($parts[0]) && ! empty($parts[1])) {
1229 $table = str_replace('`', '', $parts[0]);
1230 $all_tables[$table] = $table;
1231 $all_columns[] = $table . '.' . str_replace('`', '', $parts[1]);
1233 } // end while
1235 // Create LEFT JOINS out of Relations
1236 if ($cfgRelation['relwork'] && count($all_tables) > 0) {
1237 // Get tables and columns with valid where clauses
1238 $valid_where_clauses = $this->_getWhereClauseTablesAndColumns();
1239 $where_clause_tables = $valid_where_clauses['where_clause_tables'];
1240 $where_clause_columns = $valid_where_clauses['where_clause_columns'];
1241 // Get master table
1242 $master = $this->_getMasterTable(
1243 $all_tables, $all_columns,
1244 $where_clause_columns, $where_clause_tables
1246 $from_clause = PMA_Util::backquote($master)
1247 . PMA_getRelatives($all_tables, $master);
1249 } // end if ($cfgRelation['relwork'] && count($all_tables) > 0)
1250 } // end count($_POST['criteriaColumn']) > 0
1252 // In case relations are not defined, just generate the FROM clause
1253 // from the list of tables, however we don't generate any JOIN
1254 if (empty($from_clause) && isset($all_tables)) {
1255 $from_clause = implode(', ', $all_tables);
1257 return $from_clause;
1261 * Provides the generated SQL query
1263 * @param string $cfgRelation Relation Settings
1265 * @return string SQL query
1267 private function _getSQLQuery($cfgRelation)
1269 $sql_query = '';
1270 // get SELECT clause
1271 $sql_query .= $this->_getSelectClause();
1272 // get FROM clause
1273 $from_clause = $this->_getFromClause($cfgRelation);
1274 if (! empty($from_clause)) {
1275 $sql_query .= 'FROM ' . htmlspecialchars($from_clause) . "\n";
1277 // get WHERE clause
1278 $sql_query .= $this->_getWhereClause();
1279 // get ORDER BY clause
1280 $sql_query .= $this->_getOrderByClause();
1281 return $sql_query;
1285 * Provides the generated QBE form
1287 * @param string $cfgRelation Relation Settings
1289 * @return string QBE form
1291 public function getSelectionForm($cfgRelation)
1293 $html_output = '<form action="db_qbe.php" method="post">';
1294 $html_output .= '<fieldset>';
1295 $html_output .= '<table class="data" style="width: 100%;">';
1296 // Get table's <tr> elements
1297 $html_output .= $this->_getColumnNamesRow();
1298 $html_output .= $this->_getSortRow();
1299 $html_output .= $this->_getShowRow();
1300 $html_output .= $this->_getCriteriaInputboxRow();
1301 $html_output .= $this->_getInsDelAndOrCriteriaRows();
1302 $html_output .= $this->_getModifyColumnsRow();
1303 $html_output .= '</table>';
1304 $this->_new_row_count--;
1305 $url_params['db'] = $this->_db;
1306 $url_params['criteriaColumnCount'] = $this->_new_column_count;
1307 $url_params['rows'] = $this->_new_row_count;
1308 $html_output .= PMA_generate_common_hidden_inputs($url_params);
1309 $html_output .= '</fieldset>';
1310 // get footers
1311 $html_output .= $this->_getTableFooters();
1312 // get tables select list
1313 $html_output .= $this->_getTablesList();
1314 $html_output .= '</form>';
1315 $html_output .= '<form action="db_qbe.php" method="post">';
1316 $html_output .= PMA_generate_common_hidden_inputs(array('db' => $this->_db));
1317 // get SQL query
1318 $html_output .= '<div class="floatleft">';
1319 $html_output .= '<fieldset>';
1320 $html_output .= '<legend>'
1321 . sprintf(
1322 __('SQL query on database <b>%s</b>:'),
1323 PMA_Util::getDbLink($this->_db)
1325 $html_output .= '</legend>';
1326 $text_dir = 'ltr';
1327 $html_output .= '<textarea cols="80" name="sql_query" id="textSqlquery"'
1328 . ' rows="' . ((count($this->_criteriaTables) > 30) ? '15' : '7') . '"'
1329 . ' dir="' . $text_dir . '">';
1330 $html_output .= $this->_getSQLQuery($cfgRelation);
1331 $html_output .= '</textarea>';
1332 $html_output .= '</fieldset>';
1333 // displays form's footers
1334 $html_output .= '<fieldset class="tblFooters">';
1335 $html_output .= '<input type="hidden" name="submit_sql" value="1" />';
1336 $html_output .= '<input type="submit" value="' . __('Submit Query') . '" />';
1337 $html_output .= '</fieldset>';
1338 $html_output .= '</div>';
1339 $html_output .= '</form>';
1340 return $html_output;