The branch, master has been updated via 4f487780a07d2a89e97bb3249fd4389c7362681a (commit) via 68e1ff379806ab49b17855a66a9086b8f5714d69 (commit) via 8ce53e5bc81a8b798db7b4701d7afdad88c1406f (commit) via c63d3dde811b9e0deaf7eb8599871e3d47b76126 (commit) from fefd6a7def3433b7b9c52b0016044726015d43eb (commit)
- Log ----------------------------------------------------------------- commit 4f487780a07d2a89e97bb3249fd4389c7362681a Author: Michal Čihař mcihar@novell.com Date: Mon Aug 30 17:17:07 2010 +0200
bug #3042665 [parser] Add workaround for MySQL way of handling backtick.
commit 68e1ff379806ab49b17855a66a9086b8f5714d69 Author: Michal Čihař mcihar@novell.com Date: Mon Aug 30 17:16:44 2010 +0200
Do not fail if parsing query has failed.
commit 8ce53e5bc81a8b798db7b4701d7afdad88c1406f Author: Michal Čihař mcihar@novell.com Date: Mon Aug 30 17:03:55 2010 +0200
Not used anywhere.
commit c63d3dde811b9e0deaf7eb8599871e3d47b76126 Author: Michal Čihař mcihar@novell.com Date: Mon Aug 30 16:59:53 2010 +0200
Add more testcases.
-----------------------------------------------------------------------
Summary of changes: ChangeLog | 1 + libraries/import/sql.php | 14 +++++- libraries/sqlparser.lib.php | 39 +++++++++++++-- test/PMA_SQL_parser_test.php | 104 +++++++++++++++++++++++++++++++++++++---- 4 files changed, 140 insertions(+), 18 deletions(-)
diff --git a/ChangeLog b/ChangeLog index 3613acb..bdbba03 100644 --- a/ChangeLog +++ b/ChangeLog @@ -112,6 +112,7 @@ $Id$ + [interface] Added charts to status tab, profiling page and query results + [interface] AJAXification on various pages - [core] Remove last remaining parts of profiling code which was removed in 2006. +- bug #3042665 [parser] Add workaround for MySQL way of handling backtick.
3.3.7.0 (not yet released) - patch #3050492 [PDF scratchboard] Cannot drag table box to the edge after diff --git a/libraries/import/sql.php b/libraries/import/sql.php index fe62ca5..0e61080 100644 --- a/libraries/import/sql.php +++ b/libraries/import/sql.php @@ -168,8 +168,20 @@ while (!($GLOBALS['finished'] && $i >= $len) && !$error && !$timeout_passed) { while (!$endq) { // Find next quote $pos = strpos($buffer, $quote, $i + 1); + /* + * Behave same as MySQL and accept end of query as end of backtick. + * I know this is sick, but MySQL behaves like this: + * + * SELECT * FROM `table + * + * is treated like + * + * SELECT * FROM `table` + */ + if ($pos === FALSE && $quote == '`' && $found_delimiter) { + $pos = $first_sql_delimiter - 1; // No quote? Too short string - if ($pos === FALSE) { + } elseif ($pos === FALSE) { // We hit end of string => unclosed quote, but we handle it as end of query if ($GLOBALS['finished']) { $endq = TRUE; diff --git a/libraries/sqlparser.lib.php b/libraries/sqlparser.lib.php index b8b2bba..7c8e8fa 100644 --- a/libraries/sqlparser.lib.php +++ b/libraries/sqlparser.lib.php @@ -211,7 +211,6 @@ if (! defined('PMA_MINIMUM_COMMON')) { */ function PMA_SQP_parse($sql) { - global $cfg; global $PMA_SQPdata_column_attrib, $PMA_SQPdata_reserved_word, $PMA_SQPdata_column_type, $PMA_SQPdata_function_name, $PMA_SQPdata_column_attrib_cnt, $PMA_SQPdata_reserved_word_cnt, $PMA_SQPdata_column_type_cnt, $PMA_SQPdata_function_name_cnt; global $mysql_charsets, $mysql_collations_flat, $mysql_charsets_count, $mysql_collations_count; @@ -342,10 +341,38 @@ if (! defined('PMA_MINIMUM_COMMON')) { $pos = $GLOBALS['PMA_strpos'](' ' . $sql, $quotetype, $oldpos + 1) - 1; // ($pos === FALSE) if ($pos < 0) { - $debugstr = __('Unclosed quote') . ' @ ' . $startquotepos. "\n" - . 'STR: ' . htmlspecialchars($quotetype); - PMA_SQP_throwError($debugstr, $sql); - return $sql_array; + if ($c == '`') { + /* + * Behave same as MySQL and accept end of query as end of backtick. + * I know this is sick, but MySQL behaves like this: + * + * SELECT * FROM `table + * + * is treated like + * + * SELECT * FROM `table` + */ + $pos_quote_separator = $GLOBALS['PMA_strpos'](' ' . $sql, $GLOBALS['sql_delimiter'], $oldpos + 1) - 1; + if ($pos_quote_separator < 0) { + $len += 1; + $sql .= '`'; + $sql_array['raw'] .= '`'; + $pos = $len; + } else { + $len += 1; + $sql = $GLOBALS['PMA_substr']($sql, 0, $pos_quote_separator) . '`' . $GLOBALS['PMA_substr']($sql, $pos_quote_separator); + $sql_array['raw'] = $sql; + $pos = $pos_quote_separator; + } + if (class_exists('PMA_Message')) { + PMA_Message::warning(__('Automatically appended backtick to the end of query!'))->display(); + } + } else { + $debugstr = __('Unclosed quote') . ' @ ' . $startquotepos. "\n" + . 'STR: ' . htmlspecialchars($quotetype); + PMA_SQP_throwError($debugstr, $sql); + return $sql_array; + } }
// If the quote is the first character, it can't be @@ -806,7 +833,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { */ function PMA_SQP_analyze($arr) { - if ($arr == array()) { + if ($arr == array() || !isset($arr['len'])) { return array(); } $result = array(); diff --git a/test/PMA_SQL_parser_test.php b/test/PMA_SQL_parser_test.php index 2774ba1..aa3299c 100644 --- a/test/PMA_SQL_parser_test.php +++ b/test/PMA_SQL_parser_test.php @@ -149,12 +149,13 @@ class PMA_SQL_parser_test extends PHPUnit_Framework_TestCase public function testParse_4() { $this->assertParser('SELECT * from `aaa;', array ( - 'raw' => 'SELECT * from `aaa;', + 'raw' => 'SELECT * from `aaa`;', 0 => array ( - 'type' => 'alpha', + 'type' => 'alpha_reservedWord', 'data' => 'SELECT', 'pos' => 6, + 'forbidden' => true, ), 1 => array ( @@ -164,18 +165,99 @@ class PMA_SQL_parser_test extends PHPUnit_Framework_TestCase ), 2 => array ( - 'type' => 'alpha', + 'type' => 'alpha_reservedWord', 'data' => 'from', 'pos' => 13, + 'forbidden' => true, ), - ), -'<p>There seems to be an error in your SQL query. The MySQL server error output below, if there is any, may also help you in diagnosing the problem</p> -<pre> -ERROR: Unclosed quote @ 14 -STR: ` -SQL: SELECT * from `aaa; -</pre> -'); + 3 => + array ( + 'type' => 'quote_backtick', + 'data' => '`aaa`', + 'pos' => 0, + ), + 4 => + array ( + 'type' => 'punct_queryend', + 'data' => ';', + 'pos' => 0, + ), + 'len' => 5, + )); + } + + public function testParse_5() + { + $this->assertParser('SELECT * FROM `a_table` tbla INNER JOIN b_table` tblb ON tblb.id = tbla.id WHERE tblb.field1 != tbla.field1`;', array ( + 'raw' => 'SELECT * FROM `a_table` tbla INNER JOIN b_table` tblb ON tblb.id = tbla.id WHERE tblb.field1 != tbla.field1`;', + 0 => + array ( + 'type' => 'alpha_reservedWord', + 'data' => 'SELECT', + 'pos' => 6, + 'forbidden' => true, + ), + 1 => + array ( + 'type' => 'punct', + 'data' => '*', + 'pos' => 0, + ), + 2 => + array ( + 'type' => 'alpha_reservedWord', + 'data' => 'FROM', + 'pos' => 13, + 'forbidden' => true, + ), + 3 => + array ( + 'type' => 'quote_backtick', + 'data' => '`a_table`', + 'pos' => 0, + ), + 4 => + array ( + 'type' => 'alpha_identifier', + 'data' => 'tbla', + 'pos' => 28, + 'forbidden' => false, + ), + 5 => + array ( + 'type' => 'alpha_reservedWord', + 'data' => 'INNER', + 'pos' => 34, + 'forbidden' => true, + ), + 6 => + array ( + 'type' => 'alpha_reservedWord', + 'data' => 'JOIN', + 'pos' => 39, + 'forbidden' => true, + ), + 7 => + array ( + 'type' => 'alpha_identifier', + 'data' => 'b_table', + 'pos' => 47, + 'forbidden' => false, + ), + 8 => + array ( + 'type' => 'quote_backtick', + 'data' => '` tblb ON tblb.id = tbla.id WHERE tblb.field1 != tbla.field1`', + 'pos' => 0, + ), + 9 => + array ( + 'type' => 'punct_queryend', + 'data' => ';', + 'pos' => 0, + ), + 'len' => 10, + )); } } ?>
hooks/post-receive