diff --git a/libraries/TableSearch.class.php b/libraries/TableSearch.class.php index d2521c064b..a3b2b2ff13 100644 --- a/libraries/TableSearch.class.php +++ b/libraries/TableSearch.class.php @@ -101,7 +101,7 @@ class PMA_TableSearch $this->_columnCollations = array(); $this->_geomColumnFlag = false; $this->_foreigners = array(); - + // Loads table's information $this->_loadTableInfo($this->_db, $this->_table); } @@ -408,5 +408,790 @@ EOT; } return $str; } + + /** + * Return the where clause in case column's type is ENUM. + * + * @param mixed $criteriaValues Search criteria input + * @param string $func_type Search fucntion/operator + * + * @return string part of where clause. + */ + private function _getEnumWhereClause($criteriaValues, $func_type) + { + $where = ''; + if (! empty($criteriaValues)) { + if (! is_array($criteriaValues)) { + $criteriaValues = explode(',', $criteriaValues); + } + $enum_selected_count = count($criteriaValues); + if ($func_type == '=' && $enum_selected_count > 1) { + $func_type = 'IN'; + $parens_open = '('; + $parens_close = ')'; + + } elseif ($func_type == '!=' && $enum_selected_count > 1) { + $func_type = 'NOT IN'; + $parens_open = '('; + $parens_close = ')'; + + } else { + $parens_open = ''; + $parens_close = ''; + } + $enum_where = '\'' . PMA_sqlAddslashes($criteriaValues[0]) . '\''; + for ($e = 1; $e < $enum_selected_count; $e++) { + $enum_where .= ', \'' . PMA_sqlAddslashes($criteriaValues[$e]) + . '\''; + } + + $where = ' ' . $func_type . ' ' . $parens_open + . $enum_where . $parens_close; + } + return $where; + } + + /** + * Return the where clause for a geometrical column. + * + * @param mixed $criteriaValues Search criteria input + * @param string $names Name of the column on which search is submitted + * @param string $func_type Search fucntion/operator + * @param bool $geom_func Whether geometry functions should be applied + * + * @return string part of where clause. + */ + private function _getGeomWhereClause($criteriaValues, $names, $func_type, $geom_func = null) + { + $geom_unary_functions = array( + 'IsEmpty' => 1, + 'IsSimple' => 1, + 'IsRing' => 1, + 'IsClosed' => 1, + ); + $where = ''; + + // Get details about the geometry fucntions + $geom_funcs = PMA_getGISFunctions($types, true, false); + // New output type is the output type of the function being applied + $types = $geom_funcs[$geom_func]['type']; + + // If the function takes a single parameter + if ($geom_funcs[$geom_func]['params'] == 1) { + $backquoted_name = $geom_func . '(' . PMA_backquote($names) . ')'; + } else { + // If the function takes two parameters + // create gis data from the criteria input + $gis_data = PMA_createGISData($criteriaValues); + $where = $geom_func . '(' . PMA_backquote($names) . ',' . $gis_data . ')'; + return $where; + } + + // If the where clause is something like 'IsEmpty(`spatial_col_name`)' + if (isset($geom_unary_functions[$geom_func]) && trim($criteriaValues) == '') { + $where = $backquoted_name; + + } elseif (in_array($types, PMA_getGISDatatypes()) && ! empty($criteriaValues)) { + // create gis data from the criteria input + $gis_data = PMA_createGISData($criteriaValues); + $where = $backquoted_name . ' ' . $func_type . ' ' . $gis_data; + } + return $where; + } + + /** + * Return the where clause for query generation based on the inputs provided. + * + * @param mixed $criteriaValues Search criteria input + * @param string $names Name of the column on which search is submitted + * @param string $types Type of the field + * @param string $collations Field collation + * @param string $func_type Search fucntion/operator + * @param bool $unaryFlag Whether operator unary or not + * @param bool $geom_func Whether geometry functions should be applied + * + * @return string generated where clause. + */ + private function _getWhereClause($criteriaValues, $names, $types, $collations, + $func_type, $unaryFlag, $geom_func = null + ) { + // If geometry function is set + if ($geom_func != null && trim($geom_func) != '') { + return _getGeomWhereClause($criteriaValues, $names, $func_type, $geom_func); + } + + $backquoted_name = PMA_backquote($names); + $where = ''; + if ($unaryFlag) { + $criteriaValues = ''; + $where = $backquoted_name . ' ' . $func_type; + + } elseif (strncasecmp($types, 'enum', 4) == 0) { + $where = $backquoted_name; + $where .= _getEnumWhereClause($criteriaValues, $func_type); + + } elseif ($criteriaValues != '') { + // For these types we quote the value. Even if it's another type (like INT), + // for a LIKE we always quote the value. MySQL converts strings to numbers + // and numbers to strings as necessary during the comparison + if (preg_match('@char|binary|blob|text|set|date|time|year@i', $types) + || strpos(' ' . $func_type, 'LIKE') + ) { + $quot = '\''; + } else { + $quot = ''; + } + + // LIKE %...% + if ($func_type == 'LIKE %...%') { + $func_type = 'LIKE'; + $criteriaValues = '%' . $criteriaValues . '%'; + } + if ($func_type == 'REGEXP ^...$') { + $func_type = 'REGEXP'; + $criteriaValues = '^' . $criteriaValues . '$'; + } + + if ($func_type == 'IN (...)' + || $func_type == 'NOT IN (...)' + || $func_type == 'BETWEEN' + || $func_type == 'NOT BETWEEN' + ) { + $func_type = str_replace(' (...)', '', $func_type); + + // quote values one by one + $values = explode(',', $criteriaValues); + foreach ($values as &$value) { + $value = $quot . PMA_sqlAddslashes(trim($value)) . $quot; + } + + if ($func_type == 'BETWEEN' || $func_type == 'NOT BETWEEN') { + $where = $backquoted_name . ' ' . $func_type . ' ' + . (isset($values[0]) ? $values[0] : '') + . ' AND ' . (isset($values[1]) ? $values[1] : ''); + } else { + $where = $backquoted_name . ' ' . $func_type + . ' (' . implode(',', $values) . ')'; + } + } else { + $where = $backquoted_name . ' ' . $func_type . ' ' + . $quot . PMA_sqlAddslashes($criteriaValues) . $quot; + } + } // end if + + return $where; + } + + /** + * Builds the sql search query from the post parameters + * + * @return string the generated SQL query + */ + public function _buildSqlQuery() + { + $sql_query = 'SELECT '; + + // If only distinct values are needed + $is_distinct = (isset($_POST['distinct'])) ? 'true' : 'false'; + if ($is_distinct == 'true') { + $sql_query .= 'DISTINCT '; + } + + // if all column names were selected to display, we do a 'SELECT *' + // (more efficient and this helps prevent a problem in IE + // if one of the rows is edited and we come back to the Select results) + if (isset($_POST['zoom_submit'])) { + $sql_query .= '* '; + } else { + $sql_query .= (count($_POST['columnsToDisplay']) + == count($_POST['criteriaColumnNames']) + ? '* ' + : implode(', ', PMA_backquote($_POST['columnsToDisplay']))); + } // end if + + $sql_query .= ' FROM ' . PMA_backquote($_POST['table']); + $whereClause = _generateWhereClause(); + $sql_query .= $whereClause; + + // if the search results are to be ordered + if (isset($_POST['orderByColumn']) && $_POST['orderByColumn'] != '--nil--') { + $sql_query .= ' ORDER BY ' . PMA_backquote($_POST['orderByColumn']) + . ' ' . $_POST['order']; + } // end if + return $sql_query; + } + + /** + * Generates the where clause for the SQL search query to be executed + * + * @return string the generated where clause + */ + private function _generateWhereClause() + { + $fullWhereClause = ''; + + if (isset($_POST['customWhereClause']) && trim($_POST['customWhereClause']) != '') { + $fullWhereClause .= ' WHERE ' . $_POST['customWhereClause']; + return $fullWhereClause; + } + + // If there are no search criteria set, return + if (! array_filter($_POST['criteriaValues'])) { + return $fullWhereClause; + } + + // else continue to form the where clause from column criteria values + $fullWhereClause = $charsets = array(); + reset($_POST['criteriaColumnOperators']); + while (list($column_index, $operator) = each($_POST['criteriaColumnOperators'])) { + list($charsets[$column_index]) = explode( + '_', $_POST['criteriaColumnCollations'][$column_index] + ); + $unaryFlag = $GLOBALS['PMA_Types']->isUnaryOperator($operator); + $tmp_geom_func = isset($geom_func[$column_index]) + ? $geom_func[$column_index] : null; + + $whereClause = _getWhereClause( + $_POST['criteriaValues'][$column_index], + $_POST['criteriaColumnNames'][$column_index], + $_POST['criteriaColumnTypes'][$column_index], + $_POST['criteriaColumnCollations'][$column_index], $operator, $unaryFlag, + $tmp_geom_func + ); + + if ($whereClause) { + $fullWhereClause[] = $whereClause; + } + } // end while + + if ($fullWhereClause) { + $fullWhereClause = ' WHERE ' . implode(' AND ', $fullWhereClause); + } + return $fullWhereClause; + } + + /** + * Generates HTML for a geometrical function column to be displayed in table + * search selection form + * + * @param integer $column_index index of current column in $columnTypes array + * + * @return string the generated HTML + */ + private function _getGeomFuncHtml($column_index) + { + $html_output = ''; + // return if geometrical column is not present + if (! $this->_geomColumnFlag) { + return $html_output; + } + + /** + * Displays 'Function' column if it is present + */ + $html_output .= ''; + $geom_types = PMA_getGISDatatypes(); + // if a geometry column is present + if (in_array($this->_columnTypes[$column_index], $geom_types)) { + $html_output .= ''; + } else { + $html_output .= ' '; + } + $html_output .= ''; + return $html_output; + } + + /** + * Generates formatted HTML for extra search options in table search form + * + * @return string the generated HTML + */ + private function _getOptions() + { + $html_output = ''; + $html_output .= PMA_getDivForSliderEffect('searchoptions', __('Options')); + /** + * Displays columns select list for selecting distinct columns in the search + */ + $html_output .= '
' + . '' . __('Select columns (at least one):') . '' + . '' + . '' + . '
'; + + /** + * Displays input box for custom 'Where' clause to be used in the search + */ + $html_output .= '
' + . '' . '' . __('Or') . ' ' + . __('Add search conditions (body of the "where" clause):') . ''; + $html_output .= PMA_showMySQLDocu('SQL-Syntax', 'Functions'); + $html_output .= ''; + $html_output .= '
'; + + /** + * Displays option of changing default number of rows displayed per page + */ + $html_output .= '
' + . '' . __('Number of rows per page') . '' + . '' + . '
'; + + /** + * Displays option for ordering search results by a column value (Asc or Desc) + */ + $html_output .= '
' + . '' . __('Display order:') . '' + . ''; + $choices = array( + 'ASC' => __('Ascending'), + 'DESC' => __('Descending') + ); + $html_output .= PMA_getRadioFields( + 'order', $choices, 'ASC', false, true, "formelement" + ); + unset($choices); + + $html_output .= '

