diff --git a/src/PHPSQLParser/lexer/PHPSQLLexer.php b/src/PHPSQLParser/lexer/PHPSQLLexer.php index 8faf5574..ea1315f4 100644 --- a/src/PHPSQLParser/lexer/PHPSQLLexer.php +++ b/src/PHPSQLParser/lexer/PHPSQLLexer.php @@ -283,25 +283,30 @@ protected function isBacktick($token) { } protected function balanceBackticks($tokens) { + $result = []; + $n = count($tokens); $i = 0; - $cnt = count($tokens); - while ($i < $cnt) { - - if (!isset($tokens[$i])) { - $i++; - continue; - } - + while ($i < $n) { $token = $tokens[$i]; - + // 如果遇到一个反引号,则尝试合并直到找到匹配的结束符 if ($this->isBacktick($token)) { - $tokens = $this->balanceCharacter($tokens, $i, $token); + $balanced = $token; + $i++; + while ($i < $n) { + $balanced .= $tokens[$i]; + // 遇到匹配的结束符后退出内层循环 + if ($tokens[$i] === $token) { + break; + } + $i++; + } + $result[] = $balanced; + } else { + $result[] = $token; } - $i++; } - - return $tokens; + return $result; } // backticks are not balanced within one token, so we have diff --git a/tests/cases/parser/backtickTest.php b/tests/cases/parser/backtickTest.php index 4ea27a2f..a584d10e 100644 --- a/tests/cases/parser/backtickTest.php +++ b/tests/cases/parser/backtickTest.php @@ -63,5 +63,43 @@ public function testBacktick() { $this->assertEquals($expected, $p, "issue 35: ben's test"); } + public function generateRandomString($length = 10) + { + $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $randomString = ''; + for ($i = 0; $i < $length; $i++) { + $randomString .= $characters[rand(0, strlen($characters) - 1)]; + } + return $randomString; + } + + public function createInFilter($len) + { + $arr = []; + for ($i = 0; $i < $len; $i++) { + $arr[] = $this->generateRandomString(); + } + return '("' . implode($arr, '","') . '")'; + } + + public function testOptimizeBalanceBackticks() + { + $parser = new PHPSQLParser(); + + // test backticks + $sql = 'SELECT id, name from test where `id map` in ("a b c 1-2_3")'; + $obj = $parser->parse($sql); + $creator = new PHPSQLCreator($obj); + $sql2 = $creator->created; + $this->assertTrue(mb_strtolower($sql) === mb_strtolower($sql2)); + + // The more in conditions, the worse the performance + // The difference before and after optimization is 10 times + $sql = 'SELECT id,name from test where id in ' . $this->createInFilter(1024); + $start = microtime(true); + $parser->parse($sql); + $cost = intval((microtime(true) - $start) * 1000); + print_r('cost ' . $cost . PHP_EOL); + } }