getMySQLStringLiteralPattern("'"), $this->getMySQLStringLiteralPattern('"'), ]; } else { $patterns = [ $this->getAnsiSQLStringLiteralPattern("'"), $this->getAnsiSQLStringLiteralPattern('"'), ]; } $patterns = array_merge($patterns, [ self::BACKTICK_IDENTIFIER, self::BRACKET_IDENTIFIER, self::MULTICHAR, self::ONE_LINE_COMMENT, self::MULTI_LINE_COMMENT, self::OTHER, ]); $this->sqlPattern = sprintf('(%s)', implode('|', $patterns)); $this->tokenPattern = '~\\G' . '(?P' . self::NAMED_PARAMETER . ')' . '|(?P' . self::POSITIONAL_PARAMETER . ')' . '|(?P' . $this->sqlPattern . '|' . self::SPECIAL . ')' . '~s'; } /** * Parses the given SQL statement * * @throws Exception */ public function parse(string $sql, Visitor $visitor): void { $offset = 0; $length = strlen($sql); while ($offset < $length) { if (preg_match($this->tokenPattern, $sql, $matches, 0, $offset) === 1) { $match = $matches[0]; if ($matches['named'] !== '') { $visitor->acceptNamedParameter($match); } elseif ($matches['positional'] !== '') { $visitor->acceptPositionalParameter($match); } else { $visitor->acceptOther($match); } $offset += strlen($match); } elseif (preg_last_error() !== PREG_NO_ERROR) { // @codeCoverageIgnoreStart throw RegularExpressionError::new(); // @codeCoverageIgnoreEnd } } } private function getMySQLStringLiteralPattern(string $delimiter): string { return $delimiter . '((\\\\.)|(?![' . $delimiter . '\\\\]).)*' . $delimiter; } private function getAnsiSQLStringLiteralPattern(string $delimiter): string { return $delimiter . '[^' . $delimiter . ']*' . $delimiter; } }