diff --git a/libraries/TableSearch.class.php b/libraries/TableSearch.class.php new file mode 100644 index 0000000000..8b3b2f14d2 --- /dev/null +++ b/libraries/TableSearch.class.php @@ -0,0 +1,1197 @@ +_db = $db; + $this->_table = $table; + $this->_searchType = $searchType; + $this->_columnNames = array(); + $this->_columnNullFlags = array(); + $this->_columnTypes = array(); + $this->_columnCollations = array(); + $this->_geomColumnFlag = false; + $this->_foreigners = array(); + // Loads table's information + $this->_loadTableInfo($this->_db, $this->_table); + } + + /** + * Gets all the columns of a table along with their types, collations + * and whether null or not. + * + * @return array Array containing the column list, column types, collations + * and null constraint + */ + private function _loadTableInfo() + { + // Gets the list and number of columns + $columns = PMA_DBI_get_columns($this->_db, $this->_table, null, true); + // Get details about the geometry fucntions + $geom_types = PMA_getGISDatatypes(); + + foreach ($columns as $key => $row) { + // set column name + $this->_columnNames[] = $row['Field']; + + $type = $row['Type']; + // check whether table contains geometric columns + if (in_array($type, $geom_types)) { + $this->_geomColumnFlag = true; + } + // reformat mysql query output + if (strncasecmp($type, 'set', 3) == 0 + || strncasecmp($type, 'enum', 4) == 0 + ) { + $type = str_replace(',', ', ', $type); + } else { + // strip the "BINARY" attribute, except if we find "BINARY(" because + // this would be a BINARY or VARBINARY column type + if (! preg_match('@BINARY[\(]@i', $type)) { + $type = preg_replace('@BINARY@i', '', $type); + } + $type = preg_replace('@ZEROFILL@i', '', $type); + $type = preg_replace('@UNSIGNED@i', '', $type); + $type = strtolower($type); + } + if (empty($type)) { + $type = ' '; + } + $this->_columnTypes[] = $type; + $this->_columnNullFlags[] = $row['Null']; + $this->_columnCollations[] + = ! empty($row['Collation']) && $row['Collation'] != 'NULL' + ? $row['Collation'] + : ''; + } // end for + + // Retrieve foreign keys + $this->_foreigners = PMA_getForeigners($this->_db, $this->_table); + } + + /** + * Sets the table header for displaying a table in query-by-example format. + * + * @return HTML content, the tags and content for table header + */ + private function _getTableHeader() + { + // Display the Function column only if there is at least one geometry column + $func = ''; + if ($this->_geomColumnFlag) { + $func = '' . __('Function') . ''; + } + + return ' + ' . $func . '' . __('Column') . ' + ' . __('Type') . ' + ' . __('Collation') . ' + ' . __('Operator') . ' + ' . __('Value') . ' + + '; + } + + /** + * Returns an array with necessary configrations to create + * sub-tabs(Table Search and Zoom Search) in the table_select page. + * + * @return array Array containing configuration (icon, text, link, id, args) + * of sub-tabs for Table Search and Zoom search + */ + private function _getSubTabs() + { + $subtabs = array(); + $subtabs['search']['icon'] = 'b_search.png'; + $subtabs['search']['text'] = __('Table Search'); + $subtabs['search']['link'] = 'tbl_select.php'; + $subtabs['search']['id'] = 'tbl_search_id'; + $subtabs['search']['args']['pos'] = 0; + + $subtabs['zoom']['icon'] = 'b_props.png'; + $subtabs['zoom']['link'] = 'tbl_zoom_select.php'; + $subtabs['zoom']['text'] = __('Zoom Search'); + $subtabs['zoom']['id'] = 'zoom_search_id'; + + return $subtabs; + } + + /** + * Provides html elements for search criteria inputbox + * in case the column's type is geometrical + * + * @param int $column_index Column's index + * @param bool $in_fbs Whether we are in 'function based search' + * + * @return HTML elements. + */ + private function _getGeometricalInputBox($column_index, $in_fbs) + { + $html_output = ''; + + if ($in_fbs) { + $edit_url = 'gis_data_editor.php?' . PMA_generate_common_url(); + $edit_str = PMA_getIcon('b_edit.png', __('Edit/Insert')); + $html_output .= ''; + $html_output .= PMA_linkOrButton( + $edit_url, $edit_str, array(), false, false, '_blank' + ); + $html_output .= ''; + } + return $html_output; + } + + /** + * Provides html elements for search criteria inputbox + * in case the column is a Foreign Key + * + * @param array $foreignData Foreign keys data + * @param string $column_name Column name + * @param int $column_index Column index + * @param array $titles Selected title + * @param int $foreignMaxLimit Max limit of displaying foreign elements + * @param array $criteriaValues Array of search criteria inputs + * @param string $column_id Column's inputbox's id + * @param bool $in_zoom_search_edit Whether we are in zoom search edit + * + * @return HTML elements. + */ + private function _getForeignKeyInputBox($foreignData, $column_name, + $column_index, $titles, $foreignMaxLimit, $criteriaValues, $column_id, + $in_zoom_search_edit = false + ) { + $html_output = ''; + if (is_array($foreignData['disp_row'])) { + $html_output .= ''; + + } elseif ($foreignData['foreign_link'] == true) { + $html_output .= ''; + + $html_output .= <<'; + } + return $html_output; + } + + /** + * Provides html elements for search criteria inputbox + * in case the column is of ENUM or SET type + * + * @param int $column_index Column index + * @param array $criteriaValues Array of search criteria inputs + * @param string $column_type Column type + * @param string $column_id Column's inputbox's id + * @param bool $in_zoom_search_edit Whether we are in zoom search edit + * + * @return HTML elements. + */ + private function _getEnumSetInputBox($column_index, $criteriaValues, + $column_type, $column_id, $in_zoom_search_edit = false + ) { + $html_output = ''; + $value = explode( + ', ', + str_replace("'", '', substr($column_type, 5, -1)) + ); + $cnt_value = count($value); + + /* + * Enum in edit mode --> dropdown + * Enum in search mode --> multiselect + * Set in edit mode --> multiselect + * Set in search mode --> input (skipped here, so the 'else' + * section would handle it) + */ + if ((strncasecmp($column_type, 'enum', 4) && ! $in_zoom_search_edit) + || (strncasecmp($column_type, 'set', 3) && $in_zoom_search_edit) + ) { + $html_output .= ''; + } + + //Add select options + for ($j = 0; $j < $cnt_value; $j++) { + if (isset($criteriaValues[$column_index]) + && is_array($criteriaValues[$column_index]) + && in_array($value[$j], $criteriaValues[$column_index]) + ) { + $html_output .= ''; + } else { + $html_output .= ''; + } + } // end for + $html_output .= ''; + return $html_output; + } + + /** + * Creates the HTML content for: + * 1) Browsing foreign data for a column. + * 2) Creating elements for search criteria input on columns. + * + * @param array $foreignData Foreign keys data + * @param string $column_name Column name + * @param string $column_type Column type + * @param int $column_index Column index + * @param array $titles Selected title + * @param int $foreignMaxLimit Max limit of displaying foreign elements + * @param array $criteriaValues Array of search criteria inputs + * @param bool $in_fbs Whether we are in 'function based search' + * @param bool $in_zoom_search_edit Whether we are in zoom search edit + * + * @return string HTML content for viewing foreing data and elements + * for search criteria input. + */ + private function _getInputbox($foreignData, $column_name, $column_type, + $column_index, $titles, $foreignMaxLimit, $criteriaValues, $in_fbs = false, + $in_zoom_search_edit = false + ) { + $str = ''; + $column_type = (string)$column_type; + $column_id = ($in_zoom_search_edit) ? 'edit_fieldID_' : 'fieldID_'; + + //Get inputbox based on different column types (Foreign key, geometrical, enum) + if ($this->_foreigners && isset($this->_foreigners[$column_name])) { + $str .= $this->_getForeignKeyInputBox( + $foreignData, $column_name, $column_index, $titles, + $foreignMaxLimit, $criteriaValues, $column_id + ); + + } elseif (in_array($column_type, PMA_getGISDatatypes())) { + $str .= $this->_getGeometricalInputBox($column_index, $in_fbs); + + } elseif (strncasecmp($column_type, 'enum', 4) == 0 + || (strncasecmp($column_type, 'set', 3) == 0 && $in_zoom_search_edit) + ) { + $str .= $this->_getEnumSetInputBox( + $column_index, $criteriaValues, $column_type, $column_id, + $in_zoom_search_edit = false + ); + + } else { + // other cases + $the_class = 'textfield'; + + if ($column_type == 'date') { + $the_class .= ' datefield'; + } elseif ($column_type == 'datetime' || substr($column_type, 0, 9) == 'timestamp') { + $the_class .= ' datetimefield'; + } elseif (substr($column_type, 0, 3) == 'bit') { + $the_class .= ' bit'; + } + + $str .= ''; + } + 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 $this->_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 .= $this->_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 = $this->_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 = $this->_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 + */ + public 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( + $this->_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; + } +} +?> diff --git a/libraries/tbl_select.lib.php b/libraries/tbl_select.lib.php index e481e074b8..80dc5b2c60 100644 --- a/libraries/tbl_select.lib.php +++ b/libraries/tbl_select.lib.php @@ -121,6 +121,144 @@ function PMA_tbl_getSubTabs() return $subtabs; } +/** + * Provides html elements for search criteria inputbox + * in case the column's type is geometrical + * + * @param int $column_index Column's index + * @param bool $in_fbs Whether we are in 'function based search' + * + * @return HTML elements. + */ +function PMA_tblSearchGetGeometricalInputBox($column_index, $in_fbs) +{ + $html_output = ''; + + if ($in_fbs) { + $edit_url = 'gis_data_editor.php?' . PMA_generate_common_url(); + $edit_str = PMA_getIcon('b_edit.png', __('Edit/Insert')); + $html_output .= ''; + $html_output .= PMA_linkOrButton( + $edit_url, $edit_str, array(), false, false, '_blank' + ); + $html_output .= ''; + } + return $html_output; +} + +/** + * Provides html elements for search criteria inputbox + * in case the column is a Foreign Key + * + * @param array $foreignData Foreign keys data + * @param string $field Column name + * @param int $column_index Column index + * @param string $db Selected database + * @param string $table Selected table + * @param array $titles Selected title + * @param int $foreignMaxLimit Max limit of displaying foreign elements + * @param array $criteriaValues Array of search criteria inputs + * @param string $field_id Column's inputbox's id + * @param bool $in_zoom_search_edit Whether we are in zoom search edit + * + * @return HTML elements. + */ +function PMA_tblSearchGetForeignKeyInputBox($foreignData, $field, $column_index, + $db, $table, $titles, $foreignMaxLimit, $criteriaValues, + $field_id, $in_zoom_search_edit = false +) { + $html_output = ''; + if (is_array($foreignData['disp_row'])) { + $html_output .= ''; + + } elseif ($foreignData['foreign_link'] == true) { + $html_output .= ''; + + $html_output .= <<'; + } + return $html_output; +} + +/** + * Provides html elements for search criteria inputbox + * in case the column is of ENUM or SET type + * + * @param int $column_index Column index + * @param array $criteriaValues Array of search criteria inputs + * @param string $field_type Column type + * @param string $field_id Column's inputbox's id + * @param bool $in_zoom_search_edit Whether we are in zoom search edit + * + * @return HTML elements. + */ +function PMA_tblSearchGetEnumSetInputBox($column_index, $criteriaValues, $field_type, + $field_id, $in_zoom_search_edit = false +) { + $html_output = ''; + $value = explode( + ', ', + str_replace("'", '', substr($field_type, 5, -1)) + ); + $cnt_value = count($value); + + /* + * Enum in edit mode --> dropdown + * Enum in search mode --> multiselect + * Set in edit mode --> multiselect + * Set in search mode --> input (skipped here, so the 'else' + * section would handle it) + */ + if ((strncasecmp($field_type, 'enum', 4) && ! $in_zoom_search_edit) + || (strncasecmp($field_type, 'set', 3) && $in_zoom_search_edit) + ) { + $html_output .= ''; + } + + //Add select options + for ($j = 0; $j < $cnt_value; $j++) { + if (isset($criteriaValues[$column_index]) + && is_array($criteriaValues[$column_index]) + && in_array($value[$j], $criteriaValues[$column_index]) + ) { + $html_output .= ''; + } else { + $html_output .= ''; + } + } // end for + $html_output .= ''; + return $html_output; +} + /** * Creates the HTML content for: * 1) Browsing foreign data for a field. @@ -142,114 +280,34 @@ function PMA_tbl_getSubTabs() * @return string HTML content for viewing foreing data and elements * for search criteria input. */ -function PMA_getForeignFields_Values($foreigners, $foreignData, $field, +function PMA_tblSearchGetInputbox($foreigners, $foreignData, $field, $field_type, $column_index, $db, $table, $titles, $foreignMaxLimit, $criteriaValues, $in_fbs = false, $in_zoom_search_edit = false ) { $str = ''; $field_type = (string)$field_type; $field_id = ($in_zoom_search_edit) ? 'edit_fieldID_' : 'fieldID_'; - if ($foreigners - && isset($foreigners[$field]) - && is_array($foreignData['disp_row']) - ) { - // f o r e i g n k e y s - $str .= ''; - } elseif ($foreignData['foreign_link'] == true) { - if (isset($criteriaValues[$column_index]) - && is_string($criteriaValues[$column_index]) - ) { - $str .= ''; - } else { - $str .= ''; - } - $str .= <<'; + //Get inputbox based on different column types (Foreign key, geometrical, enum) + if ($foreigners && isset($foreigners[$field])) { + $str .= PMA_tblSearchGetForeignKeyInputBox( + $foreignData, $field, $column_index, $db, $table, $titles, + $foreignMaxLimit, $criteriaValues, $field_id + ); } elseif (in_array($field_type, PMA_getGISDatatypes())) { - // g e o m e t r y - $str .= ''; - - if ($in_fbs) { - $edit_url = 'gis_data_editor.php?' . PMA_generate_common_url(); - $edit_str = PMA_getIcon('b_edit.png', __('Edit/Insert')); - $str .= ''; - $str .= PMA_linkOrButton( - $edit_url, $edit_str, array(), false, false, '_blank' - ); - $str .= ''; - } + $str .= PMA_tblSearchGetGeometricalInputBox($column_index, $in_fbs); } elseif (strncasecmp($field_type, 'enum', 4) == 0 || (strncasecmp($field_type, 'set', 3) == 0 && $in_zoom_search_edit) ) { - // e n u m s a n d s e t s - - // Enum in edit mode --> dropdown - // Enum in search mode --> multiselect - // Set in edit mode --> multiselect - // Set in search mode --> input (skipped here, so the 'else' - // section would handle it) - - $value = explode( - ', ', - str_replace("'", '', substr($field_type, 5, -1)) + $str .= PMA_tblSearchGetEnumSetInputBox( + $column_index, $criteriaValues, $field_type, $field_id, + $in_zoom_search_edit = false ); - $cnt_value = count($value); - - if ((strncasecmp($field_type, 'enum', 4) && ! $in_zoom_search_edit) - || (strncasecmp($field_type, 'set', 3) && $in_zoom_search_edit) - ) { - $str .= ''; - } - - for ($j = 0; $j < $cnt_value; $j++) { - if (isset($criteriaValues[$column_index]) - && is_array($criteriaValues[$column_index]) - && in_array($value[$j], $criteriaValues[$column_index]) - ) { - $str .= ''; - } else { - $str .= ''; - } - } // end for - $str .= ''; } else { - // o t h e r c a s e s + // other cases $the_class = 'textfield'; if ($field_type == 'date') { @@ -260,22 +318,109 @@ EOT; $the_class .= ' bit'; } - if (isset($criteriaValues[$column_index]) - && is_string($criteriaValues[$column_index]) - ) { - $str .= ''; - } else { - $str .= ''; - } + $str .= ''; } 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. + */ +function PMA_tblSearchGetEnumWhereClause($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. + */ +function PMA_tblSearchGetGeomWhereClause($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. * @@ -287,90 +432,27 @@ EOT; * @param bool $unaryFlag Whether operator unary or not * @param bool $geom_func Whether geometry functions should be applied * - * @return string HTML content for viewing foreing data and elements - * for search criteria input. + * @return string generated where clause. */ function PMA_tbl_search_getWhereClause($criteriaValues, $names, $types, $collations, $func_type, $unaryFlag, $geom_func = null ) { - /** - * @todo move this to a more apropriate place - */ - $geom_unary_functions = array( - 'IsEmpty' => 1, - 'IsSimple' => 1, - 'IsRing' => 1, - 'IsClosed' => 1, - ); - - $w = ''; - // If geometry function is set apply it to the field name + // If geometry function is set if ($geom_func != null && trim($geom_func) != '') { - // Get details about the geometry fucntions - $geom_funcs = PMA_getGISFunctions($types, true, false); - - // 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 string - $gis_data = PMA_createGISData($criteriaValues); - - $w = $geom_func . '(' . PMA_backquote($names) . ',' . $gis_data . ')'; - return $w; - } - - // New output type is the output type of the function being applied - $types = $geom_funcs[$geom_func]['type']; - - // If the where clause is something like 'IsEmpty(`spatial_col_name`)' - if (isset($geom_unary_functions[$geom_func]) && trim($criteriaValues) == '') { - $w = $backquoted_name; - return $w; - } - } else { - $backquoted_name = PMA_backquote($names); + return PMA_tblSearchGetGeomWhereClause( + $criteriaValues, $names, $func_type, $geom_func + ); } + $backquoted_name = PMA_backquote($names); + $where = ''; if ($unaryFlag) { $criteriaValues = ''; - $w = $backquoted_name . ' ' . $func_type; - - } elseif (in_array($types, PMA_getGISDatatypes()) && ! empty($criteriaValues)) { - // create gis data from the string - $gis_data = PMA_createGISData($criteriaValues); - $w = $backquoted_name . ' ' . $func_type . ' ' . $gis_data; + $where = $backquoted_name . ' ' . $func_type; } elseif (strncasecmp($types, 'enum', 4) == 0) { - 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]) - . '\''; - } - - $w = $backquoted_name . ' ' . $func_type . ' ' . $parens_open - . $enum_where . $parens_close; - } + $where = $backquoted_name; + $where .= PMA_tblSearchGetEnumWhereClause($criteriaValues, $func_type); } elseif ($criteriaValues != '') { // For these types we quote the value. Even if it's another type (like INT), @@ -408,20 +490,20 @@ function PMA_tbl_search_getWhereClause($criteriaValues, $names, $types, $collati } if ($func_type == 'BETWEEN' || $func_type == 'NOT BETWEEN') { - $w = $backquoted_name . ' ' . $func_type . ' ' + $where = $backquoted_name . ' ' . $func_type . ' ' . (isset($values[0]) ? $values[0] : '') . ' AND ' . (isset($values[1]) ? $values[1] : ''); } else { - $w = $backquoted_name . ' ' . $func_type + $where = $backquoted_name . ' ' . $func_type . ' (' . implode(',', $values) . ')'; } } else { - $w = $backquoted_name . ' ' . $func_type . ' ' - . $quot . PMA_sqlAddslashes($criteriaValues) . $quot;; + $where = $backquoted_name . ' ' . $func_type . ' ' + . $quot . PMA_sqlAddslashes($criteriaValues) . $quot; } } // end if - return $w; + return $where; } /** @@ -719,7 +801,7 @@ function PMA_tblSearchGetColumnProperties($db, $table, $columnNames, $columnType $foreignData = PMA_getForeignData( $foreigners, $columnNames[$column_index], false, '', '' ); - $value = PMA_getForeignFields_Values( + $value = PMA_tblSearchGetInputbox( $foreigners, $foreignData, $columnNames[$column_index], $type, $search_index, $db, $table, $titles, $GLOBALS['cfg']['ForeignKeyMaxLimit'], $entered_value ); @@ -749,7 +831,6 @@ function PMA_tblSearchGetColumnProperties($db, $table, $columnNames, $columnType function PMA_tblSearchGetRowsNormal($db, $table, $columnNames, $columnTypes, $columnCollations, $columnNullFlags, $geomColumnFlag, $foreigners ) { - $titles['Browse'] = PMA_getIcon('b_browse.png', __('Browse foreign values')); $geom_types = PMA_getGISDatatypes(); $odd_row = true; $html_output = ''; @@ -1032,4 +1113,91 @@ function PMA_tblSearchGetSelectionForm($goto, $db, $table, $columnNames, } 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 string $db Selected Database + * @param string $table Selected Table + * @param array $columnNames Names of columns in the table + * @param array $columnTypes Types of columns in the table + * @param array $columnNullFlags Null information of columns + * @param array $foreigners Array of foreign keys + * @param array $data Array containing SQL query data + * + * @return string form's html + */ +function PMA_tblSearchGetZoomResultsForm($goto, $db, $table, $columnNames, + $columnTypes, $columnNullFlags, $foreigners, $data +) { + $html_output = ''; + $titles['Browse'] = PMA_getIcon('b_browse.png', __('Browse foreign values')); + $html_output .= '
'; + $html_output .= PMA_generate_common_hidden_inputs($db, $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; +} ?> diff --git a/tbl_select.php b/tbl_select.php index d956d5009c..1e1c615d7b 100644 --- a/tbl_select.php +++ b/tbl_select.php @@ -14,7 +14,7 @@ */ require_once 'libraries/common.inc.php'; require_once 'libraries/mysql_charsets.lib.php'; -require_once 'libraries/tbl_select.lib.php'; +require_once 'libraries/TableSearch.class.php'; $response = PMA_Response::getInstance(); $header = $response->getHeader(); @@ -36,6 +36,7 @@ foreach ($post_params as $one_post_param) { } } +$table_search = new PMA_TableSearch($db, $table, "normal"); /** * Not selection yet required -> displays the selection form @@ -45,7 +46,6 @@ if (! isset($_POST['columnsToDisplay']) || $_POST['columnsToDisplay'][0] == '') include_once 'libraries/tbl_common.inc.php'; //$err_url = 'tbl_select.php' . $err_url; $url_query .= '&goto=tbl_select.php&back=tbl_select.php'; - /** * Gets table's information */ @@ -56,26 +56,14 @@ if (! isset($_POST['columnsToDisplay']) || $_POST['columnsToDisplay'][0] == '') } // Defines the url to return to in case of error in the next sql statement $err_url = $goto . '?' . PMA_generate_common_url($db, $table); - - // Gets the list and number of fields - list($columnNames, $columnTypes, $columnCollations, $columnNullFlags, $geomColumnFlag) - = PMA_tbl_getFields($db, $table); - - // retrieve keys into foreign fields, if any - // check also foreigners even if relwork is FALSE (to get - // foreign keys from innodb) - $foreigners = PMA_getForeigners($db, $table); - // Displays the table search form - echo PMA_tblSearchGetSelectionForm( - $goto, $db, $table, $columnNames, $columnTypes, $columnCollations, - $columnNullFlags, $geomColumnFlag, $foreigners, "normal" - ); + $response->addHTML($table_search->getSelectionForm($goto)); + } else { /** * Selection criteria have been submitted -> do the work */ - $sql_query = PMA_tblSearchBuildSqlQuery(); + $sql_query = $table_search->buildSqlQuery(); include 'sql.php'; } ?> diff --git a/tbl_zoom_select.php b/tbl_zoom_select.php index 0ff020be97..b4c1963982 100644 --- a/tbl_zoom_select.php +++ b/tbl_zoom_select.php @@ -90,7 +90,6 @@ if (isset($_REQUEST['change_tbl_info']) && $_REQUEST['change_tbl_info'] == true) $response->addJSON('field_collation', ''); $response->addJSON('field_operators', ''); $response->addJSON('field_value', ''); - exit; } // Gets the list and number of fields list($columnNames, $columnTypes, $columnCollations, $columnNullFlags) @@ -129,7 +128,6 @@ if (! isset($goto)) { $err_url = $goto . '?' . PMA_generate_common_url($db, $table); // Gets the list and number of fields - list($columnNames, $columnTypes, $columnCollations, $columnNullFlags) = PMA_tbl_getFields($db, $table); @@ -142,13 +140,12 @@ $foreigners = PMA_getForeigners($db, $table); if ( !isset($_POST['zoom_submit']) || $_POST['dataLabel'] == '') { $dataLabel = PMA_getDisplayField($db, $table); } +//Display zoom search form echo PMA_tblSearchGetSelectionForm( $goto, $db, $table, $columnNames, $columnTypes, $columnCollations, $columnNullFlags, false, $foreigners, "zoom", $dataLabel ); -?> - $row[$_POST['criteriaColumnNames'][0]], $_POST['criteriaColumnNames'][1] => $row[$_POST['criteriaColumnNames'][1]], 'where_clause' => $uniqueCondition[0] ); $tmpData[$dataLabel] = ($dataLabel) ? $row[$dataLabel] : ''; - $data[] = $tmpData; } unset($tmpData); - /* - * Form for displaying point data and also the scatter plot - */ - ?> -
> - - - -
- -
- -
-
- -
- -
- -
- - - -