diff options
author | Dan Ungureanu <udan1107@gmail.com> | 2015-07-02 01:21:30 +0300 |
---|---|---|
committer | Dan Ungureanu <udan1107@gmail.com> | 2015-07-10 23:18:16 +0300 |
commit | 684b4bed1ad751cab9c7d673de6824e6c402d24a (patch) | |
tree | 921b0a1181f30ea4421a1c1742daf74f3f0bfc58 | |
parent | 2826b6b328dea467bb8a368d3a5fa96523ef173f (diff) |
Finished replacing the old parser in DisplayResults.
Updated sql-parser library.
Signed-off-by: Dan Ungureanu <udan1107@gmail.com>
-rw-r--r-- | libraries/DisplayResults.class.php | 214 | ||||
-rw-r--r-- | libraries/sql-parser/src/Fragments/WhereKeyword.php | 51 | ||||
-rw-r--r-- | libraries/sql-parser/src/Utils/Query.php | 83 | ||||
-rw-r--r-- | libraries/sql.lib.php | 1 | ||||
-rw-r--r-- | test/classes/PMA_DisplayResults_test.php | 32 |
5 files changed, 187 insertions, 194 deletions
diff --git a/libraries/DisplayResults.class.php b/libraries/DisplayResults.class.php index 19288f1f2b..40a67bcd63 100644 --- a/libraries/DisplayResults.class.php +++ b/libraries/DisplayResults.class.php @@ -1270,10 +1270,6 @@ class PMA_DisplayResults $printview = $this->__get('printview'); $display_params = $this->__get('display_params'); - if ($analyzed_sql_results['analyzed_sql'] == '') { - $analyzed_sql_results['analyzed_sql'] = array(); - } - // can the result be sorted? if ($displayParts['sort_lnk'] == '1') { @@ -1379,27 +1375,17 @@ class PMA_DisplayResults private function _getUnsortedSqlAndSortByKeyDropDown( $analyzed_sql_results, $sort_expression ) { - $analyzed_sql = $analyzed_sql_results['analyzed_sql']; $drop_down_html = ''; - // Just as fallback - $unsorted_sql_query = $this->__get('sql_query'); - if (isset($analyzed_sql[0]['unsorted_query'])) { - $unsorted_sql_query = $analyzed_sql[0]['unsorted_query']; - } - // Handles the case of multiple clicks on a column's header - // which would add many spaces before "ORDER BY" in the - // generated query. - $unsorted_sql_query = trim($unsorted_sql_query); - - // sorting by indexes, only if it makes sense (only one table ref) - if (isset($analyzed_sql) - && isset($analyzed_sql[0]) - && isset($analyzed_sql[0]['querytype']) - && ($analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT) - && isset($analyzed_sql[0]['table_ref']) - && (count($analyzed_sql[0]['table_ref']) == 1) - ) { + $unsorted_sql_query = SqlParser\Utils\Query::replaceClause( + $analyzed_sql_results['statement'], + $analyzed_sql_results['parser']->list, + 'ORDER BY', + '' + ); + + // Data is sorted by indexes only if it there is only one table. + if ($this->_isSelect($analyzed_sql_results)) { // grab indexes data: $indexes = PMA_Index::getFromTable( $this->__get('table'), @@ -1599,8 +1585,7 @@ class PMA_DisplayResults * * @param array $analyzed_sql_results analyzed sql results * - * @return array $comments_map table comments when condition true - * null when condition falls + * @return array $comments_map table comments * * @access private * @@ -1608,24 +1593,24 @@ class PMA_DisplayResults */ private function _getTableCommentsArray($analyzed_sql_results) { - $analyzed_sql = $analyzed_sql_results['analyzed_sql']; - - $comments_map = array(); + if ((!$GLOBALS['cfg']['ShowBrowseComments']) + || (empty($analyzed_sql_results['statement']->from)) + ) { + return array(); + } - if ($GLOBALS['cfg']['ShowBrowseComments']) { - if (isset($analyzed_sql[0]) - && is_array($analyzed_sql[0]) - && isset($analyzed_sql[0]['table_ref']) - ) { - foreach ($analyzed_sql[0]['table_ref'] as $tbl) { - $tb = $tbl['table_true_name']; - $comments_map[$tb] = PMA_getComments($this->__get('db'), $tb); - unset($tb); - } + $ret = array(); + foreach ($analyzed_sql_results['statement']->from as $field) { + if (empty($field->table)) { + continue; } + $ret[$field->table] = PMA_getComments( + empty($field->database) ? $this->__get('db') : $field->database, + $field->table + ); } - return $comments_map; + return $ret; } // end of the '_getTableCommentsArray()' function @@ -1643,14 +1628,13 @@ class PMA_DisplayResults */ private function _setHighlightedColumnGlobalField($analyzed_sql_results) { - $analyzed_sql = $analyzed_sql_results['analyzed_sql']; $highlight_columns = array(); - if (isset($analyzed_sql) && isset($analyzed_sql[0]) - && isset($analyzed_sql[0]['where_clause_identifiers']) - && is_array($analyzed_sql[0]['where_clause_identifiers']) - ) { - foreach ($analyzed_sql[0]['where_clause_identifiers'] as $wci) { - $highlight_columns[$wci] = 'true'; + + if (!empty($analyzed_sql_results['statement']->where)) { + foreach ($analyzed_sql_results['statement']->where as $expr) { + foreach ($expr->identifiers as $identifier) { + $highlight_columns[$identifier] = 'true'; + } } } @@ -2990,7 +2974,6 @@ class PMA_DisplayResults $grid_edit_class, $col_visib, $url_sql_query, $analyzed_sql_results ) { - $analyzed_sql = $analyzed_sql_results['analyzed_sql']; $row_values_html = ''; // Following variable are needed for use in isset/empty or @@ -3181,9 +3164,15 @@ class PMA_DisplayResults $display_params['data'][$row_no][$i] = $this->_getDataCellForNumericColumns( - $row[$i], $class, $condition_field, $meta, $map, - $is_field_truncated, $analyzed_sql, - $transformation_plugin, $default_function, + $row[$i], + $class, + $condition_field, + $meta, + $map, + $is_field_truncated, + $analyzed_sql_results, + $transformation_plugin, + $default_function, $transform_options ); @@ -3196,9 +3185,16 @@ class PMA_DisplayResults $display_params['data'][$row_no][$i] = $this->_getDataCellForGeometryColumns( - $row[$i], $class, $meta, $map, $_url_params, - $condition_field, $transformation_plugin, - $default_function, $transform_options, $analyzed_sql + $row[$i], + $class, + $meta, + $map, + $_url_params, + $condition_field, + $transformation_plugin, + $default_function, + $transform_options, + $analyzed_sql_results ); } else { @@ -3206,10 +3202,19 @@ class PMA_DisplayResults $display_params['data'][$row_no][$i] = $this->_getDataCellForNonNumericColumns( - $row[$i], $class, $meta, $map, $_url_params, - $condition_field, $transformation_plugin, - $default_function, $transform_options, - $is_field_truncated, $analyzed_sql, $dt_result, $i + $row[$i], + $class, + $meta, + $map, + $_url_params, + $condition_field, + $transformation_plugin, + $default_function, + $transform_options, + $is_field_truncated, + $analyzed_sql_results, + $dt_result, + $i ); } @@ -3317,7 +3322,6 @@ class PMA_DisplayResults } - /** * Get url sql query without conditions to shorten URLs * @@ -3331,28 +3335,24 @@ class PMA_DisplayResults */ private function _getUrlSqlQuery($analyzed_sql_results) { - $analyzed_sql = $analyzed_sql_results['analyzed_sql']; - if (isset($analyzed_sql) - && isset($analyzed_sql[0]) - && isset($analyzed_sql[0]['querytype']) - && ($analyzed_sql[0]['querytype'] == self::QUERY_TYPE_SELECT) - && (/*overload*/mb_strlen($this->__get('sql_query')) > 200) + if (($analyzed_sql_results['querytype'] != 'SELECT') + || (/*overload*/mb_strlen($this->__get('sql_query')) < 200) ) { + return $this->__get('sql_query'); + } - $url_sql_query = 'SELECT '; - if (isset($analyzed_sql[0]['queryflags']['distinct'])) { - $url_sql_query .= ' DISTINCT '; - } - - $url_sql_query .= $analyzed_sql[0]['select_expr_clause']; - if (!empty($analyzed_sql[0]['from_clause'])) { - $url_sql_query .= ' FROM ' . $analyzed_sql[0]['from_clause']; - } + $query = 'SELECT ' . SqlParser\Utils\Query::getClause( + $parser->statements[0], $parser->list, 'SELECT' + ); - return $url_sql_query; + $from_clause = SqlParser\Utils\Query::getClause( + $parser->statements[0], $parser->list, 'FROM' + ); + if (!empty($from_clause)) { + $query .= ' FROM ' . $from_clause; } - return $this->__get('sql_query'); + return $query; } // end of the '_getUrlSqlQuery()' function @@ -3732,7 +3732,7 @@ class PMA_DisplayResults * @param array $map the list of relations * @param boolean $is_field_truncated the condition for blob data * replacements - * @param array $analyzed_sql the analyzed query + * @param array $analyzed_sql_results the analyzed query * @param object|string $transformation_plugin the name of transformation plugin * @param string $default_function the default transformation * function @@ -3746,7 +3746,7 @@ class PMA_DisplayResults */ private function _getDataCellForNumericColumns( $column, $class, $condition_field, $meta, $map, $is_field_truncated, - $analyzed_sql, $transformation_plugin, $default_function, + $analyzed_sql_results, $transformation_plugin, $default_function, $transform_options ) { @@ -3763,7 +3763,7 @@ class PMA_DisplayResults $cell = $this->_getRowData( 'right ' . $class, $condition_field, - $analyzed_sql, $meta, $map, $column, + $analyzed_sql_results, $meta, $map, $column, $transformation_plugin, $default_function, $nowrap, $where_comparison, $transform_options, $is_field_truncated, '' @@ -3796,7 +3796,7 @@ class PMA_DisplayResults * @param string $default_function the default transformation * function * @param string $transform_options the transformation parameters - * @param array $analyzed_sql the analyzed query + * @param array $analyzed_sql_results the analyzed query * * @return string $cell the prepared data cell, html content * @@ -3807,7 +3807,7 @@ class PMA_DisplayResults private function _getDataCellForGeometryColumns( $column, $class, $meta, $map, $_url_params, $condition_field, $transformation_plugin, $default_function, $transform_options, - $analyzed_sql + $analyzed_sql_results ) { if (! isset($column) || is_null($column)) { $cell = $this->_buildNullDisplay($class, $condition_field, $meta); @@ -3845,7 +3845,7 @@ class PMA_DisplayResults ) = $this->_getPartialText($wktval); $cell = $this->_getRowData( - $class, $condition_field, $analyzed_sql, $meta, $map, + $class, $condition_field, $analyzed_sql_results, $meta, $map, $wktval, $transformation_plugin, $default_function, '', $where_comparison, $transform_options, $is_field_truncated, '' @@ -3867,7 +3867,7 @@ class PMA_DisplayResults $cell = $this->_getRowData( $class, $condition_field, - $analyzed_sql, $meta, $map, $wkbval, + $analyzed_sql_results, $meta, $map, $wkbval, $transformation_plugin, $default_function, '', $where_comparison, $transform_options, $is_field_truncated, '' @@ -3909,7 +3909,7 @@ class PMA_DisplayResults * @param string $transform_options the transformation parameters * @param boolean $is_field_truncated is data truncated due to * LimitChars - * @param array $analyzed_sql the analyzed query + * @param array $analyzed_sql_results the analyzed query * @param integer &$dt_result the link id associated to * the query which results * have to be displayed @@ -3924,7 +3924,7 @@ class PMA_DisplayResults private function _getDataCellForNonNumericColumns( $column, $class, $meta, $map, $_url_params, $condition_field, $transformation_plugin, $default_function, $transform_options, - $is_field_truncated, $analyzed_sql, &$dt_result, $col_index + $is_field_truncated, $analyzed_sql_results, &$dt_result, $col_index ) { $original_length = 0; @@ -4035,7 +4035,7 @@ class PMA_DisplayResults $cell = $this->_getRowData( $class, $condition_field, - $analyzed_sql, $meta, $map, $column, + $analyzed_sql_results, $meta, $map, $column, $transformation_plugin, $default_function, $nowrap, $where_comparison, $transform_options, $is_field_truncated, $original_length @@ -5310,7 +5310,7 @@ class PMA_DisplayResults * @param string $class css classes for the td element * @param bool $condition_field whether the column is a part of * the where clause - * @param array $analyzed_sql the analyzed query + * @param array $analyzed_sql_results the analyzed query * @param object $meta the meta-information about the * field * @param array $map the list of relations @@ -5335,11 +5335,10 @@ class PMA_DisplayResults * */ private function _getRowData( - $class, $condition_field, $analyzed_sql, $meta, $map, $data, + $class, $condition_field, $analyzed_sql_results, $meta, $map, $data, $transformation_plugin, $default_function, $nowrap, $where_comparison, $transform_options, $is_field_truncated, $original_length='' ) { - $relational_display = $_SESSION['tmpval']['relational_display']; $printview = $this->__get('printview'); $decimals = isset($meta->decimals) ? $meta->decimals : '-1'; @@ -5358,32 +5357,19 @@ class PMA_DisplayResults ) . '">'; - if (isset($analyzed_sql[0]['select_expr']) - && is_array($analyzed_sql[0]['select_expr']) - ) { - - foreach ($analyzed_sql[0]['select_expr'] - as $select_expr_position => $select_expr - ) { - - $alias = $analyzed_sql[0]['select_expr'] - [$select_expr_position]['alias']; - - if (!isset($alias) || !/*overload*/mb_strlen($alias)) { - continue; - } // end if - - $true_column = $analyzed_sql[0]['select_expr'] - [$select_expr_position]['column']; - - if ($alias == $meta->name) { - // this change in the parameter does not matter - // outside of the function - $meta->name = $true_column; - } // end if - - } // end foreach - } // end if + if (!empty($analyzed_sql_results['statement'])) { + $statement = $analyzed_sql_results['statement']; + if (!empty($statement->expr)) { + foreach ($statement->expr as $expr) { + if ((empty($expr->alias)) || (empty($expr->column))) { + continue; + } + if (strcasecmp($meta->name, $expr->alias) == 0) { + $meta->name = $expr->column; + } + } + } + } if (isset($map[$meta->name])) { diff --git a/libraries/sql-parser/src/Fragments/WhereKeyword.php b/libraries/sql-parser/src/Fragments/WhereKeyword.php index 0710738169..f5bec24040 100644 --- a/libraries/sql-parser/src/Fragments/WhereKeyword.php +++ b/libraries/sql-parser/src/Fragments/WhereKeyword.php @@ -30,7 +30,14 @@ class WhereKeyword extends Fragment * * @var array */ - public static $OPERATORS = array('&&', '(', ')', 'AND', 'OR', 'XOR', '||'); + public static $OPERATORS = array('&&', 'AND', 'OR', 'XOR', '||'); + + /** + * Identifiers recognized. + * + * @var array + */ + public $identifiers = array(); /** * Whether this fragment is an operator. @@ -67,11 +74,13 @@ class WhereKeyword extends Fragment { $ret = array(); + $expr = new WhereKeyword(); + /** - * The condition that was parsed so far. - * @var string + * Counts brackets. + * @var int */ - $tmp = ''; + $brackets = 0; for (; $list->idx < $list->count; ++$list->idx) { @@ -93,10 +102,10 @@ class WhereKeyword extends Fragment // Conditions are delimited by logical operators. if (in_array($token->value, static::$OPERATORS, true)) { - if (!empty(trim($tmp))) { + $expr->expr = trim($expr->expr); + if (!empty($expr->expr)) { // Adding the condition that is delimited by this operator. - $ret[] = new WhereKeyword($tmp); - $tmp = ''; + $ret[] = $expr; } // Adding the operator. @@ -104,21 +113,39 @@ class WhereKeyword extends Fragment $expr->isOperator = true; $ret[] = $expr; + $expr = new WhereKeyword(); continue; } + if ($token->type === Token::TYPE_OPERATOR) { + if ($token->value === '(') { + ++$brackets; + } elseif ($token->value === ')') { + --$brackets; + } + } + // No keyword is expected. if (($token->type === Token::TYPE_KEYWORD) && ($token->flags & Token::FLAG_KEYWORD_RESERVED)) { - break; + if ($brackets == 0) { + break; + } } - $tmp .= $token->token; - + $expr->expr .= $token->token; + if (($token->type === Token::TYPE_NONE) + || (($token->type === Token::TYPE_KEYWORD) && (!($token->flags & Token::FLAG_KEYWORD_RESERVED))) + || ($token->type === Token::TYPE_STRING) + || ($token->type === Token::TYPE_SYMBOL) + ) { + $expr->identifiers[] = $token->value; + } } // Last iteration was not processed. - if (!empty(trim($tmp))) { - $ret[] = new WhereKeyword($tmp); + $expr->expr = trim($expr->expr); + if (!empty($expr->expr)) { + $ret[] = $expr; } --$list->idx; diff --git a/libraries/sql-parser/src/Utils/Query.php b/libraries/sql-parser/src/Utils/Query.php index f97374404a..11a08d0212 100644 --- a/libraries/sql-parser/src/Utils/Query.php +++ b/libraries/sql-parser/src/Utils/Query.php @@ -8,6 +8,7 @@ */ namespace SqlParser\Utils; +use SqlParser\Lexer; use SqlParser\Parser; use SqlParser\Statement; use SqlParser\Token; @@ -407,32 +408,6 @@ class Query } /** - * Gets the type of clause. - * - * @param string $clause The clause. - * - * @return string - */ - public static function getClauseType($clause) - { - $type = ''; - for ($i = 0, $len = strlen($clause); $i < $len; ++$i) { - if ((empty($type)) && (ctype_space($clause[$i]))) { - // Skipping whitespaces if we haven't started determining the - // type. - continue; - } - if (!ctype_alnum($clause[$i])) { - // The type contains only alphanumeric characters. - break; - } - // Adding character. - $type .= $clause[$i]; - } - return $type; - } - - /** * Gets a specific clause. * * @param Statement $statement The parsed query that has to be modified. @@ -475,10 +450,22 @@ class Query $clauses = array_flip(array_keys($statement::$CLAUSES)); /** + * Lexer used for lexing the clause. + * @var Lexer + */ + $lexer = new Lexer($clause); + + /** + * The type of this clause. + * @var string + */ + $clauseType = $lexer->list->getNextOfType(Token::TYPE_KEYWORD)->value; + + /** * The index of this clause. * @var int */ - $clauseIdx = $clauses[static::getClauseType($clause)]; + $clauseIdx = $clauses[$clauseType]; for ($i = $statement->first; $i <= $statement->last; ++$i) { $token = $list->tokens[$i]; @@ -493,16 +480,15 @@ class Query if ($brackets == 0) { // Checking if we changed sections. - if ($token->type === Token::TYPE_KEYWORD) { - if (isset($clauses[$token->value])) { - if ($clauses[$token->value] >= $currIdx) { - $currIdx = $clauses[$token->value]; - if (($skipFirst) && ($currIdx == $clauseIdx)) { - // This token is skipped (not added to the old - // clause) because it will be replaced. - continue; - } - } + if (($token->type === Token::TYPE_KEYWORD) + && (isset($clauses[$token->value])) + && ($clauses[$token->value] >= $currIdx) + ) { + $currIdx = $clauses[$token->value]; + if (($skipFirst) && ($currIdx == $clauseIdx)) { + // This token is skipped (not added to the old + // clause) because it will be replaced. + continue; } } } @@ -526,25 +512,30 @@ class Query * * @param Statement $statement The parsed query that has to be modified. * @param TokensList $list The list of tokens. - * @param string $clause The clause to be replaced. + * @param string $old The type of the clause that should be + * replaced. This can be an entire clause. + * @param string $new The new clause. If this parameter is omitted + * it is considered to be equal with `$old`. * @param bool $onlyType Whether only the type of the clause should * be replaced or the entire clause. * * @return string */ - public static function replaceClause($statement, $list, $clause, $onlyType = false) + public static function replaceClause($statement, $list, $old, $new = null, $onlyType = false) { // TODO: Update the tokens list and the statement. + if ($new === null) { + $new = $old; + } + if ($onlyType) { - return static::getClause($statement, $list, $clause, -1, false) . ' ' . - $clause . ' ' . - static::getCLause($statement, $list, $clause, 0) . ' ' . - static::getClause($statement, $list, $clause, 1, false); + return static::getClause($statement, $list, $old, -1, false) . ' ' . + $new . ' ' . static::getCLause($statement, $list, $old, 0) . ' ' . + static::getClause($statement, $list, $old, 1, false); } - return static::getClause($statement, $list, $clause, -1, false) . ' ' . - $clause . ' ' . - static::getClause($statement, $list, $clause, 1, false); + return static::getClause($statement, $list, $old, -1, false) . ' ' . + $new . ' ' . static::getClause($statement, $list, $old, 1, false); } } diff --git a/libraries/sql.lib.php b/libraries/sql.lib.php index 5381a3e4e2..0e44cc9c6c 100644 --- a/libraries/sql.lib.php +++ b/libraries/sql.lib.php @@ -1186,6 +1186,7 @@ function PMA_countQueryResults( $analyzed_sql_results['statement'], $analyzed_sql_results['parser']->list, 'SELECT SQL_CALC_FOUND_ROWS', + null, true ); diff --git a/test/classes/PMA_DisplayResults_test.php b/test/classes/PMA_DisplayResults_test.php index 9c69a6b004..3485a80bf1 100644 --- a/test/classes/PMA_DisplayResults_test.php +++ b/test/classes/PMA_DisplayResults_test.php @@ -1240,30 +1240,18 @@ class PMA_DisplayResults_Test extends PHPUnit_Framework_TestCase */ public function dataProviderForTestSetHighlightedColumnGlobalField() { + $parser = new SqlParser\Parser( + 'SELECT * FROM db_name WHERE `db_name`.`tbl`.id > 0 AND `id` < 10' + ); return array( array( + array('statement' => $parser->statements[0]), array( - 'analyzed_sql' => array(), + 'db_name' => 'true', + 'tbl' => 'true', + 'id' => 'true', ), - array() ), - array( - array( - 'analyzed_sql' => array( - 0 => array( - 'where_clause_identifiers' => array( - 0 => '`id`', - 1 => '`id`', - 2 => '`db_name`' - ) - ) - ), - ), - array( - '`id`' => 'true', - '`db_name`' => 'true' - ) - ) ); } @@ -1576,7 +1564,7 @@ class PMA_DisplayResults_Test extends PHPUnit_Framework_TestCase * @param string $default_function the default transformation function * @param string $transform_options the transformation parameters * @param boolean $is_field_truncated is data truncated due to LimitChars - * @param array $analyzed_sql the analyzed query + * @param array $analyzed_sql_results the analyzed query * @param integer $dt_result the link id associated to the query * which results have to be displayed * @param integer $col_index the column index @@ -1590,7 +1578,7 @@ class PMA_DisplayResults_Test extends PHPUnit_Framework_TestCase $protectBinary, $column, $class, $meta, $map, $_url_params, $condition_field, $transformation_plugin, $default_function, $transform_options, $is_field_truncated, - $analyzed_sql, $dt_result, $col_index, $output + $analyzed_sql_results, $dt_result, $col_index, $output ) { $_SESSION['tmpval']['display_binary'] = true; $_SESSION['tmpval']['display_blob'] = false; @@ -1604,7 +1592,7 @@ class PMA_DisplayResults_Test extends PHPUnit_Framework_TestCase array( $column, $class, $meta, $map, $_url_params, $condition_field, $transformation_plugin, $default_function, $transform_options, - $is_field_truncated, $analyzed_sql, &$dt_result, $col_index + $is_field_truncated, $analyzed_sql_results, &$dt_result, $col_index ) ) ); |