Skip to content

Commit 2fcb5eb

Browse files
authored
Merge pull request #6926 from shyim/fix/performance-parser
feat: improve performance of sql parser
2 parents 6459738 + 1ab9177 commit 2fcb5eb

File tree

1 file changed

+20
-33
lines changed

1 file changed

+20
-33
lines changed

src/SQL/Parser.php

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,9 @@
77
use Doctrine\DBAL\SQL\Parser\Visitor;
88

99
use function array_merge;
10-
use function assert;
11-
use function current;
1210
use function implode;
13-
use function key;
14-
use function next;
1511
use function preg_last_error;
1612
use function preg_match;
17-
use function reset;
1813
use function sprintf;
1914
use function strlen;
2015

@@ -45,6 +40,7 @@ final class Parser
4540
private const OTHER = '[^' . self::SPECIAL_CHARS . ']+';
4641

4742
private string $sqlPattern;
43+
private string $tokenPattern;
4844

4945
public function __construct(bool $mySQLStringEscaping)
5046
{
@@ -69,7 +65,12 @@ public function __construct(bool $mySQLStringEscaping)
6965
self::OTHER,
7066
]);
7167

72-
$this->sqlPattern = sprintf('(%s)', implode('|', $patterns));
68+
$this->sqlPattern = sprintf('(%s)', implode('|', $patterns));
69+
$this->tokenPattern = '~\\G'
70+
. '(?P<named>' . self::NAMED_PARAMETER . ')'
71+
. '|(?P<positional>' . self::POSITIONAL_PARAMETER . ')'
72+
. '|(?P<other>' . $this->sqlPattern . '|' . self::SPECIAL . ')'
73+
. '~s';
7374
}
7475

7576
/**
@@ -79,40 +80,26 @@ public function __construct(bool $mySQLStringEscaping)
7980
*/
8081
public function parse(string $sql, Visitor $visitor): void
8182
{
82-
/** @var array<string,callable> $patterns */
83-
$patterns = [
84-
self::NAMED_PARAMETER => static function (string $sql) use ($visitor): void {
85-
$visitor->acceptNamedParameter($sql);
86-
},
87-
self::POSITIONAL_PARAMETER => static function (string $sql) use ($visitor): void {
88-
$visitor->acceptPositionalParameter($sql);
89-
},
90-
$this->sqlPattern => static function (string $sql) use ($visitor): void {
91-
$visitor->acceptOther($sql);
92-
},
93-
self::SPECIAL => static function (string $sql) use ($visitor): void {
94-
$visitor->acceptOther($sql);
95-
},
96-
];
97-
9883
$offset = 0;
99-
100-
while (($handler = current($patterns)) !== false) {
101-
if (preg_match('~\G' . key($patterns) . '~s', $sql, $matches, 0, $offset) === 1) {
102-
$handler($matches[0]);
103-
reset($patterns);
104-
105-
$offset += strlen($matches[0]);
84+
$length = strlen($sql);
85+
while ($offset < $length) {
86+
if (preg_match($this->tokenPattern, $sql, $matches, 0, $offset) === 1) {
87+
$match = $matches[0];
88+
if ($matches['named'] !== '') {
89+
$visitor->acceptNamedParameter($match);
90+
} elseif ($matches['positional'] !== '') {
91+
$visitor->acceptPositionalParameter($match);
92+
} else {
93+
$visitor->acceptOther($match);
94+
}
95+
96+
$offset += strlen($match);
10697
} elseif (preg_last_error() !== PREG_NO_ERROR) {
10798
// @codeCoverageIgnoreStart
10899
throw RegularExpressionError::new();
109100
// @codeCoverageIgnoreEnd
110-
} else {
111-
next($patterns);
112101
}
113102
}
114-
115-
assert($offset === strlen($sql));
116103
}
117104

118105
private function getMySQLStringLiteralPattern(string $delimiter): string

0 commit comments

Comments
 (0)