Commit version 24.12.13800
This commit is contained in:
@ -5,11 +5,12 @@ declare(strict_types=1);
|
||||
namespace Doctrine\SqlFormatter;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
use const PHP_EOL;
|
||||
|
||||
final class CliHighlighter implements Highlighter
|
||||
{
|
||||
const HIGHLIGHT_FUNCTIONS = 'functions';
|
||||
public const HIGHLIGHT_FUNCTIONS = 'functions';
|
||||
|
||||
/** @var array<string, string> */
|
||||
private $escapeSequences;
|
||||
@ -33,9 +34,9 @@ final class CliHighlighter implements Highlighter
|
||||
];
|
||||
}
|
||||
|
||||
public function highlightToken(int $type, string $value) : string
|
||||
public function highlightToken(int $type, string $value): string
|
||||
{
|
||||
if ($type === Token::TOKEN_TYPE_BOUNDARY && ($value==='(' || $value===')')) {
|
||||
if ($type === Token::TOKEN_TYPE_BOUNDARY && ($value === '(' || $value === ')')) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
@ -47,7 +48,7 @@ final class CliHighlighter implements Highlighter
|
||||
return $prefix . $value . "\x1b[0m";
|
||||
}
|
||||
|
||||
private function prefix(int $type)
|
||||
private function prefix(int $type): ?string
|
||||
{
|
||||
if (! isset(self::TOKEN_TYPE_TO_HIGHLIGHT[$type])) {
|
||||
return null;
|
||||
@ -56,7 +57,7 @@ final class CliHighlighter implements Highlighter
|
||||
return $this->escapeSequences[self::TOKEN_TYPE_TO_HIGHLIGHT[$type]];
|
||||
}
|
||||
|
||||
public function highlightError(string $value) : string
|
||||
public function highlightError(string $value): string
|
||||
{
|
||||
return sprintf(
|
||||
'%s%s%s%s',
|
||||
@ -67,12 +68,12 @@ final class CliHighlighter implements Highlighter
|
||||
);
|
||||
}
|
||||
|
||||
public function highlightErrorMessage(string $value) : string
|
||||
public function highlightErrorMessage(string $value): string
|
||||
{
|
||||
return $this->highlightError($value);
|
||||
}
|
||||
|
||||
public function output(string $string) : string
|
||||
public function output(string $string): string
|
||||
{
|
||||
return $string . "\n";
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ final class Cursor
|
||||
$this->tokens = $tokens;
|
||||
}
|
||||
|
||||
public function next(int $exceptTokenType = null)
|
||||
public function next(?int $exceptTokenType = null): ?Token
|
||||
{
|
||||
while ($token = $this->tokens[++$this->position] ?? null) {
|
||||
if ($exceptTokenType !== null && $token->isOfType($exceptTokenType)) {
|
||||
@ -33,7 +33,7 @@ final class Cursor
|
||||
return null;
|
||||
}
|
||||
|
||||
public function previous(int $exceptTokenType = null)
|
||||
public function previous(?int $exceptTokenType = null): ?Token
|
||||
{
|
||||
while ($token = $this->tokens[--$this->position] ?? null) {
|
||||
if ($exceptTokenType !== null && $token->isOfType($exceptTokenType)) {
|
||||
@ -46,7 +46,7 @@ final class Cursor
|
||||
return null;
|
||||
}
|
||||
|
||||
public function subCursor() : self
|
||||
public function subCursor(): self
|
||||
{
|
||||
$cursor = new self($this->tokens);
|
||||
$cursor->position = $this->position;
|
||||
|
@ -6,7 +6,7 @@ namespace Doctrine\SqlFormatter;
|
||||
|
||||
interface Highlighter
|
||||
{
|
||||
const TOKEN_TYPE_TO_HIGHLIGHT = [
|
||||
public const TOKEN_TYPE_TO_HIGHLIGHT = [
|
||||
Token::TOKEN_TYPE_BOUNDARY => self::HIGHLIGHT_BOUNDARY,
|
||||
Token::TOKEN_TYPE_WORD => self::HIGHLIGHT_WORD,
|
||||
Token::TOKEN_TYPE_BACKTICK_QUOTE => self::HIGHLIGHT_BACKTICK_QUOTE,
|
||||
@ -20,30 +20,30 @@ interface Highlighter
|
||||
Token::TOKEN_TYPE_BLOCK_COMMENT => self::HIGHLIGHT_COMMENT,
|
||||
];
|
||||
|
||||
const HIGHLIGHT_BOUNDARY = 'boundary';
|
||||
const HIGHLIGHT_WORD = 'word';
|
||||
const HIGHLIGHT_BACKTICK_QUOTE = 'backtickQuote';
|
||||
const HIGHLIGHT_QUOTE = 'quote';
|
||||
const HIGHLIGHT_RESERVED = 'reserved';
|
||||
const HIGHLIGHT_NUMBER = 'number';
|
||||
const HIGHLIGHT_VARIABLE = 'variable';
|
||||
const HIGHLIGHT_COMMENT = 'comment';
|
||||
const HIGHLIGHT_ERROR = 'error';
|
||||
public const HIGHLIGHT_BOUNDARY = 'boundary';
|
||||
public const HIGHLIGHT_WORD = 'word';
|
||||
public const HIGHLIGHT_BACKTICK_QUOTE = 'backtickQuote';
|
||||
public const HIGHLIGHT_QUOTE = 'quote';
|
||||
public const HIGHLIGHT_RESERVED = 'reserved';
|
||||
public const HIGHLIGHT_NUMBER = 'number';
|
||||
public const HIGHLIGHT_VARIABLE = 'variable';
|
||||
public const HIGHLIGHT_COMMENT = 'comment';
|
||||
public const HIGHLIGHT_ERROR = 'error';
|
||||
|
||||
/**
|
||||
* Highlights a token depending on its type.
|
||||
*/
|
||||
public function highlightToken(int $type, string $value) : string;
|
||||
public function highlightToken(int $type, string $value): string;
|
||||
|
||||
/**
|
||||
* Highlights a token which causes an issue
|
||||
*/
|
||||
public function highlightError(string $value) : string;
|
||||
public function highlightError(string $value): string;
|
||||
|
||||
/**
|
||||
* Highlights an error message
|
||||
*/
|
||||
public function highlightErrorMessage(string $value) : string;
|
||||
public function highlightErrorMessage(string $value): string;
|
||||
|
||||
/**
|
||||
* Helper function for building string output
|
||||
@ -52,5 +52,5 @@ interface Highlighter
|
||||
*
|
||||
* @return string The quoted string
|
||||
*/
|
||||
public function output(string $string) : string;
|
||||
public function output(string $string): string;
|
||||
}
|
||||
|
@ -7,13 +7,14 @@ namespace Doctrine\SqlFormatter;
|
||||
use function htmlentities;
|
||||
use function sprintf;
|
||||
use function trim;
|
||||
|
||||
use const ENT_COMPAT;
|
||||
use const ENT_IGNORE;
|
||||
use const PHP_EOL;
|
||||
|
||||
final class HtmlHighlighter implements Highlighter
|
||||
{
|
||||
const HIGHLIGHT_PRE = 'pre';
|
||||
public const HIGHLIGHT_PRE = 'pre';
|
||||
|
||||
/**
|
||||
* This flag tells us if queries need to be enclosed in <pre> tags
|
||||
@ -45,11 +46,11 @@ final class HtmlHighlighter implements Highlighter
|
||||
$this->usePre = $usePre;
|
||||
}
|
||||
|
||||
public function highlightToken(int $type, string $value) : string
|
||||
public function highlightToken(int $type, string $value): string
|
||||
{
|
||||
$value = htmlentities($value, ENT_COMPAT | ENT_IGNORE, 'UTF-8');
|
||||
|
||||
if ($type === Token::TOKEN_TYPE_BOUNDARY && ($value==='(' || $value===')')) {
|
||||
if ($type === Token::TOKEN_TYPE_BOUNDARY && ($value === '(' || $value === ')')) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
@ -61,7 +62,7 @@ final class HtmlHighlighter implements Highlighter
|
||||
return '<span ' . $attributes . '>' . $value . '</span>';
|
||||
}
|
||||
|
||||
public function attributes(int $type)
|
||||
public function attributes(int $type): ?string
|
||||
{
|
||||
if (! isset(self::TOKEN_TYPE_TO_HIGHLIGHT[$type])) {
|
||||
return null;
|
||||
@ -70,7 +71,7 @@ final class HtmlHighlighter implements Highlighter
|
||||
return $this->htmlAttributes[self::TOKEN_TYPE_TO_HIGHLIGHT[$type]];
|
||||
}
|
||||
|
||||
public function highlightError(string $value) : string
|
||||
public function highlightError(string $value): string
|
||||
{
|
||||
return sprintf(
|
||||
'%s<span %s>%s</span>',
|
||||
@ -80,16 +81,16 @@ final class HtmlHighlighter implements Highlighter
|
||||
);
|
||||
}
|
||||
|
||||
public function highlightErrorMessage(string $value) : string
|
||||
public function highlightErrorMessage(string $value): string
|
||||
{
|
||||
return $this->highlightError($value);
|
||||
}
|
||||
|
||||
public function output(string $string) : string
|
||||
public function output(string $string): string
|
||||
{
|
||||
$string =trim($string);
|
||||
$string = trim($string);
|
||||
|
||||
// This is derp truncate for long list
|
||||
// Added by Observium Developers. IN list truncated for a long list
|
||||
$string = preg_replace('!(IN</span>\s*)(\()([^\)]+)(\))!', '$1$2<div class="text-truncate" onclick="revealHiddenOverflow(this)">$3</div>$4', $string);
|
||||
|
||||
if (! $this->usePre) {
|
||||
|
@ -6,22 +6,22 @@ namespace Doctrine\SqlFormatter;
|
||||
|
||||
final class NullHighlighter implements Highlighter
|
||||
{
|
||||
public function highlightToken(int $type, string $value) : string
|
||||
public function highlightToken(int $type, string $value): string
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function highlightError(string $value) : string
|
||||
public function highlightError(string $value): string
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function highlightErrorMessage(string $value) : string
|
||||
public function highlightErrorMessage(string $value): string
|
||||
{
|
||||
return ' ' . $value;
|
||||
}
|
||||
|
||||
public function output(string $string) : string
|
||||
public function output(string $string): string
|
||||
{
|
||||
return $string;
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ use function str_repeat;
|
||||
use function str_replace;
|
||||
use function strlen;
|
||||
use function trim;
|
||||
|
||||
use const PHP_SAPI;
|
||||
|
||||
final class SqlFormatter
|
||||
@ -33,7 +34,7 @@ final class SqlFormatter
|
||||
/** @var Tokenizer */
|
||||
private $tokenizer;
|
||||
|
||||
public function __construct(Highlighter $highlighter = null)
|
||||
public function __construct(?Highlighter $highlighter = null)
|
||||
{
|
||||
$this->tokenizer = new Tokenizer();
|
||||
$this->highlighter = $highlighter ?? (PHP_SAPI === 'cli' ? new CliHighlighter() : new HtmlHighlighter());
|
||||
@ -46,7 +47,7 @@ final class SqlFormatter
|
||||
*
|
||||
* @return string The SQL string with HTML styles and formatting wrapped in a <pre> tag
|
||||
*/
|
||||
public function format(string $string, string $indentString = ' ') : string
|
||||
public function format(string $string, string $indentString = ' '): string
|
||||
{
|
||||
// This variable will be populated with formatted html
|
||||
$return = '';
|
||||
@ -148,7 +149,7 @@ final class SqlFormatter
|
||||
// Allow up to 3 non-whitespace tokens inside inline parentheses
|
||||
$length = 0;
|
||||
$subCursor = $cursor->subCursor();
|
||||
for ($j=1; $j<=250; $j++) {
|
||||
for ($j = 1; $j <= 250; $j++) {
|
||||
// Reached end of string
|
||||
$next = $subCursor->next(Token::TOKEN_TYPE_WHITESPACE);
|
||||
if (! $next) {
|
||||
@ -164,17 +165,19 @@ final class SqlFormatter
|
||||
}
|
||||
|
||||
// Reached an invalid token for inline parentheses
|
||||
if ($next->value()===';' || $next->value()==='(') {
|
||||
if ($next->value() === ';' || $next->value() === '(') {
|
||||
break;
|
||||
}
|
||||
|
||||
// Reached an invalid token type for inline parentheses
|
||||
if ($next->isOfType(
|
||||
Token::TOKEN_TYPE_RESERVED_TOPLEVEL,
|
||||
Token::TOKEN_TYPE_RESERVED_NEWLINE,
|
||||
Token::TOKEN_TYPE_COMMENT,
|
||||
Token::TOKEN_TYPE_BLOCK_COMMENT
|
||||
)) {
|
||||
if (
|
||||
$next->isOfType(
|
||||
Token::TOKEN_TYPE_RESERVED_TOPLEVEL,
|
||||
Token::TOKEN_TYPE_RESERVED_NEWLINE,
|
||||
Token::TOKEN_TYPE_COMMENT,
|
||||
Token::TOKEN_TYPE_BLOCK_COMMENT
|
||||
)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -206,8 +209,8 @@ final class SqlFormatter
|
||||
$indentLevel--;
|
||||
|
||||
// Reset indent level
|
||||
while ($j=array_shift($indentTypes)) {
|
||||
if ($j!=='special') {
|
||||
while ($j = array_shift($indentTypes)) {
|
||||
if ($j !== 'special') {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -232,7 +235,7 @@ final class SqlFormatter
|
||||
|
||||
// If the last indent type was 'special', decrease the special indent for this round
|
||||
reset($indentTypes);
|
||||
if (current($indentTypes)==='special') {
|
||||
if (current($indentTypes) === 'special') {
|
||||
$indentLevel--;
|
||||
array_shift($indentTypes);
|
||||
}
|
||||
@ -256,9 +259,11 @@ final class SqlFormatter
|
||||
if ($token->value() === 'LIMIT' && ! $inlineParentheses) {
|
||||
$clauseLimit = true;
|
||||
}
|
||||
} elseif ($clauseLimit &&
|
||||
} elseif (
|
||||
$clauseLimit &&
|
||||
$token->value() !== ',' &&
|
||||
! $token->isOfType(Token::TOKEN_TYPE_NUMBER, Token::TOKEN_TYPE_WHITESPACE)) {
|
||||
! $token->isOfType(Token::TOKEN_TYPE_NUMBER, Token::TOKEN_TYPE_WHITESPACE)
|
||||
) {
|
||||
// Checks if we are out of the limit clause
|
||||
$clauseLimit = false;
|
||||
} elseif ($token->value() === ',' && ! $inlineParentheses) {
|
||||
@ -294,9 +299,11 @@ final class SqlFormatter
|
||||
}
|
||||
|
||||
// If the token shouldn't have a space before it
|
||||
if ($token->value() === '.' ||
|
||||
if (
|
||||
$token->value() === '.' ||
|
||||
$token->value() === ',' ||
|
||||
$token->value() === ';') {
|
||||
$token->value() === ';'
|
||||
) {
|
||||
$return = rtrim($return, ' ');
|
||||
}
|
||||
|
||||
@ -322,12 +329,14 @@ final class SqlFormatter
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($prev->isOfType(
|
||||
Token::TOKEN_TYPE_QUOTE,
|
||||
Token::TOKEN_TYPE_BACKTICK_QUOTE,
|
||||
Token::TOKEN_TYPE_WORD,
|
||||
Token::TOKEN_TYPE_NUMBER
|
||||
)) {
|
||||
if (
|
||||
$prev->isOfType(
|
||||
Token::TOKEN_TYPE_QUOTE,
|
||||
Token::TOKEN_TYPE_BACKTICK_QUOTE,
|
||||
Token::TOKEN_TYPE_WORD,
|
||||
Token::TOKEN_TYPE_NUMBER
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -355,7 +364,7 @@ final class SqlFormatter
|
||||
*
|
||||
* @return string The SQL string with HTML styles applied
|
||||
*/
|
||||
public function highlight(string $string) : string
|
||||
public function highlight(string $string): string
|
||||
{
|
||||
$cursor = $this->tokenizer->tokenize($string);
|
||||
|
||||
@ -378,7 +387,7 @@ final class SqlFormatter
|
||||
*
|
||||
* @return string The SQL string without comments
|
||||
*/
|
||||
public function compress(string $string) : string
|
||||
public function compress(string $string): string
|
||||
{
|
||||
$result = '';
|
||||
$cursor = $this->tokenizer->tokenize($string);
|
||||
@ -392,11 +401,13 @@ final class SqlFormatter
|
||||
|
||||
// Remove extra whitespace in reserved words (e.g "OUTER JOIN" becomes "OUTER JOIN")
|
||||
|
||||
if ($token->isOfType(
|
||||
Token::TOKEN_TYPE_RESERVED,
|
||||
Token::TOKEN_TYPE_RESERVED_NEWLINE,
|
||||
Token::TOKEN_TYPE_RESERVED_TOPLEVEL
|
||||
)) {
|
||||
if (
|
||||
$token->isOfType(
|
||||
Token::TOKEN_TYPE_RESERVED,
|
||||
Token::TOKEN_TYPE_RESERVED_NEWLINE,
|
||||
Token::TOKEN_TYPE_RESERVED_TOPLEVEL
|
||||
)
|
||||
) {
|
||||
$newValue = preg_replace('/\s+/', ' ', $token->value());
|
||||
assert($newValue !== null);
|
||||
$token = $token->withValue($newValue);
|
||||
|
@ -10,23 +10,23 @@ use function strpos;
|
||||
final class Token
|
||||
{
|
||||
// Constants for token types
|
||||
const TOKEN_TYPE_WHITESPACE = 0;
|
||||
const TOKEN_TYPE_WORD = 1;
|
||||
const TOKEN_TYPE_QUOTE = 2;
|
||||
const TOKEN_TYPE_BACKTICK_QUOTE = 3;
|
||||
const TOKEN_TYPE_RESERVED = 4;
|
||||
const TOKEN_TYPE_RESERVED_TOPLEVEL = 5;
|
||||
const TOKEN_TYPE_RESERVED_NEWLINE = 6;
|
||||
const TOKEN_TYPE_BOUNDARY = 7;
|
||||
const TOKEN_TYPE_COMMENT = 8;
|
||||
const TOKEN_TYPE_BLOCK_COMMENT = 9;
|
||||
const TOKEN_TYPE_NUMBER = 10;
|
||||
const TOKEN_TYPE_ERROR = 11;
|
||||
const TOKEN_TYPE_VARIABLE = 12;
|
||||
public const TOKEN_TYPE_WHITESPACE = 0;
|
||||
public const TOKEN_TYPE_WORD = 1;
|
||||
public const TOKEN_TYPE_QUOTE = 2;
|
||||
public const TOKEN_TYPE_BACKTICK_QUOTE = 3;
|
||||
public const TOKEN_TYPE_RESERVED = 4;
|
||||
public const TOKEN_TYPE_RESERVED_TOPLEVEL = 5;
|
||||
public const TOKEN_TYPE_RESERVED_NEWLINE = 6;
|
||||
public const TOKEN_TYPE_BOUNDARY = 7;
|
||||
public const TOKEN_TYPE_COMMENT = 8;
|
||||
public const TOKEN_TYPE_BLOCK_COMMENT = 9;
|
||||
public const TOKEN_TYPE_NUMBER = 10;
|
||||
public const TOKEN_TYPE_ERROR = 11;
|
||||
public const TOKEN_TYPE_VARIABLE = 12;
|
||||
|
||||
// Constants for different components of a token
|
||||
const TOKEN_TYPE = 0;
|
||||
const TOKEN_VALUE = 1;
|
||||
public const TOKEN_TYPE = 0;
|
||||
public const TOKEN_VALUE = 1;
|
||||
|
||||
/** @var int */
|
||||
private $type;
|
||||
@ -40,29 +40,29 @@ final class Token
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function value() : string
|
||||
public function value(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function type() : int
|
||||
public function type(): int
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function isOfType(int ...$types) : bool
|
||||
public function isOfType(int ...$types): bool
|
||||
{
|
||||
return in_array($this->type, $types, true);
|
||||
}
|
||||
|
||||
public function hasExtraWhitespace() : bool
|
||||
public function hasExtraWhitespace(): bool
|
||||
{
|
||||
return strpos($this->value(), ' ')!== false ||
|
||||
return strpos($this->value(), ' ') !== false ||
|
||||
strpos($this->value(), "\n") !== false ||
|
||||
strpos($this->value(), "\t") !== false;
|
||||
}
|
||||
|
||||
public function withValue(string $value) : self
|
||||
public function withValue(string $value): self
|
||||
{
|
||||
return new self($this->type(), $value);
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ final class Tokenizer
|
||||
'CONVERT',
|
||||
'CREATE',
|
||||
'CROSS',
|
||||
'CURRENT ROW',
|
||||
'CURRENT_TIMESTAMP',
|
||||
'DATABASE',
|
||||
'DATABASES',
|
||||
@ -108,11 +109,13 @@ final class Tokenizer
|
||||
'FAST',
|
||||
'FIELDS',
|
||||
'FILE',
|
||||
'FILTER',
|
||||
'FIRST',
|
||||
'FIXED',
|
||||
'FLUSH',
|
||||
'FOR',
|
||||
'FORCE',
|
||||
'FOLLOWING',
|
||||
'FOREIGN',
|
||||
'FULL',
|
||||
'FULLTEXT',
|
||||
@ -120,7 +123,8 @@ final class Tokenizer
|
||||
'GLOBAL',
|
||||
'GRANT',
|
||||
'GRANTS',
|
||||
'GROUP_CONCAT',
|
||||
'GROUP',
|
||||
'GROUPS',
|
||||
'HEAP',
|
||||
'HIGH_PRIORITY',
|
||||
'HOSTS',
|
||||
@ -180,6 +184,7 @@ final class Tokenizer
|
||||
'MYISAM',
|
||||
'NAMES',
|
||||
'NATURAL',
|
||||
'NO OTHERS',
|
||||
'NOT',
|
||||
'NOW()',
|
||||
'NULL',
|
||||
@ -192,12 +197,14 @@ final class Tokenizer
|
||||
'ON UPDATE',
|
||||
'ON DELETE',
|
||||
'OUTFILE',
|
||||
'OVER',
|
||||
'PACK_KEYS',
|
||||
'PAGE',
|
||||
'PARTIAL',
|
||||
'PARTITION',
|
||||
'PARTITIONS',
|
||||
'PASSWORD',
|
||||
'PRECEDING',
|
||||
'PRIMARY',
|
||||
'PRIVILEGES',
|
||||
'PROCEDURE',
|
||||
@ -213,6 +220,7 @@ final class Tokenizer
|
||||
'READ',
|
||||
'READ_ONLY',
|
||||
'READ_WRITE',
|
||||
'RECURSIVE',
|
||||
'REFERENCES',
|
||||
'REGEXP',
|
||||
'RELOAD',
|
||||
@ -277,6 +285,7 @@ final class Tokenizer
|
||||
'TEMPORARY',
|
||||
'TERMINATED',
|
||||
'THEN',
|
||||
'TIES',
|
||||
'TO',
|
||||
'TRAILING',
|
||||
'TRANSACTIONAL',
|
||||
@ -284,6 +293,7 @@ final class Tokenizer
|
||||
'TRUNCATE',
|
||||
'TYPE',
|
||||
'TYPES',
|
||||
'UNBOUNDED',
|
||||
'UNCOMMITTED',
|
||||
'UNIQUE',
|
||||
'UNLOCK',
|
||||
@ -307,6 +317,7 @@ final class Tokenizer
|
||||
* @var string[]
|
||||
*/
|
||||
private $reservedToplevel = [
|
||||
'WITH',
|
||||
'SELECT',
|
||||
'FROM',
|
||||
'WHERE',
|
||||
@ -327,6 +338,11 @@ final class Tokenizer
|
||||
'UNION',
|
||||
'EXCEPT',
|
||||
'INTERSECT',
|
||||
'PARTITION BY',
|
||||
'ROWS',
|
||||
'RANGE',
|
||||
'GROUPS',
|
||||
'WINDOW',
|
||||
];
|
||||
|
||||
/** @var string[] */
|
||||
@ -341,6 +357,7 @@ final class Tokenizer
|
||||
'XOR',
|
||||
'OR',
|
||||
'AND',
|
||||
'EXCLUDE',
|
||||
];
|
||||
|
||||
/** @var string[] */
|
||||
@ -351,6 +368,7 @@ final class Tokenizer
|
||||
'ADDTIME',
|
||||
'AES_DECRYPT',
|
||||
'AES_ENCRYPT',
|
||||
'APPROX_COUNT_DISTINCT',
|
||||
'AREA',
|
||||
'ASBINARY',
|
||||
'ASCII',
|
||||
@ -380,6 +398,7 @@ final class Tokenizer
|
||||
'CHARACTER_LENGTH',
|
||||
'CHARSET',
|
||||
'CHAR_LENGTH',
|
||||
'CHECKSUM_AGG',
|
||||
'COALESCE',
|
||||
'COERCIBILITY',
|
||||
'COLLATION',
|
||||
@ -395,8 +414,10 @@ final class Tokenizer
|
||||
'COS',
|
||||
'COT',
|
||||
'COUNT',
|
||||
'COUNT_BIG',
|
||||
'CRC32',
|
||||
'CROSSES',
|
||||
'CUME_DIST',
|
||||
'CURDATE',
|
||||
'CURRENT_DATE',
|
||||
'CURRENT_TIME',
|
||||
@ -418,6 +439,7 @@ final class Tokenizer
|
||||
'DECODE',
|
||||
'DEFAULT',
|
||||
'DEGREES',
|
||||
'DENSE_RANK',
|
||||
'DES_DECRYPT',
|
||||
'DES_ENCRYPT',
|
||||
'DIFFERENCE',
|
||||
@ -437,6 +459,7 @@ final class Tokenizer
|
||||
'EXTRACTVALUE',
|
||||
'FIELD',
|
||||
'FIND_IN_SET',
|
||||
'FIRST_VALUE',
|
||||
'FLOOR',
|
||||
'FORMAT',
|
||||
'FOUND_ROWS',
|
||||
@ -457,6 +480,8 @@ final class Tokenizer
|
||||
'GET_LOCK',
|
||||
'GLENGTH',
|
||||
'GREATEST',
|
||||
'GROUPING',
|
||||
'GROUPING_ID',
|
||||
'GROUP_CONCAT',
|
||||
'GROUP_UNIQUE_USERS',
|
||||
'HEX',
|
||||
@ -478,9 +503,12 @@ final class Tokenizer
|
||||
'ISSIMPLE',
|
||||
'IS_FREE_LOCK',
|
||||
'IS_USED_LOCK',
|
||||
'LAG',
|
||||
'LAST_DAY',
|
||||
'LAST_INSERT_ID',
|
||||
'LAST_VALUE',
|
||||
'LCASE',
|
||||
'LEAD',
|
||||
'LEAST',
|
||||
'LEFT',
|
||||
'LENGTH',
|
||||
@ -489,6 +517,7 @@ final class Tokenizer
|
||||
'LINESTRING',
|
||||
'LINESTRINGFROMTEXT',
|
||||
'LINESTRINGFROMWKB',
|
||||
'LISTAGG',
|
||||
'LN',
|
||||
'LOAD_FILE',
|
||||
'LOCALTIME',
|
||||
@ -536,6 +565,8 @@ final class Tokenizer
|
||||
'MULTIPOLYGONFROMTEXT',
|
||||
'MULTIPOLYGONFROMWKB',
|
||||
'NAME_CONST',
|
||||
'NTH_VALUE',
|
||||
'NTILE',
|
||||
'NULLIF',
|
||||
'NUMGEOMETRIES',
|
||||
'NUMINTERIORRINGS',
|
||||
@ -546,6 +577,9 @@ final class Tokenizer
|
||||
'ORD',
|
||||
'OVERLAPS',
|
||||
'PASSWORD',
|
||||
'PERCENT_RANK',
|
||||
'PERCENTILE_CONT',
|
||||
'PERCENTILE_DISC',
|
||||
'PERIOD_ADD',
|
||||
'PERIOD_DIFF',
|
||||
'PI',
|
||||
@ -566,6 +600,7 @@ final class Tokenizer
|
||||
'QUOTE',
|
||||
'RADIANS',
|
||||
'RAND',
|
||||
'RANK',
|
||||
'RELATED',
|
||||
'RELEASE_LOCK',
|
||||
'REPEAT',
|
||||
@ -574,6 +609,7 @@ final class Tokenizer
|
||||
'RIGHT',
|
||||
'ROUND',
|
||||
'ROW_COUNT',
|
||||
'ROW_NUMBER',
|
||||
'RPAD',
|
||||
'RTRIM',
|
||||
'SCHEMA',
|
||||
@ -591,9 +627,12 @@ final class Tokenizer
|
||||
'SRID',
|
||||
'STARTPOINT',
|
||||
'STD',
|
||||
'STDEV',
|
||||
'STDEVP',
|
||||
'STDDEV',
|
||||
'STDDEV_POP',
|
||||
'STDDEV_SAMP',
|
||||
'STRING_AGG',
|
||||
'STRCMP',
|
||||
'STR_TO_DATE',
|
||||
'SUBDATE',
|
||||
@ -630,7 +669,9 @@ final class Tokenizer
|
||||
'UTC_TIME',
|
||||
'UTC_TIMESTAMP',
|
||||
'UUID',
|
||||
'VAR',
|
||||
'VARIANCE',
|
||||
'VARP',
|
||||
'VAR_POP',
|
||||
'VAR_SAMP',
|
||||
'VERSION',
|
||||
@ -669,6 +710,7 @@ final class Tokenizer
|
||||
private $boundaries = [
|
||||
',',
|
||||
';',
|
||||
'::', // PostgreSQL cast operator
|
||||
':',
|
||||
')',
|
||||
'(',
|
||||
@ -727,7 +769,7 @@ final class Tokenizer
|
||||
*
|
||||
* @param string $string The SQL string
|
||||
*/
|
||||
public function tokenize(string $string) : Cursor
|
||||
public function tokenize(string $string): Cursor
|
||||
{
|
||||
$tokens = [];
|
||||
|
||||
@ -774,7 +816,7 @@ final class Tokenizer
|
||||
*
|
||||
* @return Token An associative array containing the type and value of the token.
|
||||
*/
|
||||
private function createNextToken(string $string, Token $previous = null) : Token
|
||||
private function createNextToken(string $string, ?Token $previous = null): Token
|
||||
{
|
||||
$matches = [];
|
||||
// Whitespace
|
||||
@ -783,9 +825,11 @@ final class Tokenizer
|
||||
}
|
||||
|
||||
// Comment
|
||||
if ($string[0] === '#' ||
|
||||
(isset($string[1]) && ($string[0]==='-' && $string[1]==='-') ||
|
||||
(isset($string[1]) && $string[0]==='/' && $string[1]==='*'))) {
|
||||
if (
|
||||
$string[0] === '#' ||
|
||||
(isset($string[1]) && (($string[0] === '-' && $string[1] === '-') ||
|
||||
($string[0] === '/' && $string[1] === '*')))
|
||||
) {
|
||||
// Comment until end of line
|
||||
if ($string[0] === '-' || $string[0] === '#') {
|
||||
$last = strpos($string, "\n");
|
||||
@ -805,9 +849,9 @@ final class Tokenizer
|
||||
}
|
||||
|
||||
// Quoted String
|
||||
if ($string[0]==='"' || $string[0]==='\'' || $string[0]==='`' || $string[0]==='[') {
|
||||
if ($string[0] === '"' || $string[0] === '\'' || $string[0] === '`' || $string[0] === '[') {
|
||||
return new Token(
|
||||
($string[0]==='`' || $string[0]==='['
|
||||
($string[0] === '`' || $string[0] === '['
|
||||
? Token::TOKEN_TYPE_BACKTICK_QUOTE
|
||||
: Token::TOKEN_TYPE_QUOTE),
|
||||
$this->getQuotedString($string)
|
||||
@ -820,7 +864,7 @@ final class Tokenizer
|
||||
$type = Token::TOKEN_TYPE_VARIABLE;
|
||||
|
||||
// If the variable name is quoted
|
||||
if ($string[1]==='"' || $string[1]==='\'' || $string[1]==='`') {
|
||||
if ($string[1] === '"' || $string[1] === '\'' || $string[1] === '`') {
|
||||
$value = $string[0] . $this->getQuotedString(substr($string, 1));
|
||||
} else {
|
||||
// Non-quoted variable name
|
||||
@ -836,11 +880,13 @@ final class Tokenizer
|
||||
}
|
||||
|
||||
// Number (decimal, binary, or hex)
|
||||
if (preg_match(
|
||||
'/^([0-9]+(\.[0-9]+)?|0x[0-9a-fA-F]+|0b[01]+)($|\s|"\'`|' . $this->regexBoundaries . ')/',
|
||||
$string,
|
||||
$matches
|
||||
)) {
|
||||
if (
|
||||
preg_match(
|
||||
'/^([0-9]+(\.[0-9]+)?|0x[0-9a-fA-F]+|0b[01]+)($|\s|"\'`|' . $this->regexBoundaries . ')/',
|
||||
$string,
|
||||
$matches
|
||||
)
|
||||
) {
|
||||
return new Token(Token::TOKEN_TYPE_NUMBER, $matches[1]);
|
||||
}
|
||||
|
||||
@ -854,38 +900,44 @@ final class Tokenizer
|
||||
if (! $previous || $previous->value() !== '.') {
|
||||
$upper = strtoupper($string);
|
||||
// Top Level Reserved Word
|
||||
if (preg_match(
|
||||
'/^(' . $this->regexReservedToplevel . ')($|\s|' . $this->regexBoundaries . ')/',
|
||||
$upper,
|
||||
$matches
|
||||
)) {
|
||||
if (
|
||||
preg_match(
|
||||
'/^(' . $this->regexReservedToplevel . ')($|\s|' . $this->regexBoundaries . ')/',
|
||||
$upper,
|
||||
$matches
|
||||
)
|
||||
) {
|
||||
return new Token(
|
||||
Token::TOKEN_TYPE_RESERVED_TOPLEVEL,
|
||||
substr($string, 0, strlen($matches[1]))
|
||||
substr($upper, 0, strlen($matches[1]))
|
||||
);
|
||||
}
|
||||
|
||||
// Newline Reserved Word
|
||||
if (preg_match(
|
||||
'/^(' . $this->regexReservedNewline . ')($|\s|' . $this->regexBoundaries . ')/',
|
||||
$upper,
|
||||
$matches
|
||||
)) {
|
||||
if (
|
||||
preg_match(
|
||||
'/^(' . $this->regexReservedNewline . ')($|\s|' . $this->regexBoundaries . ')/',
|
||||
$upper,
|
||||
$matches
|
||||
)
|
||||
) {
|
||||
return new Token(
|
||||
Token::TOKEN_TYPE_RESERVED_NEWLINE,
|
||||
substr($string, 0, strlen($matches[1]))
|
||||
substr($upper, 0, strlen($matches[1]))
|
||||
);
|
||||
}
|
||||
|
||||
// Other Reserved Word
|
||||
if (preg_match(
|
||||
'/^(' . $this->regexReserved . ')($|\s|' . $this->regexBoundaries . ')/',
|
||||
$upper,
|
||||
$matches
|
||||
)) {
|
||||
if (
|
||||
preg_match(
|
||||
'/^(' . $this->regexReserved . ')($|\s|' . $this->regexBoundaries . ')/',
|
||||
$upper,
|
||||
$matches
|
||||
)
|
||||
) {
|
||||
return new Token(
|
||||
Token::TOKEN_TYPE_RESERVED,
|
||||
substr($string, 0, strlen($matches[1]))
|
||||
substr($upper, 0, strlen($matches[1]))
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -897,7 +949,7 @@ final class Tokenizer
|
||||
if (preg_match('/^(' . $this->regexFunction . '[(]|\s|[)])/', $upper, $matches)) {
|
||||
return new Token(
|
||||
Token::TOKEN_TYPE_RESERVED,
|
||||
substr($string, 0, strlen($matches[1])-1)
|
||||
substr($upper, 0, strlen($matches[1]) - 1)
|
||||
);
|
||||
}
|
||||
|
||||
@ -914,14 +966,14 @@ final class Tokenizer
|
||||
*
|
||||
* @return string[] The quoted strings
|
||||
*/
|
||||
private function quoteRegex(array $strings) : array
|
||||
private function quoteRegex(array $strings): array
|
||||
{
|
||||
return array_map(static function (string $string) : string {
|
||||
return array_map(static function (string $string): string {
|
||||
return preg_quote($string, '/');
|
||||
}, $strings);
|
||||
}
|
||||
|
||||
private function getQuotedString(string $string) : string
|
||||
private function getQuotedString(string $string): string
|
||||
{
|
||||
$ret = '';
|
||||
|
||||
@ -930,14 +982,16 @@ final class Tokenizer
|
||||
// 2. square bracket quoted string (SQL Server) using ]] to escape
|
||||
// 3. double quoted string using "" or \" to escape
|
||||
// 4. single quoted string using '' or \' to escape
|
||||
if (preg_match(
|
||||
'/^(((`[^`]*($|`))+)|
|
||||
if (
|
||||
preg_match(
|
||||
'/^(((`[^`]*($|`))+)|
|
||||
((\[[^\]]*($|\]))(\][^\]]*($|\]))*)|
|
||||
(("[^"\\\\]*(?:\\\\.[^"\\\\]*)*("|$))+)|
|
||||
((\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*(\'|$))+))/sx',
|
||||
$string,
|
||||
$matches
|
||||
)) {
|
||||
$string,
|
||||
$matches
|
||||
)
|
||||
) {
|
||||
$ret = $matches[1];
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user