'; + return $html_output; + } + + /** + * Other search criteria like data label + * (for tbl_zoom_select.php) + * + * @param array $dataLabel Label for points in zoom plot + * + * @return string the generated html + */ + private function _getOptionsZoom($dataLabel) + { + $html_output = ''; + $html_output .= ''; + //Select options for datalabel + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + //Inputbox for changing default maximum rows to plot + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= '
'; + $html_output .= ''; + $html_output .= '
'; + return $html_output; + } + + /** + * Provides a column's type, collation, operators list, and crietria value + * to display in table search form + * + * @param integer $search_index Row number in table search form + * @param integer $column_index Column index in ColumnNames array + * + * @return array Array contaning column's properties + */ + private function _getColumnProperties($search_index, $column_index) + { + $selected_operator = (isset($_POST['criteriaColumnOperators']) + ? $_POST['criteriaColumnOperators'][$search_index] : ''); + $entered_value = (isset($_POST['criteriaValues']) + ? $_POST['criteriaValues'] : ''); + $titles['Browse'] = PMA_getIcon('b_browse.png', __('Browse foreign values')); + //Gets column's type and collation + $type = $this->_columnTypes[$column_index]; + $collation = $this->_columnCollations[$column_index]; + //Gets column's comparison operators depending on column type + $func = ''; + //Gets link to browse foreign data(if any) and criteria inputbox + $foreignData = PMA_getForeignData( + $this->_foreigners, $this->_columnNames[$column_index], false, '', '' + ); + $value = $this->_getInputbox( + $foreignData, $this->_columnNames[$column_index], $type, $search_index, + $titles, $GLOBALS['cfg']['ForeignKeyMaxLimit'], $entered_value + ); + return array( + 'type' => $type, + 'collation' => $collation, + 'func' => $func, + 'value' => $value + ); + } + + /** + * Provides the search form's table row in case of Normal Search + * (for tbl_select.php) + * + * @return string the generated table row + */ + private function _getRowsNormal() + { + $odd_row = true; + $html_output = ''; + // for every column present in table + for ($column_index = 0; $column_index < count($this->_columnNames); $column_index++) { + $html_output .= ''; + $odd_row = !$odd_row; + //If 'Function' column is present + $html_output .= $this->_getGeomFuncHtml($column_index); + //Displays column's name, type, collation and value + $html_output .= '' . htmlspecialchars($this->_columnNames[$column_index]) + . ''; + $properties = $this->_getColumnProperties($column_index, $column_index); + $html_output .= '' . $properties['type'] . ''; + $html_output .= '' . $properties['collation'] . ''; + $html_output .= '' . $properties['func'] . ''; + $html_output .= '' . $properties['value'] . ''; + $html_output .= ''; + //Displays hidden fields + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + } // end for + + return $html_output; + } + + /** + * Provides the search form's table row in case of Zoom Search + * (for tbl_zoom_select.php) + * + * @return string the generated table row + */ + private function _getRowsZoom() + { + $odd_row = true; + $html_output = ''; + /** + * Get already set search criteria (if any) + */ + + //Displays column rows for search criteria input + for ($i = 0; $i < 4; $i++) { + //After X-Axis and Y-Axis column rows, display additional criteria option + if ($i == 2) { + $html_output .= ''; + $html_output .= __("Additional search criteria"); + $html_output .= ''; + } + $html_output .= ''; + $odd_row = ! $odd_row; + //Select options for column names + $html_output .= ''; + if (isset($_POST['criteriaColumnNames']) + && $_POST['criteriaColumnNames'][$i] != 'pma_null' + ) { + $key = array_search($_POST['criteriaColumnNames'][$i], $this->_columnNames); + $properties = $this->_getColumnProperties($i, $key); + $type[$i] = $properties['type']; + $collation[$i] = $properties['collation']; + $func[$i] = $properties['func']; + $value[$i] = $properties['value']; + } + //Column type + $html_output .= '' . (isset($type[$i]) ? $type[$i] : '') . ''; + //Column Collation + $html_output .= '' . (isset($collation[$i]) ? $collation[$i] : '') + . ''; + //Select options for column operators + $html_output .= '' . (isset($func[$i]) ? $func[$i] : '') . ''; + //Inputbox for search criteria value + $html_output .= '' . (isset($value[$i]) ? $value[$i] : '') . ''; + $html_output .= ''; + //Displays hidden fields + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + }//end for + return $html_output; + } + + /** + * Generates HTML for displaying fields table in search form + * + * @return string the generated HTML + */ + private function _getFieldsTableHtml() + { + $html_output = ''; + $html_output .= '_searchType == 'zoom' ? ' id="tableFieldsId"' : '') . '>'; + $html_output .= $this->_getTableHeader(); + $html_output .= ''; + + if ($this->_searchType == 'zoom') { + $html_output .= $this->_getRowsZoom(); + } else { + $html_output .= $this->_getRowsNormal(); + } + + $html_output .= '
'; + return $html_output; + } + + /** + * Provides the form tag for table search form + * (normal search or zoom search) + * + * @param string $goto Goto URL + * + * @return string the HTML for form tag + */ + private function _getFormTag($goto) + { + $html_output = ''; + $scriptName = ($this->_searchType == 'zoom' ? 'tbl_zoom_select.php' : 'tbl_select.php'); + $formId = ($this->_searchType == 'zoom' ? 'zoom_search_form' : 'tbl_search_form'); + + $html_output .= '
'; + + $html_output .= PMA_generate_common_hidden_inputs($this->_db, $this->_table); + $html_output .= ''; + $html_output .= ''; + + return $html_output; + } + + /** + * Generates the table search form under table search tab + * + * @param string $goto Goto URL + * @param string $dataLabel Label for points in zoom plot + * + * @return string the generated HTML for table search form + */ + public function _getSelectionForm($goto, $dataLabel = null) + { + $html_output = ''; + $html_output .= '
'; + $url_params = array(); + $url_params['db'] = $this->_db; + $url_params['table'] = $this->_table; + + $html_output .= PMA_generateHtmlTabs( + PMA_tbl_getSubTabs(), $url_params, 'topmenu2' + ); + $html_output .= $this->_getFormTag($goto); + + $html_output .= '
'; + $html_output .= ($this->_searchType == 'zoom' + ? '' : '
'); + + // Set caption for fieldset + if ($this->_searchType == 'zoom') { + $html_output .= '' + . __('Do a "query by example" (wildcard: "%") for two different columns') + . ''; + } else { + $html_output .= '' + . __('Do a "query by example" (wildcard: "%")') + . ''; + } + + /** + * Displays fields table in search form + */ + $html_output .= $this->_getFieldsTableHtml(); + + /** + * Displays more search options + */ + if ($this->_searchType == 'zoom') { + $html_output .= $this->_getOptionsZoom($dataLabel); + } else { + $html_output .= '
' + . '' + . '
'; + $html_output .= $this->_getOptions(); + } + + /** + * Displays selection form's footer elements + */ + $html_output .= '
'; + $html_output .= ''; + $html_output .= '
'; + if ($this->_searchType == 'zoom') { + $html_output = '
' + . $html_output . '
'; + } else { + $html_output .= '
'; + } + return $html_output; + } + + /** + * Provides form for displaying point data and also the scatter plot + * (for tbl_zoom_select.php) + * + * @param string $goto Goto URL + * @param array $data Array containing SQL query data + * + * @return string form's html + */ + public function _getZoomResultsForm($goto, $data) + { + $html_output = ''; + $titles['Browse'] = PMA_getIcon('b_browse.png', __('Browse foreign values')); + $html_output .= '
'; + $html_output .= PMA_generate_common_hidden_inputs($this->_db, $this->_table); + $html_output .= ''; + $html_output .= ''; + + $html_output .= '
'; + $html_output .= '' . __('Browse/Edit the points') . ''; + + //JSON encode the data(query result) + $html_output .= '
'; + if (isset($_POST['zoom_submit']) && ! empty($data)) { + $html_output .= '
'; + $html_output .= '
' + . __('How to use') . '
'; + $html_output .= ''; + $html_output .= '
'; + $html_output .= ''; + $html_output .= '
'; + } + $html_output .= '
'; + + //Displays rows in point edit form + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + return $html_output; + } } ?>