77use Doctrine \DBAL \SQL \Parser \Visitor ;
88
99use function array_merge ;
10- use function assert ;
11- use function current ;
1210use function implode ;
13- use function key ;
14- use function next ;
1511use function preg_last_error ;
1612use function preg_match ;
17- use function reset ;
1813use function sprintf ;
1914use 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